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

在上篇文章里面,我们在 ApplicationService 当中看到了权限检测代码,通过注入 IAuthorizationService 就可以实现权限检测。不过跳转到源码才发现,这个接口是 ASP.NET Core 原生提供的 “基于策略” 的权限验证接口,这就说明 ABP vNext 基于原生的授权验证框架进行了自定义扩展。

让我们来看一下 Volo.Abp.Ddd.Application 项目的依赖结构(权限相关)。

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

本篇文章下面的内容基本就会围绕上述框架模块展开,本篇文章通篇较长,因为还涉及到 .NET Core IdentityIdentityServer4 这两部分。关于这两部分的内容,我会在本篇文章大概讲述 ABP vNext 的实现,关于更加详细的内容,请查阅官方文档或其他博主的博客。

二、源码分析

ABP vNext 关于权限验证和权限定义的部分,都存放在 Volo.Abp.AuthorizationVolo.Abp.Security 模块内部。源码分析我都比较喜欢倒推,即通过实际的使用场景,反向推导 基础实现,所以后面文章编写的顺序也将会以这种方式进行。

2.1 Security 基础组件库

这里我们先来到 Volo.Abp.Security,因为这个模块代码和类型都是最少的。这个项目都没有模块定义,说明里面的东西都是定义的一些基础组件。

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

2.1.1 Claims 与 Identity 的快捷访问

先从第一个扩展方法开始,这个扩展方法里面比较简单,它主要是提供对 ClaimsPrincipal 和 IIdentity 的快捷访问方法。比如我要从 ClaimsPrincipal / IIdentity 获取租户 Id、用户 Id 等。

public static class AbpClaimsIdentityExtensions { public static Guid? FindUserId([NotNull] this ClaimsPrincipal principal) { Check.NotNull(principal, nameof(principal)); // 根据 AbpClaimTypes.UserId 查找对应的值。 var userIdOrNull = principal.Claims?.FirstOrDefault(c => c.Type == AbpClaimTypes.UserId); if (userIdOrNull == null || userIdOrNull.Value.IsNullOrWhiteSpace()) { return null; } // 返回 Guid 对象。 return Guid.Parse(userIdOrNull.Value); } 2.1.2 未授权异常的定义

这个异常我们在老版本 ABP 里面也见到过,它就是 AbpAuthorizationException 。只要有任何未授权的操作,都会导致该异常被抛出。后面我们在讲解 ASP.NET Core MVC 的时候就会知道,在默认的错误码处理中,针对于程序抛出的 AbpAuthorizationException ,都会视为 403 或者 401 错误。

public class DefaultHttpExceptionStatusCodeFinder : IHttpExceptionStatusCodeFinder, ITransientDependency { // ... 其他代码 public virtual HttpStatusCode GetStatusCode(HttpContext httpContext, Exception exception) { // ... 其他代码 // 根据 HTTP 协议对于状态码的定义,401 表示的是没有登录的用于尝试访问受保护的资源。而 403 则表示用户已经登录,但他没有目标资源的访问权限。 if (exception is AbpAuthorizationException) { return httpContext.User.Identity.IsAuthenticated ? HttpStatusCode.Forbidden : HttpStatusCode.Unauthorized; } // ... 其他代码 } // ... 其他代码 }

就 AbpAuthorizationException 异常来说,它本身并不复杂,只是一个简单的异常而已。只是因为它的特殊含义,在 ABP vNext 处理异常时都会进行特殊处理。

只是在这里我说明一下,ABP vNext 将它所有的异常都设置为可序列化的,这里的可序列化不仅仅是将 Serialzable 标签打在类上就行了。ABP vNext 还创建了基于 StreamingContext 的构造函数,方便我们后续对序列化操作进行定制化处理。

关于运行时序列化的相关文章,可以参考 《CLR Via C#》第 24 章,我也编写了相应的 读书笔记

2.1.3 当前用户与客户端

开发人员经常会在各种地方需要获取当前的用户信息,ABP vNext 将当前用户封装到 ICurrentUser 与其实现 CurrentUser 当中,使用时只需要注入 ICurrentUser 接口即可。

我们首先康康 ICurrentUser 接口的定义:

public interface ICurrentUser { bool IsAuthenticated { get; } [CanBeNull] Guid? Id { get; } [CanBeNull] string UserName { get; } [CanBeNull] string PhoneNumber { get; } bool PhoneNumberVerified { get; } [CanBeNull] string Email { get; } bool EmailVerified { get; } Guid? TenantId { get; } [NotNull] string[] Roles { get; } [CanBeNull] Claim FindClaim(string claimType); [NotNull] Claim[] FindClaims(string claimType); [NotNull] Claim[] GetAllClaims(); bool IsInRole(string roleName); }

那么这些值是从哪儿来的呢?从带有 Claim 返回值的方法来看,肯定就是从 HttpContext.User 或者 Thread.CurrentPrincipal 里面拿到的。

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

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