.Net Core中自定义认证实现
Posted One To One
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.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
参考:认证
以上是关于.Net Core中自定义认证实现的主要内容,如果未能解决你的问题,请参考以下文章
.Net Core中AuthorizationHandlerContext如何获取当前请求的相关信息