首页 > 其他分享 >.Net Core中自定义认证实现

.Net Core中自定义认证实现

时间:2023-07-30 11:22:38浏览次数:35  
标签:Core 自定义 CustomerAuthenticationHandler 认证 CustomerSchemeName new Net public

一、起因  (原文)

 最近项目中需要对项目同时支持JWT认证,以及自定义的认证校验方式认证。通过对官方文档了解,得到认证实现主要通过继承 IAuthenticationHandler 或 AuthenticationHandler<TOptions>来实现自定义认证的处理。 

 那么接下来实现一个自定义的认证访问。

二、自定义认证实现 

 1、根据前面内容得知,处理认证通过IAuthenticationHandler 实例处理;那么首先添加一个自定义IAuthenticationHandler 类型:

复制代码 复制代码
/// <summary>
/// 方式一:自定义认证处理器
/// </summary>
public class CustomerAuthenticationHandler : IAuthenticationHandler
{
    private IUserService _userService;
    public CustomerAuthenticationHandler(IUserService userService)
    {
        _userService = userService;
    }

    /// <summary>
    /// 自定义认证Scheme名称
    /// </summary>
    public const string CustomerSchemeName = "cusAuth";

    private AuthenticationScheme _scheme;
    private HttpContext _context;

    /// <summary>
    /// 认证逻辑:认证校验主要逻辑
    /// </summary>
    /// <returns></returns>
    public Task<AuthenticateResult> AuthenticateAsync()
    {
        AuthenticateResult result;
        _context.Request.Headers.TryGetValue("Authorization", out StringValues values);
        string valStr = values.ToString();
        if (!string.IsNullOrWhiteSpace(valStr))
        {
            //认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
            string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerSchemeName.Length + 1))).Split(':');
            var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
            var validVale = _userService.IsValid(loginInfo);
            if (!validVale)
                result = AuthenticateResult.Fail("未登陆");
            else
            {
                var ticket = GetAuthTicket(loginInfo.Username, "admin");
                result = AuthenticateResult.Success(ticket);
            }
        }
        else
        {
            result = AuthenticateResult.Fail("未登陆");
        }
        return Task.FromResult(result);
    }

    /// <summary>
    /// 未登录时的处理
    /// </summary>
    /// <param name="properties"></param>
    /// <returns></returns>
    public Task ChallengeAsync(AuthenticationProperties properties)
    {
        _context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
        return Task.CompletedTask;
    }

    /// <summary>
    /// 权限不足时处理
    /// </summary>
    /// <param name="properties"></param>
    /// <returns></returns>
    public Task ForbidAsync(AuthenticationProperties properties)
    {
        _context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
        return Task.CompletedTask;
    }

    /// <summary>
    /// 初始化认证
    /// </summary>
    /// <param name="scheme"></param>
    /// <param name="context"></param>
    /// <returns></returns>
    public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
    {
        _scheme = scheme;
        _context = context;
        return Task.CompletedTask;
    }

    #region 认证校验逻辑

    /// <summary>
    /// 生成认证票据
    /// </summary>
    /// <param name="name"></param>
    /// <param name="role"></param>
    /// <returns></returns>
    private AuthenticationTicket GetAuthTicket(string name, string role)
    {
        var claimsIdentity = new ClaimsIdentity(new Claim[]
        {
    new Claim(ClaimTypes.Name, name),
    new Claim(ClaimTypes.Role, role),
        }, CustomerSchemeName);
        var principal = new ClaimsPrincipal(claimsIdentity);
        return new AuthenticationTicket(principal, _scheme.Name);
    }

    #endregion
}

/// <summary>
/// 方式二:继承已实现的基类
/// </summary>
public class SubAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
    public SubAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
        : base(options, logger, encoder, clock)
    {
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        throw new NotImplementedException();
    }
}
复制代码 复制代码

 2、在Startup.cs中启用自定义认证:

复制代码 复制代码
public void ConfigureServices(IServiceCollection services)
{
    //other code
    services.AddAuthentication(o =>
    {
        x.DefaultAuthenticateScheme = CustomerAuthenticationHandler.CustomerSchemeName;
        x.DefaultChallengeScheme = CustomerAuthenticationHandler.CustomerSchemeName;
        o.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName);
    });
    //other code
}

