19

深入解读 ASP.NET Core 身份认证过程

 3 years ago
source link: http://www.cnblogs.com/JulianHuang/p/13766100.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

长话短说:上文我们讲了 ASP.NET Core 基于声明的访问控制到底是什么鬼?

今天我们乘胜追击:聊一聊ASP.NET Core 中的身份验证。

身份验证是确定用户身份的过程。 授权是确定用户是否有权访问资源的过程。

1. 万变不离其宗

显而易见,一个常规的身份认证用例包括两部分:

① 对用户进行身份验证

② 在未经身份验证的用户试图访问受限资源时作出反应

已注册的身份验证处理程序及其配置选项被称为“方案”,方案可用作一种机制,供用户参考相关处理程序的身份验证、挑战和禁止行为。

我们口头上常说的:

基于cookie认证方案,若认证成功,go on,若认证失败则跳转回登录页面;

基于基本身份认证(BA)方案,若认证成功,go on,若认证失败则给浏览器返回 WWW-Authenticate 标头, 浏览器会再次弹出认证窗口。

2. ASP.NET Core认证原理

在 ASP.NET Core 中,身份验证由 IAuthenticationService 负责,身份验证服务会调用已注册的身份验证处理程序来完成与身份验证相关的操作, 整个验证过程由 认证中间件 来串联。

一图以蔽之:

c99ce9c3-22f9-43da-958a-92c281838c02.png?UCloudPublicKey=TOKEN_8d8b72be-579a-4e83-bfd0-5f6ce1546f13&Signature=7tOjcM%252B2V8NpeVRkXw1g4De8VcU%253D&Expires=1601817858

其中有几个关键步骤

  1. 认证处理程序

    可结合方案Scheme中的配置项 AuthenticationSchemeOptions 编写认证处理程序。

    基于Cookie的认证方案可在Options项中可指定登录地址,

    基于基本身份的认证方案可在Options项中指定用户名/密码;

  2. 身份认证程序继承自 AuthenticationHandler类IAuthenticationHandler接口

    6F7JNbY.png!mobile
  • 核心认证函数可落地基于声明的访问控制,生成绑定了ClaimsPrincipal、Scheme的 AuthenticationTicket对象 ; 无论认证成功/失败,函数返回 AuthenticateResult对象

  • 挑战(对未认证的用户做出的反应): 例如返回登录页面

  • 禁止(对已认证,但对特定资源无权访问做出的反应) : 例如返回提示字符串

以上均为服务注册过程

  1. IAuthenticationService

    收到请求,认证中间件使用 IAuthenticationService 对HttpContext按照要求的scheme进行认证, 实际内部会调用第2步编写的认证处理程序。

    nQj6jmr.png!mobile

以上认证原理,之前有一个近身实战: ASP.NET Core 实现基本身份验证。

源代码如下: https://www.cnblogs.com/JulianHuang/p/10345365.html

3. ASP.NET Core获取当前用户

基于声明的访问控制, 我们会在HttpContext.User属性存储身份信息。

var claims = new[] {
               new Claim(ClaimTypes.NameIdentifier,username),
               new Claim(ClaimTypes.Name,username),
           };
 var identity = new ClaimsIdentity(claims, Scheme.Name);
 var principal = new ClaimsPrincipal(identity);
 Context.User = principal;

Web应用程序中获取当前登录用户, 有两种代码场合:

3.1 在控制器中获取当前登录用户

控制器是处理请求的 一等公民,天生自带HttpContext。

直接通过ControllerBase基类中包含的HttpContext属性,获取User对象。

实际上Razor Page、Razor View、Middleware均包含HttpContext属性/参数, 可直接使用。

3.2 在服务中获取当前登录用户

这个时候,服务是作为请求处理中的一个环节,并没有直接可用的HttpContext。

ASP.NET Core 提供了 IHttpContextAccessor类 能够注入此次请求中的HttpContext对象(依赖注入框架的作用)。

//  下面的用户实体类,需要获取当前登录用户,借助IHttpContextAccessor注入httpContext
public class UserEntityService : IUserEntityService
{
   private IHttpContextAccessor _accessor;
   private readonly IMongoCollection<UserProfile> _users;

   public UserEntityService(IHttpContextAccessor accessor, IDefaultMongoDatabaseProvider databaseProvider)
   {
       _accessor = accessor;
       _users = databaseProvider.GetCollection<UserProfile>(CollectionNames.UserProfiles);
   }

   public Task<UserProfile> GetCurrentUserAsync()
   {
       var rawUser = this._accessor.HttpContext.User();
       if (rawUser == null)
       {
          return null;
       }
       var filter = Builders<UserProfile>.Filter.Eq("UserId", rawUser.UserId);
      return _users.Find(filter).FirstOrDefaultAsync();
   }
}

+ abp vnext

我们不需要区分以上代码场合,在Controller或者Application 服务中使用 ICurrentUser 接口拿到登录用户。

旁白

个人认为,ASP.NET Core身份认证的源代码, 基于现实认知提炼而来,让我们惊叹于框架代码的的简洁精炼、层次分明。

基于声明的访问控制已成标准,ASP.NET Core/abp vnext 均提供了完善的支持。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK