asp.net core 2.1认证
这篇文章基于asp.net core的CookieAuthenticationHandler来讲述。
认证和授权很相似,他们的英文也很相似,一个是Authentication认证,一个是Authorization授权。
asp.net core中的认证需要在Startup类中进行配置:
//ConfigureServices方法中: services.AddAuthentication(option => { option.DefaultScheme = "Cookie"; option.DefaultChallengeScheme = "Cookie"; option.DefaultAuthenticateScheme = "Cookie"; option.DefaultForbidScheme = "Cookie"; option.DefaultSignInScheme = "Cookie"; option.DefaultSignOutScheme = "Cookie"; }).AddCookie("Cookie", option => { option.LoginPath = "/Account/Login"; option.AccessDeniedPath = "/Account/Forbidden"; //....... });
//Configure方法中 app.UseAuthentication();
看一看到如果需要认证的话是需要分别在ConfigureService方法和Configure方法中分别进行配置的。
我们看到上面在AddAuthentication方法中配置了一个option,这个option是一个Action<AuthenticationOption>,在里面,写了一堆scheme。这个scheme是什么意思呢?我们先解释一下在asp.neet core中发生的这几个动作。在asp.net core中是有几个动作要发生的:
1、登陆(Signin):用户要进行登陆的动作。
2、登出(Signout):用户要进行登出。
3、Challenge:这个不好翻译,意思当用户需要请求一个被保护的资源时,系统要求用户进行登陆。总之他也是一个登陆的动作,但是被动的登陆。
4、认证(Authenticate):认证,系统将用户的信息从token/cookie中读取出来。和登陆这个动作正好相反。
5、Forbid:系统对用户执行了拒绝的操作。
上面这些动作最后都是由一个Handler来执行的,这个handler就是一个IAuthenticationHandler的实现。
我们先给出了上面的总结,再看一下具体的情况。asp.net core2.0开始上面的这些动作的执行都是通过HttpContext的扩展方法来执行的。我们拿登陆来说,其他都大同小异。
先看HttpContext.SigninAsync这个方法:
var claim = new Claim("name", "wallee");//我的众多信息中的一个信息单元,还有年龄、性别、家庭等等 var identity = new ClaimsIdentity("身份证");//我的众多身份证件中的一个,还有驾驶证、准考证、会计证、计算机二级证等等 identity.AddClaim(claim);//将上面那个信息片段添加到我的身份证里面 var principal=new ClaimsPrincipal(identity);//将身份证作为我这个人的初始化参数,初始化一个ClaimsPrincipal就代表了一个主体。 HttpContext.SignInAsync(principal);//最后,利用这个主体,调用HttpContext的扩展方法进行登陆。
上面的代码中注释解释了一些和本文无关但又非常重要的信息,我们关键看最后哪一行:HttpContext.SigninAsync(principal);这行代码实现了最终的登陆。现在我们看一下它的实现:
public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) { return context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties); }
上面的代码就是SigninAsync这个扩展方法的最终实现,之所以说是最终是因为它一开始调用的是同名的其他重载方法,但是方法内部最终调用到了这里。
可以看到一开始这个方法是从DI里面获取了一个IAuthenticationService,这个东西在services.AddAuthentication()这个方法中被注入到了DI,有兴趣的可以看一下。本文对这个不展开了。
之后,调用IAuthenticationService类型上面的SigninAsync(),这个方法要接收四个参数,都是从HttpContext.SigninAsync()方法中传进来的。
- 一个是context,表示一个http上下文
- 一个是scheme,表示一个方案
- 一个是ClaimsPrincipal,表示一个主体,就是用户
- 一个是AuthenticationProperties,用来设置一些参数比如Cookie持续时间等等
然后继续看一下IAuthenticationService.SignAsync()方法:
public virtual async Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) { if (principal == null) throw new ArgumentNullException(nameof (principal)); if (scheme == null) { scheme = (await this.Schemes.GetDefaultSignInSchemeAsync())?.Name; if (scheme == null) throw new InvalidOperationException("No authenticationScheme was specified, and there was no DefaultSignInScheme found."); } IAuthenticationSignInHandler handlerAsync = await this.Handlers.GetHandlerAsync(context, scheme) as IAuthenticationSignInHandler; if (handlerAsync == null) throw new InvalidOperationException(string.Format("No IAuthenticationSignInHandler is configured to handle sign in for the scheme: {0}", (object) scheme)); await handlerAsync.SignInAsync(principal, properties); }
这个方法的流程是:
1、判断principal是否为null如果是则抛异常
2、如果scheme为null则从Scheme属性(IAuthenticationSchemeProvider)中找出默认的scheme的名字。
3、如果这个默认的也是null的话,就抛异常
4、利用scheme(string),和context(httpcontext)从Handlers属性(IAuthenticationHandlerProvider)中找出IAuthenticationHandler。
5、如果第四步找出的handler为空,那么抛异常。
6、如果不为空,那么,有最后得到的handler来执行Signin的动作,这个动作需要两个参数,一个是ClaimsPrincipal类型的principal,还有一个是AuthenticationProperties的properties。
总结:上面的登陆方法是从调用HttpContext的扩展方法SigninAsync开始的,最终会调用一个接收三个参数(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties,context不算)的扩展方法,这个方法在内部要从DI中拿到一个IAuthenticationSerivce接口类型的对象,这个对象是对IAuthenticationScheme和对IAuthenticationHandler的一个封装。拿到这个IAuthentcationService的对象之后,调用这个对象上的SigninAsync方法,这个方法内部会先对传入的scheme参数进行一些判断,如果shcme为空,那么通过Scheme(IAuthenticationSchemeProvider)属性来查找一个默认的。如果还是空的话抛异常,接着,利用Handlers属性(IAuthenticationHandlerProvider类型)找到最终的handler:IAuthenticationHandler对象,来处理最后的登陆。
原文地址:https://www.cnblogs.com/pangjianxin/p/9388224.html