.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中的认证管理解析
.NET Core中的认证管理解析 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用户和权限管理的项目,已经准备好了用户注册.登录等很多页面,也可 ...
- [转].NET Core中的认证管理解析
本文转自:http://www.cnblogs.com/durow/p/5783089.html 0x00 问题来源 在新建.NET Core的Web项目时选择“使用个人用户账户”就可以创建一个带有用 ...
- 如何在ASP.NET Core中自定义Azure Storage File Provider
文章标题:如何在ASP.NET Core中自定义Azure Storage File Provider 作者:Lamond Lu 地址:https://www.cnblogs.com/lwqlun/p ...
- ASP.NET Core中自定义路由约束
路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...
- CORE MVC 自定义认证
微软的认证体系,集成了EF,和它的表结构,对于我们已有的系统,或者想高度自定义的人,该怎么办呢? 答案在: https://docs.microsoft.com/en-us/aspnet/core/s ...
- .net core 中的经典设计模式的应用
.net core 中的经典设计模式的应用 Intro 前段时间我们介绍了23种设计模式,今天来分享一下 asp.net core 种我觉得比较典型的设计模式的应用 实例 责任链模式 asp.net ...
- asp.net core 2.1认证
asp.net core 2.1认证 这篇文章基于asp.net core的CookieAuthenticationHandler来讲述. 认证和授权很相似,他们的英文也很相似,一个是Authenti ...
- asp.net Core 中AuthorizationHandler 实现自定义授权
前言 ASP.NET Core 中 继承的是AuthorizationHandler ,而ASP.NET Framework 中继承的是AuthorizeAttribute. 它们都是用过重写里面的方 ...
- asp.net core 自定义认证方式--请求头认证
asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思 ...
随机推荐
- 痞子衡嵌入式:揭秘i.MXRT1170上用J-Link连接复位后PC总是停在0x223104的原因
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRT1170上安全调试策略实现对JLink调试的影响. 痞子衡之前写过一篇旧文 <i.MXRT600的ISP模式下用J-L ...
- RPA项目POC指南:概念、步骤与技巧
"为什么部署RPA前要进行POC?RPA不是开箱即用吗?" 其实,RPA的实施并非总是一帆风顺,"碰坑"在所难免. 据安永报告显示,30%至50%的初始RPA项 ...
- java类型转换拓展
数据类型拓展 在Java中二进制用0b开头,八进制用0开头,十六进制用0x表示 整数拓展 int i=10; int i2=010;//八进制 int i3=0x10;//十六进制0x,0-9,A- ...
- 【LeetCode】1465. 切割后面积最大的蛋糕 Maximum Area of a Piece of Cake After Horizontal and Vertical Cuts
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 找最大间隔之积 日期 题目地址:https://lee ...
- 【LeetCode】575. Distribute Candies 解题报告(Java & Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 Java解法 Python解法 日期 题目地址:ht ...
- 【LeetCode】842. Split Array into Fibonacci Sequence 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【.NET 遇上 GraphQL】 ChilliCream 平台介绍
ChilliCream ChilliCream 是一个开源免费的 GraphQL 平台, 提供了构建.管理, 和访问 GraphQL API 的端到端的解决方案. https://chillicrea ...
- 洛谷 P2397:yyy loves Maths VI (mode)(摩尔投票算法)
题目背景 自动上次redbag用加法好好的刁难过了yyy同学以后,yyy十分愤怒.他还击给了redbag一题,但是这题他惊讶的发现自己居然也不会,所以只好找你 题目描述 [h1]udp2:第一题因为语 ...
- 「算法笔记」Polya 定理
一.前置概念 接下来的这些定义摘自 置换群 - OI Wiki. 1. 群 若集合 \(s\neq \varnothing\) 和 \(S\) 上的运算 \(\cdot\) 构成的代数结构 \((S, ...
- <数据结构>关键路径
目录 AOV网和AOE网 AOV网 AOE网 定义 与AOV网的转化 AOE网中着重解决的两个问题 1.最长路径问题 2.关键活动问题 总结 最长路径 无正环的图 有向无环图的最短路径 其他情况 关键 ...