[Abp vNext 源码分析] - 7. 权限与验证 (2)

那么它的实现就非常简单了,只需要注入 ABP vNext 为我们提供的 ICurrentPrincipalAccessor 访问器,我们就能够拿到这个身份容器(ClaimsPrincipal)。

public class CurrentUser : ICurrentUser, ITransientDependency { // ... 其他代码 public virtual string[] Roles => FindClaims(AbpClaimTypes.Role).Select(c => c.Value).ToArray(); private readonly ICurrentPrincipalAccessor _principalAccessor; public CurrentUser(ICurrentPrincipalAccessor principalAccessor) { _principalAccessor = principalAccessor; } // ... 其他代码 public virtual Claim[] FindClaims(string claimType) { // 直接使用 LINQ 查询对应的 Type 就能拿到上述信息。 return _principalAccessor.Principal?.Claims.Where(c => c.Type == claimType).ToArray() ?? EmptyClaimsArray; } // ... 其他代码 }

至于 CurrentUserExtensions 扩展类,里面只是对 ClaimsPrincipal 的搜索方法进行了多种封装而已。

PS:

除了 ICurrentUser 与 ICurrentClient 之外,在 ABP vNext 里面还有 ICurrentTenant 来获取当前租户信息。通过这三个组件,取代了老 ABP 框架的 IAbpSession 组件,三个组件都没有 IAbpSession.Use() 扩展方法帮助我们临时更改当前用户/租户。

2.1.4 ClaimsPrincipal 访问器

关于 ClaimsPrincipal 的内容,可以参考杨总的 《ASP.NET Core 之 Identity 入门》 进行了解,大致来说就是存有 Claim 信息的聚合对象。

关于 ABP vNext 框架预定义的 Claim Type 都存放在 AbpClaimTypes 类型里面的,包括租户 Id、用户 Id 等数据,这些玩意儿最终会被放在 JWT(JSON Web Token) 里面去。

一般来说 ClaimsPrincipal 里面都是从 HttpContext.User 或者 Thread.CurrentPrincipal 得到的,ABP vNext 为我们抽象出了一个快速访问接口 ICurrentPrincipalAccessor。开发人员注入之后,就可以获得当前用户的 ClaimsPrincipal 对象。

public interface ICurrentPrincipalAccessor { ClaimsPrincipal Principal { get; } }

对于 Thread.CurrentPrincipal 的实现:

public class ThreadCurrentPrincipalAccessor : ICurrentPrincipalAccessor, ISingletonDependency { public virtual ClaimsPrincipal Principal => Thread.CurrentPrincipal as ClaimsPrincipal; }

而针对于 Http 上下文的实现,则是放在 Volo.Abp.AspNetCore 模块里面的。

public class HttpContextCurrentPrincipalAccessor : ThreadCurrentPrincipalAccessor { // 如果没有获取到数据,则使用 Thread.CurrentPrincipal。 public override ClaimsPrincipal Principal => _httpContextAccessor.HttpContext?.User ?? base.Principal; private readonly IHttpContextAccessor _httpContextAccessor; public HttpContextCurrentPrincipalAccessor(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; } } 扩展知识:两者的区别?

Thread.CurrentPrincipal 可以设置/获得当前线程的 ClaimsPrincipal 数据,而 HttpContext?.User 一般都是被 ASP.NET Core 中间件所填充的。

最新的 ASP.NET Core 开发建议是不要使用 Thread.CurrentPrincipal 和 ClaimsPrincipal.Current (内部实现还是使用的前者)。这是因为 Thread.CurrentPrincipal 是一个静态成员...而这个静态成员在异步代码中会出现各种问题,例如有以下代码:

// Create a ClaimsPrincipal and set Thread.CurrentPrincipal var identity = new ClaimsIdentity(); identity.AddClaim(new Claim(ClaimTypes.Name, "User1")); Thread.CurrentPrincipal = new ClaimsPrincipal(identity); // Check the current user Console.WriteLine($"Current user: {Thread.CurrentPrincipal?.Identity.Name}"); // For the method to complete asynchronously await Task.Yield(); // Check the current user after Console.WriteLine($"Current user: {Thread.CurrentPrincipal?.Identity.Name}");

当 await 执行完成之后会产生线程切换,这个时候 Thread.CurrentPrincipal 的值就是 null 了,这就会产生不可预料的后果。

如果你还想了解更多信息,可以参考以下两篇博文:

DAVID PINE - 《WHAT HAPPENED TO MY THREAD.CURRENTPRINCIPAL》

SCOTT HANSELMAN - 《System.Threading.Thread.CurrentPrincipal vs. System.Web.HttpContext.Current.User or why FormsAuthentication can be subtle》

2.1.5 字符串加密工具

这一套东西就比较简单了,是 ABP vNext 为我们提供的一套开箱即用组件。开发人员可以使用 IStringEncryptionService 来加密/解密你的字符串,默认实现是基于 Rfc2898DeriveBytes 的。关于详细信息,你可以阅读具体的代码,这里不再赘述。

2.2 权限与校验

Volo.Abp.Authorization 模块里面就对权限进行了具体定义,并且基于 ASP.NET Core Authentication 进行无缝集成。如果读者对于 ASP.NET Core 认证和授权不太了解,可以去学习一下 雨夜朦胧 大神的《ASP.NET Core 认证于授权》系列文章,这里就不再赘述。

2.2.1 权限的注册

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpzzps.html