微信公众号:趣编程ACE
关注可了解.NET日常开发技巧。如需源码,请公众号留言 [源码];
上文回顾
【鉴权/授权】一步一步实现一个简易JWT鉴权自定义身份验证CustomerAuthenticationHandler使用
上篇文章我演示了如何利用.net core 里面内置的验证方案-Bearer 进行身份验证,本文通过一个简单的例子来实现自定义身份验证流程。
超清观看哦~
首先创建一个登录服务
里面有三大步骤
1//Step1: 登录接口 需要在内置容器里面依赖注入2public interface ICustomerAuthentication3{4 ...5}67// 接口的实例8public class CustomerAuthentication : ICustomerAuthentication9{
10 // Step2:提供一个登录方法
11 public string Login(string userName, string password)
12 {
13
14 }
15}
16
17// Step3: 容器依赖注入
18builder.Services.AddSingleton<ICustomerAuthentication,CustomerAuthentication>();
登录接口实现
1// 相当于在内存里面定义一个用户对象集合 模拟从数据库查询获取用户对象 方便check2private readonly IDictionary<string,string> users = new Dictionary<string,string>3{4 {"p1","a1"},5 {"p2","a2"},6};7// 存放token集合8private readonly IDictionary<string,string> tokens = new Dictionary<string,string>();9public IDictionary<string,string> Tokens =>tokens; // 实现接口 并初始化
10
11public string Login(string userName, string password)
12{
13 // check 用户真实存在
14 if(!users.Any(u=>u.Key==userName && u.Value==password))
15 {
16 return null;
17 }
18 // create token 通过一个Guid 类型的数据来代替token 仅为演示
19 var token = new Guid().ToString();
20 tokens.Add(token,userName);
21 return token ;
22}
创建一个自定义CustomerAuthenticationHandler类
1public class CustomerAuthenticationHandler :AuthenticationHandler<BasicAuthenticationOptions>
2{
3 ...
4}
其中CustomerAuthenticationHandler需要继承AuthenticationHandler接口,这个接口需要一个用于身份验证的Options配置类,所以需要定义一下BasicAuthenticationOptions 继承AuthenticationSchemeOptions
1public class BasicAuthenticationOptions :AuthenticationSchemeOptions
2{
3
4}
实现HandleAuthenticateAsync方法
1protected override async Task<AuthenticateResult> HandleAuthenticateAsync()2 {3 // throw new NotImplementedException();4 if(!Request.Headers.ContainsKey("Authorization"))5 {6 return AuthenticateResult.Fail("UnAuthorized");7 }89 // 获取请求头里面 Authorization对应的value
10 string authenticationHeader = Request.Headers["Authorization"];
11 if(string.IsNullOrEmpty(authenticationHeader))
12 {
13 return AuthenticateResult.Fail("UnAuthorized");
14 }
15 if(!authenticationHeader.StartsWith("Bearer",StringComparison.OrdinalIgnoreCase))
16 {
17 return AuthenticateResult.Fail("UnAuthorized");
18 }
19 // 获取token
20 string token = authenticationHeader.Substring("bearer".Length).Trim();
21 if(string.IsNullOrEmpty(token))
22 {
23 return AuthenticateResult.Fail("UnAuthorized");
24 }
25
26 try
27 {
28 // 验证token 调用下方ValidateToken() 这个方法
29 return ValidateToken(token);
30 }
31 catch (System.Exception ex)
32 {
33 // 记录日志
34 return AuthenticateResult.Fail("UnAuthorized");
35 }
36 }
37
38private AuthenticateResult ValidateToken(string token)
39 {
40 var validateToken = _customerAuthentication.Tokens.FirstOrDefault(t=>t.Key ==token);
41 if(validateToken.Key is null )
42 {
43 return AuthenticateResult.Fail("UnAuthorized");
44 }
45 var claims = new List<Claim>
46 {
47 new Claim(ClaimTypes.Name,validateToken.Value)
48 };
49
50 var identity = new ClaimsIdentity(claims,Scheme.Name);
51 var principle = new GenericPrincipal(identity,null);
52 var ticket = new AuthenticationTicket(principle,Scheme.Name);
53 return AuthenticateResult.Success(ticket);
54 }
该方法返回一个AuthenticateResult类型的对象来表示身份验证是否成功,如果成功,需要将这个票据返还给用户。
那么为啥需要票据呢?因为我们在Http传输协议下,需要保证附加在请求头或者请求参数的内容的安全性,所以需要将principal对象包裹成AuthenticationTicket对象,在后者里面我们可以增加一些安全配置。
DI中注册认证服务
1// 自定义验证 取名为一个 test 的Scheme方案
2builder.Services.AddAuthentication("test")
3 .AddScheme<BasicAuthenticationOptions,CustomerAuthenticationHandler>("test",null);
PS:本文来自社区群粉丝投稿~