.NetCore中自定义认证实现

博客 动态
0 363
张三
张三 2022-01-24 11:58:35
悬赏:0 积分 收藏

.Net Core中自定义认证实现

一、起因

 最近项目中需要对项目同时支持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

 参考:认证

  

posted @ 2022-01-23 16:45 chaney1992 阅读(540) 评论(6) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    1111 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员