.Net Core中自定義認(rèn)證實(shí)現(xiàn)
一、起因
最近項(xiàng)目中需要對項(xiàng)目同時(shí)支持JWT認(rèn)證,以及自定義的認(rèn)證校驗(yàn)方式認(rèn)證。通過對官方文檔了解,得到認(rèn)證實(shí)現(xiàn)主要通過繼承 IAuthenticationHandler 或 AuthenticationHandler<TOptions>來實(shí)現(xiàn)自定義認(rèn)證的處理?!?/p>
那么接下來實(shí)現(xiàn)一個(gè)自定義的認(rèn)證訪問。
二、自定義認(rèn)證實(shí)現(xiàn)
1、根據(jù)前面內(nèi)容得知,處理認(rèn)證通過IAuthenticationHandler 實(shí)例處理;那么首先添加一個(gè)自定義IAuthenticationHandler 類型:
/// <summary>
/// 方式一:自定義認(rèn)證處理器
/// </summary>
public class CustomerAuthenticationHandler : IAuthenticationHandler
{
? ? private IUserService _userService;
? ? public CustomerAuthenticationHandler(IUserService userService)
? ? {
? ? ? ? _userService = userService;
? ? }
? ? /// <summary>
? ? /// 自定義認(rèn)證Scheme名稱
? ? /// </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)的基類
/// </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)記,測試驗(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)目中可能存在,對一個(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)證類型:繼承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)證主要通過實(shí)現(xiàn)IAuthenticationHandler 接口實(shí)現(xiàn),如果要實(shí)現(xiàn)多認(rèn)證方式通過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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Asp.Net Core添加請求頭自定義認(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ǔ)過程向數(shù)據(jù)庫存值的具體實(shí)現(xiàn)
本文為大家介紹下使用存儲(chǔ)過程向數(shù)據(jù)庫存值的具體實(shí)現(xiàn)過程,感興趣的朋友不要錯(cuò)過2014-01-01
.Net core下直接執(zhí)行SQL語句并生成DataTable的實(shí)現(xiàn)方法
.net core可以執(zhí)行SQL語句,但是只能生成強(qiáng)類型的返回結(jié)果。這篇文章主要介紹了.Net core下直接執(zhí)行SQL語句并生成DataTable的相關(guān)資料,需要的朋友可以參考下2016-11-11
asp.net Checbox在GridView中的應(yīng)用實(shí)例分析
這篇文章主要介紹了asp.net Checbox在GridView中的應(yīng)用,結(jié)合實(shí)例形式分析了GridView中添加與使用Checbox的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Entity?Framework?Core種子數(shù)據(jù)Data-Seeding
這篇文章介紹了Entity?Framework?Core種子數(shù)據(jù)Data-Seeding的用法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03
1個(gè)文件如何輕松搞定Asp.net core 3.1動(dòng)態(tài)頁面轉(zhuǎn)靜態(tài)頁面
這篇文章主要給大家介紹了關(guān)于如何通過1個(gè)文件輕松搞定Asp.net core 3.1動(dòng)態(tài)頁面轉(zhuǎn)靜態(tài)頁面的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Asp.net core 3.1具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05

