一、起因

 最近项目中需要对项目同时支持JWT认证,以及自定义的认证校验方式认证。通过对官方文档了解,得到认证实现主要通过继承IAuthenticationHandler 或 AuthenticationHandler<TOptions>来实现自定义认证的处理。 

 那么接下来实现一个自定义的认证访问。

二、自定义认证实现

 1、根据前面内容得知,处理认证通过IAuthenticationHandler 实例处理;那么首先添加一个自定义IAuthenticationHandler 类型:

  1. /// <summary>
  2. /// 方式一:自定义认证处理器
  3. /// </summary>
  4. public class CustomerAuthenticationHandler : IAuthenticationHandler
  5. {
  6. private IUserService _userService;
  7. public CustomerAuthenticationHandler(IUserService userService)
  8. {
  9. _userService = userService;
  10. }
  11.  
  12. /// <summary>
  13. /// 自定义认证Scheme名称
  14. /// </summary>
  15. public const string CustomerSchemeName = "cusAuth";
  16.  
  17. private AuthenticationScheme _scheme;
  18. private HttpContext _context;
  19.  
  20. /// <summary>
  21. /// 认证逻辑:认证校验主要逻辑
  22. /// </summary>
  23. /// <returns></returns>
  24. public Task<AuthenticateResult> AuthenticateAsync()
  25. {
  26. AuthenticateResult result;
  27. _context.Request.Headers.TryGetValue("Authorization", out StringValues values);
  28. string valStr = values.ToString();
  29. if (!string.IsNullOrWhiteSpace(valStr))
  30. {
  31. //认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
  32. string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerSchemeName.Length + 1))).Split(':');
  33. var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
  34. var validVale = _userService.IsValid(loginInfo);
  35. if (!validVale)
  36. result = AuthenticateResult.Fail("未登陆");
  37. else
  38. {
  39. var ticket = GetAuthTicket(loginInfo.Username, "admin");
  40. result = AuthenticateResult.Success(ticket);
  41. }
  42. }
  43. else
  44. {
  45. result = AuthenticateResult.Fail("未登陆");
  46. }
  47. return Task.FromResult(result);
  48. }
  49.  
  50. /// <summary>
  51. /// 未登录时的处理
  52. /// </summary>
  53. /// <param name="properties"></param>
  54. /// <returns></returns>
  55. public Task ChallengeAsync(AuthenticationProperties properties)
  56. {
  57. _context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
  58. return Task.CompletedTask;
  59. }
  60.  
  61. /// <summary>
  62. /// 权限不足时处理
  63. /// </summary>
  64. /// <param name="properties"></param>
  65. /// <returns></returns>
  66. public Task ForbidAsync(AuthenticationProperties properties)
  67. {
  68. _context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
  69. return Task.CompletedTask;
  70. }
  71.  
  72. /// <summary>
  73. /// 初始化认证
  74. /// </summary>
  75. /// <param name="scheme"></param>
  76. /// <param name="context"></param>
  77. /// <returns></returns>
  78. public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
  79. {
  80. _scheme = scheme;
  81. _context = context;
  82. return Task.CompletedTask;
  83. }
  84.  
  85. #region 认证校验逻辑
  86.  
  87. /// <summary>
  88. /// 生成认证票据
  89. /// </summary>
  90. /// <param name="name"></param>
  91. /// <param name="role"></param>
  92. /// <returns></returns>
  93. private AuthenticationTicket GetAuthTicket(string name, string role)
  94. {
  95. var claimsIdentity = new ClaimsIdentity(new Claim[]
  96. {
  97. new Claim(ClaimTypes.Name, name),
  98. new Claim(ClaimTypes.Role, role),
  99. }, CustomerSchemeName);
  100. var principal = new ClaimsPrincipal(claimsIdentity);
  101. return new AuthenticationTicket(principal, _scheme.Name);
  102. }
  103.  
  104. #endregion
  105. }
  106.  
  107. /// <summary>
  108. /// 方式二:继承已实现的基类
  109. /// </summary>
  110. public class SubAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
  111. {
  112. public SubAuthenticationHandler(IOptionsMonitor<AuthenticationSchemeOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
  113. : base(options, logger, encoder, clock)
  114. {
  115. }
  116.  
  117. protected override Task<AuthenticateResult> HandleAuthenticateAsync()
  118. {
  119. throw new NotImplementedException();
  120. }
  121. }

 2、在Startup.cs中启用自定义认证:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //other code
  4. services.AddAuthentication(o =>
  5. {
  6. x.DefaultAuthenticateScheme = CustomerAuthenticationHandler.CustomerSchemeName;
  7. x.DefaultChallengeScheme = CustomerAuthenticationHandler.CustomerSchemeName;
  8. o.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName);
  9. });
  10. //other code
  11. }
  12.  
  13. public void Configure(IApplicationBuilder app)
  14. {
  15. //other code
  16. app.UseRouting();
  17.  
  18. //在UseRouting后;UseEndpoints前添加以下代码
  19. app.UseAuthentication();
  20. app.UseAuthorization();
  21.  
  22. //other code
  23. app.UseEndpoints()
  24. }

 3、在控制器上添加认证标记,测试验证

  1. //指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
  2. [Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
  3. [Route("api/[controller]")]
  4. [ApiController]
  5. public class AuditLogController : ControllerBase
  6. {
  7. //code
  8. }

  调用

  

三、多认证支持

 在实际项目中可能存在,对一个控制器支持多种认证方式如:常用的Jwt认证、自定义认证等,那么如何实现呢?

 1、在Startup的ConfigureServices 方法中添加以下逻辑:

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. //other code
  4. services.Configure<JwtSetting>(Configuration.GetSection("JWTSetting"));
  5. var token = Configuration.GetSection("JWTSetting").Get<JwtSetting>();
  6. //JWT认证
  7. services.AddAuthentication(x =>
  8. {
  9. x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  10. x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
         //添加自定义认证处理器
  11. x.AddScheme<CustomerAuthenticationHandler>(CustomerAuthenticationHandler.CustomerSchemeName, CustomerAuthenticationHandler.CustomerSchemeName);
  12. }).AddJwtBearer(x =>
  13. {
  14. x.RequireHttpsMetadata = false;
  15. x.SaveToken = true;
  16. x.TokenValidationParameters = new TokenValidationParameters
  17. {
  18. ValidateIssuerSigningKey = true,
  19. IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(token.SecretKey)),
  20. ValidIssuer = token.Issuer,
  21. ValidAudience = token.Audience,
  22. ValidateIssuer = false,
  23. ValidateAudience = false
  24. };
  25. });
  26. //other code
  27. }

 2、在需要支持多种认证方式的控制器上添加标记:

  1. //指定认证时,采用CustomerAuthenticationHandler.CustomerSchemeName
  2. [Authorize(AuthenticationSchemes = CustomerAuthenticationHandler.CustomerSchemeName)]
  3. [Route("api/[controller]")]
  4. [ApiController]
  5. public class AuditLogController : ControllerBase
  6. {
  7. //code
  8. }
  9.  
  10. //指定认证采用JWT
  11. [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
  12. public class WeatherForecastController : ControllerBase
  13. {
  14. //code
  15. }

  这样就支持了两种认证方式

 3、一个控制器支持多种认证类型:继承Jwt认证处理,并根据Scheme那么调用自定义的认证处理器:

  1. /// <summary>
  2. /// 方式二:同时支持多种认证方式
  3. /// </summary>
  4. public class MultAuthenticationHandler : JwtBearerHandler
  5. {
  6. public const string MultAuthName = "MultAuth";
  7. IUserService _userService;
  8. public MultAuthenticationHandler(IOptionsMonitor<JwtBearerOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
  9. : base(options, logger, encoder, clock)
  10. {
  11. _userService = userService;
  12. }
  13.  
  14. protected override Task<AuthenticateResult> HandleAuthenticateAsync()
  15. {
  16. Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
  17. string valStr = values.ToString();
  18. if (valStr.StartsWith(CustomerAuthenticationHandler.CustomerSchemeName))
  19. {
  20. var result = Valid();
  21. if (result != null)
  22. return Task.FromResult(AuthenticateResult.Success(result));
  23. else
  24. return Task.FromResult(AuthenticateResult.Fail("未认证"));
  25. }
  26. else
  27. return base.AuthenticateAsync();
  28. }
  29.  
  30. private AuthenticationTicket Valid()
  31. {
  32. Context.Request.Headers.TryGetValue("Authorization", out StringValues values);
  33. string valStr = values.ToString();
  34. if (!string.IsNullOrWhiteSpace(valStr))
  35. {
  36. //认证模拟basic认证:cusAuth YWRtaW46YWRtaW4=
  37. string[] authVal = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(valStr.Substring(CustomerAuthenticationHandler.CustomerSchemeName.Length + 1))).Split(':');
  38. var loginInfo = new Dto.LoginDto() { Username = authVal[0], Password = authVal[1] };
  39. if (_userService.IsValid(loginInfo))
  40. return GetAuthTicket(loginInfo.Username, "admin");
  41. }
  42. return null;
  43. }
  44.  
  45. /// <summary>
  46. /// 生成认证票据
  47. /// </summary>
  48. /// <param name="name"></param>
  49. /// <param name="role"></param>
  50. /// <returns></returns>
  51. private AuthenticationTicket GetAuthTicket(string name, string role)
  52. {
  53. var claimsIdentity = new ClaimsIdentity(new Claim[]
  54. {
  55. new Claim(ClaimTypes.Name, name),
  56. new Claim(ClaimTypes.Role, role),
  57. }, CustomerAuthenticationHandler.CustomerSchemeName);
  58. var principal = new ClaimsPrincipal(claimsIdentity);
  59. return new AuthenticationTicket(principal, CustomerAuthenticationHandler.CustomerSchemeName);
  60. }
  61. }

四、总结

 .Net Core中的自定义认证主要通过实现IAuthenticationHandler 接口实现,如果要实现多认证方式通过AddScheme 应用自定义实现的认证处理器。

 源码:github

 参考:认证

  

.Net Core中自定义认证实现的更多相关文章

  1. .NET Core中的认证管理解析

    .NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...

  2. [转].NET Core中的认证管理解析

    本文转自:http://www.cnblogs.com/durow/p/5783089.html 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用 ...

  3. 如何在ASP.NET Core中自定义Azure Storage File Provider

    文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...

  4. ASP.NET Core中自定义路由约束

    路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...

  5. CORE MVC 自定义认证

    微软的认证体系,集成了EF,和它的表结构,对于我们已有的系统,或者想高度自定义的人,该怎么办呢? 答案在: https://docs.microsoft.com/en-us/aspnet/core/s ...

  6. .net core 中的经典设计模式的应用

    .net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...

  7. asp.net core 2.1认证

    asp.net core 2.1认证 这篇文章基于asp.net core的CookieAuthenticationHandler来讲述. 认证和授权很相似,他们的英文也很相似,一个是Authenti ...

  8. asp.net Core 中AuthorizationHandler 实现自定义授权

    前言 ASP.NET Core 中 继承的是AuthorizationHandler ,而ASP.NET Framework 中继承的是AuthorizeAttribute. 它们都是用过重写里面的方 ...

  9. asp.net core 自定义认证方式--请求头认证

    asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...

随机推荐

  1. 痞子衡嵌入式:揭秘i.MXRT1170上用J-Link连接复位后PC总是停在0x223104的原因

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上安全调试策略实现对JLink调试的影响. 痞子衡之前写过一篇旧文 <i.MXRT600的ISP模式下用J-L ...

  2. RPA项目POC指南:概念、步骤与技巧

    "为什么部署RPA前要进行POC?RPA不是开箱即用吗?" 其实,RPA的实施并非总是一帆风顺,"碰坑"在所难免. 据安永报告显示,30%至50%的初始RPA项 ...

  3. java类型转换拓展

    数据类型拓展 在Java中二进制用0b开头,八进制用0开头,十六进制用0x表示 整数拓展  int i=10; int i2=010;//八进制 int i3=0x10;//十六进制0x,0-9,A- ...

  4. 【LeetCode】1465. 切割后面积最大的蛋糕 Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 找最大间隔之积 日期 题目地址:https://lee ...

  5. 【LeetCode】575. Distribute Candies 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 题目地址:ht ...

  6. 【LeetCode】842. Split Array into Fibonacci Sequence 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  7. 【.NET 遇上 GraphQL】 ChilliCream 平台介绍

    ChilliCream ChilliCream 是一个开源免费的 GraphQL 平台, 提供了构建.管理, 和访问 GraphQL API 的端到端的解决方案. https://chillicrea ...

  8. 洛谷 P2397:yyy loves Maths VI (mode)(摩尔投票算法)

    题目背景 自动上次redbag用加法好好的刁难过了yyy同学以后,yyy十分愤怒.他还击给了redbag一题,但是这题他惊讶的发现自己居然也不会,所以只好找你 题目描述 [h1]udp2:第一题因为语 ...

  9. 「算法笔记」Polya 定理

    一.前置概念 接下来的这些定义摘自 置换群 - OI Wiki. 1. 群 若集合 \(s\neq \varnothing\) 和 \(S\) 上的运算 \(\cdot\) 构成的代数结构 \((S, ...

  10. <数据结构>关键路径

    目录 AOV网和AOE网 AOV网 AOE网 定义 与AOV网的转化 AOE网中着重解决的两个问题 1.最长路径问题 2.关键活动问题 总结 最长路径 无正环的图 有向无环图的最短路径 其他情况 关键 ...