.Net Core中自定義認(rèn)證實(shí)現(xiàn)
一、起因
最近項(xiàng)目中需要對(duì)項(xiàng)目同時(shí)支持JWT認(rèn)證,以及自定義的認(rèn)證校驗(yàn)方式認(rèn)證。通過(guò)對(duì)官方文檔了解,得到認(rèn)證實(shí)現(xiàn)主要通過(guò)繼承 IAuthenticationHandler 或 AuthenticationHandler<TOptions>來(lái)實(shí)現(xiàn)自定義認(rèn)證的處理?!?/p>
那么接下來(lái)實(shí)現(xiàn)一個(gè)自定義的認(rèn)證訪問(wèn)。
二、自定義認(rèn)證實(shí)現(xiàn)
1、根據(jù)前面內(nèi)容得知,處理認(rèn)證通過(guò)IAuthenticationHandler 實(shí)例處理;那么首先添加一個(gè)自定義IAuthenticationHandler 類(lèi)型:
/// <summary> /// 方式一:自定義認(rèn)證處理器 /// </summary> public class CustomerAuthenticationHandler : IAuthenticationHandler { ? ? private IUserService _userService; ? ? public CustomerAuthenticationHandler(IUserService userService) ? ? { ? ? ? ? _userService = userService; ? ? } ? ? /// <summary> ? ? /// 自定義認(rèn)證Scheme名稱(chēng) ? ? /// </summary> ? ? public const string CustomerSchemeName = "cusAuth"; ? ? private AuthenticationScheme _scheme; ? ? private HttpContext _context; ? ? /// <summary> ? ? /// 認(rèn)證邏輯:認(rèn)證校驗(yàn)主要邏輯 ? ? /// </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)) ? ? ? ? { ? ? ? ? ? ? //認(rèn)證模擬basic認(rèn)證: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> ? ? /// 未登錄時(shí)的處理 ? ? /// </summary> ? ? /// <param name="properties"></param> ? ? /// <returns></returns> ? ? public Task ChallengeAsync(AuthenticationProperties properties) ? ? { ? ? ? ? _context.Response.StatusCode = (int)HttpStatusCode.Unauthorized; ? ? ? ? return Task.CompletedTask; ? ? } ? ? /// <summary> ? ? /// 權(quán)限不足時(shí)處理 ? ? /// </summary> ? ? /// <param name="properties"></param> ? ? /// <returns></returns> ? ? public Task ForbidAsync(AuthenticationProperties properties) ? ? { ? ? ? ? _context.Response.StatusCode = (int)HttpStatusCode.Forbidden; ? ? ? ? return Task.CompletedTask; ? ? } ? ? /// <summary> ? ? /// 初始化認(rèn)證 ? ? /// </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 認(rèn)證校驗(yàn)邏輯 ? ? /// <summary> ? ? /// 生成認(rèn)證票據(jù) ? ? /// </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> /// 方式二:繼承已實(shí)現(xiàn)的基類(lèi) /// </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中啟用自定義認(rèn)證:
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、在控制器上添加認(rèn)證標(biāo)記,測(cè)試驗(yàn)證
//指定認(rèn)證時(shí),采用CustomerAuthenticationHandler.CustomerSchemeName [Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)] [Route("api/[controller]")] [ApiController] public class AuditLogController : ControllerBase { ?//code }
調(diào)用
三、多認(rèn)證支持
在實(shí)際項(xiàng)目中可能存在,對(duì)一個(gè)控制器支持多種認(rèn)證方式如:常用的Jwt認(rèn)證、自定義認(rèn)證等,那么如何實(shí)現(xiàn)呢?
1、在Startup的ConfigureServices 方法中添加以下邏輯:
public void ConfigureServices(IServiceCollection services) { ? ? //other code ? ? services.Configure<JwtSetting>(Configuration.GetSection("JWTSetting")); ? ? var token = Configuration.GetSection("JWTSetting").Get<JwtSetting>(); ? ? //JWT認(rèn)證 ? ? services.AddAuthentication(x => ? ? { ? ? ? ? x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; ? ? ? ? x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; //添加自定義認(rèn)證處理器 ? ? ? ? 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、在需要支持多種認(rèn)證方式的控制器上添加標(biāo)記:
//指定認(rèn)證時(shí),采用CustomerAuthenticationHandler.CustomerSchemeName [Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)] [Route("api/[controller]")] [ApiController] public class AuditLogController : ControllerBase { ?//code } //指定認(rèn)證采用JWT? [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]? public class WeatherForecastController : ControllerBase? { ? //code? }
這樣就支持了兩種認(rèn)證方式
3、一個(gè)控制器支持多種認(rèn)證類(lèi)型:繼承Jwt認(rèn)證處理,并根據(jù)Scheme那么調(diào)用自定義的認(rèn)證處理器:
/// <summary> /// 方式二:同時(shí)支持多種認(rèn)證方式 /// </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("未認(rèn)證")); ? ? ? ? } ? ? ? ? else ? ? ? ? ? ? return base.AuthenticateAsync(); ? ? } ? ? private AuthenticationTicket Valid() ? ? { ? ? ? ? Context.Request.Headers.TryGetValue("Authorization", out StringValues values); ? ? ? ? string valStr = values.ToString(); ? ? ? ? if (!string.IsNullOrWhiteSpace(valStr)) ? ? ? ? { ? ? ? ? ? ? //認(rèn)證模擬basic認(rèn)證: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> ? ? /// 生成認(rèn)證票據(jù) ? ? /// </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); ? ? } }
四、總結(jié)
.Net Core中的自定義認(rèn)證主要通過(guò)實(shí)現(xiàn)IAuthenticationHandler 接口實(shí)現(xiàn),如果要實(shí)現(xiàn)多認(rèn)證方式通過(guò)AddScheme 應(yīng)用自定義實(shí)現(xiàn)的認(rèn)證處理器。
源碼:github
到此這篇關(guān)于.Net Core中自定義認(rèn)證實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān).Net Core 自定義認(rèn)證內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Asp.Net Core添加請(qǐng)求頭自定義認(rèn)證的示例
- .Net Core實(shí)現(xiàn)JWT授權(quán)認(rèn)證
- .net?core?api接口JWT方式認(rèn)證Token
- ASP.NET Core3.1 Ocelot認(rèn)證的實(shí)現(xiàn)
- ASP.NET Core使用JWT認(rèn)證授權(quán)的方法
- ASP.NET Core 實(shí)現(xiàn)基本認(rèn)證的示例代碼
- ASP.NET Core學(xué)習(xí)之使用JWT認(rèn)證授權(quán)詳解
- 淺談ASP.NET Core 中jwt授權(quán)認(rèn)證的流程原理
- ASP.Net Core3.0中使用JWT認(rèn)證的實(shí)現(xiàn)
相關(guān)文章
用存儲(chǔ)過(guò)程向數(shù)據(jù)庫(kù)存值的具體實(shí)現(xiàn)
本文為大家介紹下使用存儲(chǔ)過(guò)程向數(shù)據(jù)庫(kù)存值的具體實(shí)現(xiàn)過(guò)程,感興趣的朋友不要錯(cuò)過(guò)2014-01-01.Net core下直接執(zhí)行SQL語(yǔ)句并生成DataTable的實(shí)現(xiàn)方法
.net core可以執(zhí)行SQL語(yǔ)句,但是只能生成強(qiáng)類(lèi)型的返回結(jié)果。這篇文章主要介紹了.Net core下直接執(zhí)行SQL語(yǔ)句并生成DataTable的相關(guān)資料,需要的朋友可以參考下2016-11-11asp.net Checbox在GridView中的應(yīng)用實(shí)例分析
這篇文章主要介紹了asp.net Checbox在GridView中的應(yīng)用,結(jié)合實(shí)例形式分析了GridView中添加與使用Checbox的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07Entity?Framework?Core種子數(shù)據(jù)Data-Seeding
這篇文章介紹了Entity?Framework?Core種子數(shù)據(jù)Data-Seeding的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-031個(gè)文件如何輕松搞定Asp.net core 3.1動(dòng)態(tài)頁(yè)面轉(zhuǎn)靜態(tài)頁(yè)面
這篇文章主要給大家介紹了關(guān)于如何通過(guò)1個(gè)文件輕松搞定Asp.net core 3.1動(dòng)態(tài)頁(yè)面轉(zhuǎn)靜態(tài)頁(yè)面的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Asp.net core 3.1具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05