public void Configure(IApplicationBuilder app)
{
    //other code
    app.UseRouting();

    //在UseRouting后;UseEndpoints前添加以下代码
    app.UseAuthentication();
    app.UseAuthorization();

    //other code
    app.UseEndpoints()
}
复制代码 复制代码

 3、在控制器上添加认证标记,测试验证

复制代码 复制代码
//指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
[Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
[Route("api/[controller]")]
[ApiController]
public class AuditLogController : ControllerBase
{
 //code
}
复制代码 复制代码

  调用

  

三、多认证支持

 在实际项目中可能存在,对一个控制器支持多种认证方式如:常用的Jwt认证、自定义认证等,那么如何实现呢?

 1、在Startup的ConfigureServices 方法中添加以下逻辑:

复制代码 复制代码
public void ConfigureServices(IServiceCollection services)
{
    //other code
    services.Configure<JwtSetting>(Configuration.GetSection("JWTSetting"));
    var token = Configuration.GetSection("JWTSetting").Get<JwtSetting>();
    //JWT认证
    services.AddAuthentication(x =>
    {
        x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
     //添加自定义认证处理器 x.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName); }).AddJwtBearer(x => { x.RequireHttpsMetadata = false; x.SaveToken = true; x.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.SecretKey)), ValidIssuer = token.Issuer, ValidAudience = token.Audience, ValidateIssuer = false, ValidateAudience = false }; }); //other code }
复制代码 复制代码

 2、在需要支持多种认证方式的控制器上添加标记:

复制代码 复制代码
//指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
[Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
[Route("api/[controller]")]
[ApiController]
public class AuditLogController : ControllerBase
{
 //code
}



//指定认证采用JWT 
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] 
public class WeatherForecastController : ControllerBase 
{
  //code 
}
复制代码 复制代码

   这样就支持了两种认证方式

 3、一个控制器支持多种认证类型:继承Jwt认证处理,并根据Scheme那么调用自定义的认证处理器:

复制代码 复制代码
/// <summary>
/// 方式二:同时支持多种认证方式
/// </summary>
public class MultAuthenticationHandler : JwtBearerHandler
{
    public const string MultAuthName = "MultAuth";
    IUserService _userService;
    public MultAuthenticationHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
        : base(options, logger, encoder, clock)
    {
        _userService = userService;
    }

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
        string valStr = values.ToString();
        if (valStr.StartsWith(CustomerAuthenticationHandler.CustomerSchemeName))
        {
            var result = Valid();
            if (result != null)
                return Task.FromResult(AuthenticateResult.Success(result));
            else
                return Task.FromResult(AuthenticateResult.Fail("未认证"));
        }
        else
            return base.AuthenticateAsync();
    }

    private AuthenticationTicket Valid()
    {
        Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
        string valStr = values.ToString();
        if (!string.IsNullOrWhiteSpace(valStr))
        {
            //认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
            string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerAuthenticationHandler.CustomerSchemeName.Length + 1))).Split(':');
            var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
            if (_userService.IsValid(loginInfo))
                return GetAuthTicket(loginInfo.Username, "admin");
        }
        return null;
    }

    /// <summary>
    /// 生成认证票据
    /// </summary>
    /// <param name="name"></param>
    /// <param name="role"></param>
    /// <returns></returns>
    private AuthenticationTicket GetAuthTicket(string name, string role)
    {
        var claimsIdentity = new ClaimsIdentity(new Claim[]
        {
            new Claim(ClaimTypes.Name, name),
            new Claim(ClaimTypes.Role, role),
        }, CustomerAuthenticationHandler.CustomerSchemeName);
        var principal = new ClaimsPrincipal(claimsIdentity);
        return new AuthenticationTicket(principal, CustomerAuthenticationHandler.CustomerSchemeName);
    }
}
复制代码 复制代码

四、总结

  .Net Core中的自定义认证主要通过实现IAuthenticationHandler 接口实现,如果要实现多认证方式通过AddScheme 应用自定义实现的认证处理器。

 源码:github

 参考:认证

 

转 https://www.cnblogs.com/cwsheng/p/15835731.html

标签:Core,自定义,CustomerAuthenticationHandler,认证,CustomerSchemeName,new,Net,public
From: https://www.cnblogs.com/Alex80/p/17591158.html

相关文章

  • 【go语言】2.4.2 自定义包的创建和使用
    在Go中,任何一个目录都可以被视为一个包。创建自定义包的基本步骤是:新建一个目录,用于存放包的源文件。在新建的目录中编写Go代码,代码的第一行应该是 package包名。使用 import 语句在其他地方导入和使用这个包。接下来,我们详细看一下如何创建和使用自定义包。创建自......
  • Neural Network 初学
    参数:机器学习的内容超参数:人手动设置的数值,比如学习率、训练轮数MLP在inputlayer和outputlayer之间有一堆hiddenlayer,每两层之间可以理解成一张完全二分图,二分图的邻接矩阵上有一些权重,随机初始化。将图片的每个像素点抽出来变成向量之后在二分图上矩阵乘法得到第一层......
  • .NET Core 6.0 配置自定义JWT鉴权
    JWT授权配置1、安装Microsoft.IdentityModel.Tokens包;2、创建一个认证用户信息实体类UserInfo3、创建一个JWT配置类JWTTokenOptions   publicclassJwtTokenOptions   {       ///<summary>       ///JWT认证Key       ///</sum......
  • ArchLinux安装KDE Plasma和NetworkManager后网络无法正常连接的问题
    前几天刚刷了系统,发现开机自动启动NetworkManager后,无法正常激活网络(也就是网卡开机默认DOWN),但手动dhcpcd后就可以正常使用网络,所以我最近一直在开机自启NetworkManager后手动sudodhcpcd,直到今天我发现ipv6有点小问题之后实在忍不了了,解决了一下这个问题具体怎么解决的呢,简单的......
  • MODBUS-TCP转Ethernet IP 网关连接空压机 配置案例
    本案例是工业现场应用捷米特JM-EIP-TCP的Ethernet/IP转Modbus-TCP网关连接欧姆龙PLC与空压机的配置案例。使用设备:欧姆龙PLC,捷米特JM-EIP-TCP网关,ETHERNET/IP 的电气连接  ETHERNET/IP 采用标准的 T568B 接法,支持直连和交叉接线方式,如上图所示。ETHERNET/IP 只需要连......
  • springboot启动中ccs样式和图片找不到, 报net::ERR_ABORTED 404
    1、 net::ERR_ABORTED404  项目结构 3、css错误的:<linkhref="/static/iconfont/style.css"type="text/css"rel="stylesheet">正确的:<linkhref="iconfont/style.css"type="text/css"rel="stylesh......
  • ETHERNET/IP转RS485/RS232网关ethernet和tcp/ip的区别
    网络数据传输遇到的协议不同、数据互通麻烦等问题,一直困扰着大家。然而,现在有一种神器——捷米JM-EIP-RS485/232,它将ETHERNET/IP网络和RS485/RS232总线连接在一起,让数据传输更加便捷高效。那么,它是如何实现这一功能的呢?JM-EIP-RS485/232是一款自主研发的通讯网关,可以在ETHERNET/......
  • windows10 安装.NET 5开发环境
    0、环境说明操作系统:windows10系统64位  1、开发工具版本windows10系统VisualStudio2019开发.NET5项目环境要求:VisualStudio2019 :升级到版本16.8以上(可直接在VS工具中直接升级版本) 2、下载.NET5官网网址:https://dotnet.microsoft.com/zh-cn/download/dotnet......
  • VMware-NAT网络模式下-设置静态IP后无法连接Internet的问题
    VMware-NAT网络模式下-设置静态IP后无法连接Internet的问题 设置Centos的静态IP和DNS     参考资料1.VMware-NAT网络模式下-设置静态IP后无法连接Internet的问题......
  • 在 ASP.NET Core 中使用 IHttpClientFactory 发出 HTTP 请求(官方文档)
    在ASP.NETCore中使用IHttpClientFactory发出HTTP请求项目2023/04/11本文内容消耗模式发出POST、PUT和DELETE请求出站请求中间件使用基于Polly的处理程序作者:KirkLarkin、SteveGordon、GlennCondron和RyanNowak。可以注册IHttpClientFactory并将其......