.Net Core中自定義認證實現(xiàn)
一、起因
最近項目中需要對項目同時支持JWT認證,以及自定義的認證校驗方式認證。通過對官方文檔了解,得到認證實現(xiàn)主要通過繼承 IAuthenticationHandler 或 AuthenticationHandler<TOptions>來實現(xiàn)自定義認證的處理。
那么接下來實現(xiàn)一個自定義的認證訪問。
二、自定義認證實現(xiàn)
1、根據(jù)前面內(nèi)容得知,處理認證通過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>
? ? /// 權(quán)限不足時處理
? ? /// </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>
? ? /// 生成認證票據(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>
/// 方式二:繼承已實現(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中啟用自定義認證:
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、在控制器上添加認證標(biāo)記,測試驗證
//指定認證時,采用CustomerAuthenticationHandler.CustomerSchemeName
[Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
[Route("api/[controller]")]
[ApiController]
public class AuditLogController : ControllerBase
{
?//code
}調(diào)用

三、多認證支持
在實際項目中可能存在,對一個控制器支持多種認證方式如:常用的Jwt認證、自定義認證等,那么如何實現(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認證
? ? 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、在需要支持多種認證方式的控制器上添加標(biāo)記:
//指定認證時,采用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認證處理,并根據(jù)Scheme那么調(diào)用自定義的認證處理器:
/// <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>
? ? /// 生成認證票據(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中的自定義認證主要通過實現(xiàn)IAuthenticationHandler 接口實現(xiàn),如果要實現(xiàn)多認證方式通過AddScheme 應(yīng)用自定義實現(xiàn)的認證處理器。
源碼:github
到此這篇關(guān)于.Net Core中自定義認證實現(xiàn)的文章就介紹到這了,更多相關(guān).Net Core 自定義認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
.Net Core WebApi部署到Windows服務(wù)器上的步驟
這篇文章主要介紹了.Net Core WebApi部署到Windows服務(wù)器上的步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03
asp.net GridView中使用RadioButton單選按鈕的方法
這篇文章主要介紹了asp.net GridView中使用RadioButton單選按鈕的方法,結(jié)合實例形式總結(jié)分析了三種GridView中使用RadioButton單選按鈕的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下2016-07-07
ASP.NET從客戶端中檢測到有潛在危險的request.form值的3種解決方法
這篇文章主要介紹了ASP.NET從客戶端中檢測到有潛在危險的request.form值的3種解決方法,這是ASP.NET開發(fā)中一個比較常見的經(jīng)典的問題,需要的朋友可以參考下2015-01-01
Asp.net回調(diào)技術(shù)Callback學(xué)習(xí)筆記
這篇文章主要記錄了Asp.net回調(diào)技術(shù)Callback的一些知識,感興趣的朋友可以參考下2014-08-08
.Net Web Api中利用FluentValidate進行參數(shù)驗證的方法
最近在做Web API,用到了流式驗證,就簡單的說說這個流式驗證,下面這篇文章主要給大家介紹了關(guān)于.Net Web Api中利用FluentValidate進行參數(shù)驗證的相關(guān)資料,,需要的朋友可以參考借鑒,下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-07-07

