ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

ASP.NET Core 授权(Authorization)组件源码指南:从 Policy 到 Middleware 的完整实现解析

ASP.NET Core 授权(Authorization)组件源码指南:从 Policy 到 Middleware 的完整实现解析 ASP.NET Core 授权Authorization组件源码指南从 Policy 到 Middleware 的完整实现解析【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore本篇指南以 aspnetcore 仓库中src/Security/Authorization/组件为主体系统讲解 ASP.NET Core 授权能力的模块划分、核心对象模型Requirement、Handler、Policy、Service、策略授权中间件的执行流程以及该组件的本地构建与测试方法。读完本文你将掌握授权组件的目录结构、AddAuthorization/UseAuthorization的底层注册链路、内置需求与处理器的工作方式并能独立在本仓库中对该组件进行源码级调试与测试验证。组件定位与目录结构Authorization 是 ASP.NET Core 安全体系中判断当前用户是否具备所需权限的核心组件与负责识别用户身份的 Authenticationsrc/Security/Authentication/分工明确。整个安全模块的入口说明见 src/Security/README.md其中明确指出Authentication 负责识别用户Authorization 负责判断用户是否拥有所需权限。按 src/Security/Authorization/README.md 的说明该组件包含三个子目录Core/共享授权组件即与具体宿主MVC、SignalR、最小 API无关的核心类型包括IAuthorizationService、AuthorizationPolicy、AuthorizationHandlerContext、AuthorizationOptions以及全部内置需求与处理器。Policy/基于策略Policy的授权提供AddAuthorization服务注册、UseAuthorization中间件接入、IPolicyEvaluator策略评估器与中间件结果处理器。test/共享测试覆盖 Core 与 Policy 两部分的单元测试。从源码结构看这种Core 提供可复用的核心机制、Policy 提供 HTTP 管道集成的拆分使得授权逻辑既能被 MVC 的AuthorizeFilter、端点路由的AuthorizationMiddleware、SignalR 与 Blazor 复用又能保持单一职责、避免循环依赖。核心概念模型Requirement、Handler、Context、Policy授权组件的核心设计可以概括为四个互相协作的对象需求Requirement、处理器Handler、上下文Context与策略Policy。IAuthorizationRequirement一个标记接口IAuthorizationRequirement是授权的最小单元本身只是空标记接口见 IAuthorizationRequirement.cs。它不定义任何行为行为完全由对应的 Handler 决定这为自定义授权条件提供了极大自由度——你可以为任意业务规则定义一个 Requirement 类。IAuthorizationHandler 与基类IAuthorizationHandler定义唯一的入口HandleAsync(AuthorizationHandlerContext context)见 IAuthorizationHandler.cs。实际开发中通常不直接实现该接口而是继承两个泛型基类见 AuthorizationHandler.csAuthorizationHandlerTRequirement针对特定需求类型其HandleAsync会遍历context.Requirements中所有TRequirement类型的需求并逐个调用HandleRequirementAsyncAuthorizationHandlerTRequirement, TResource进一步限定资源类型仅当context.Resource is TResource时才执行评估适合文档、单据等资源敏感型授权。AuthorizationHandlerContext评估状态容器AuthorizationHandlerContext在一次授权评估期间承载全部状态见 AuthorizationHandlerContext.csRequirements本次授权需满足的全部需求集合User当前ClaimsPrincipalResource可选的资源对象可为 nullPendingRequirements尚未被标记为成功的需求集合其实现是一个HashSetIAuthorizationRequirementHasSucceeded内部逻辑为!_failCalled _succeedCalled !PendingRequirements.Any()即未被 Fail、至少 Succeed 过一次、且无遗留待办需求三者同时成立Succeed(requirement)将需求移出PendingRequirementsFail()/Fail(reason)显式宣告失败可携带AuthorizationFailureReason供失败诊断。AuthorizationPolicy需求的组合单元AuthorizationPolicy将一组Requirements与一组AuthenticationSchemes绑定为一个整体且所有需求必须全部成功授权才算通过见 AuthorizationPolicy.cs 的类注释。构造时若需求列表为空会抛出InvalidOperationException。此外它还提供静态方法Combine(params AuthorizationPolicy[] policies)合并多个策略CombineAsync(IAuthorizationPolicyProvider, IEnumerableIAuthorizeData)按IAuthorizeData如[Authorize]特性解析并合并策略CombineAsync(IAuthorizationPolicyProvider, IEnumerableobject metadata)直接消费端点元数据Endpoint Metadata计算有效策略——AuthorizationMiddleware使用的正是这一重载SignalR、Blazor、MVC 也可以用它得到与中间件一致的结果。AuthorizationPolicyBuilder流畅构建策略策略推荐通过AuthorizationPolicyBuilder构建AuthorizationPolicyBuilder.cs其内置方法包括方法添加的需求类型说明RequireAuthenticatedUser()DenyAnonymousAuthorizationRequirement要求用户已通过认证匿名拒绝RequireRole(params string[] roles)RolesAuthorizationRequirement要求用户至少拥有其中一个角色RequireClaim(claimType, allowedValues?)ClaimsAuthorizationRequirement要求存在指定声明类型可选限定允许值RequireUserName(userName)NameAuthorizationRequirement要求用户名称精确匹配RequireAssertion(FuncAuthorizationHandlerContext, bool \| Taskbool)AssertionRequirement以委托断言自定义条件AddAuthenticationSchemes(params string[] schemes)—限定在哪些认证方案下评估AddRequirements(params IAuthorizationRequirement[] requirements)任意自定义需求追加自定义需求每个方法均返回this支持链式调用最终由Build()生成不可变策略Requirements与AuthenticationSchemes均以只读列表暴露。注意RequireAuthenticatedUser()复用的是静态单例DenyAnonymousAuthorizationRequirement这是刻意设计以减少分配。授权服务IAuthorizationService 与默认实现IAuthorizationService是编程式授权的统一入口IAuthorizationService.cs定义两个核心重载TaskAuthorizationResult AuthorizeAsync(ClaimsPrincipal user, object? resource, IEnumerableIAuthorizationRequirement requirements); TaskAuthorizationResult AuthorizeAsync(ClaimsPrincipal user, object? resource, string policyName);resource参数可选、可传null。围绕该接口AuthorizationServiceExtensions.cs 还提供了若干便捷重载例如AuthorizeAsync(user, policy)、AuthorizeAsync(user, policyName)、AuthorizeAsync(user, resource, requirement)单个需求会被包装为数组。默认实现DefaultAuthorizationService的执行流程DefaultAuthorizationService.cs完整展现了整个评估管道通过IAuthorizationHandlerContextFactory.CreateContext(...)创建评估上下文通过IAuthorizationHandlerProvider.GetHandlersAsync(context)取得全部适用的处理器逐个调用handler.HandleAsync(authContext)若InvokeHandlersAfterFailure为false且上下文已失败则提前break由IAuthorizationEvaluator.Evaluate(authContext)汇总出最终AuthorizationResult通过ILogger记录成功或失败日志对应LoggingExtensions中的UserAuthorizationSucceeded/UserAuthorizationFailed。按策略名授权的重载会先经IAuthorizationPolicyProvider.GetPolicyAsync(policyName)解析策略找不到时抛出InvalidOperationException: No policy found: {policyName}.。配置选项AuthorizationOptions所有策略与默认行为的程序化配置集中在AuthorizationOptionsAuthorizationOptions.cs关键成员如下InvokeHandlersAfterFailure默认true某个处理器调用Fail()后是否仍继续调用其余处理器。置为false可在失败后短路节省评估开销DefaultPolicy默认要求已认证用户即new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build()当[Authorize]存在但未指定策略名时生效FallbackPolicy默认null即不生效仅在完全没有授权元数据无[Authorize]、无RequireAuthorization()时由CombineAsync兜底使用主要用于中间件级全局授权场景AddPolicy(string name, AuthorizationPolicy policy)与AddPolicy(string name, ActionAuthorizationPolicyBuilder configurePolicy)按名称注册命名策略底层以Dictionarystring, TaskAuthorizationPolicy?OrdinalIgnoreCase比较存储GetPolicy(name)/GetPolicyTask(name)按名查找策略。这里有一个容易混淆但重要的语义区分源码注释中特别强调[Authorize]存在时走DefaultPolicy只有完全无授权元数据时才可能落到FallbackPolicy因此默认策略是显式要求授权时的安全基线回退策略是全局兜底。内置需求与处理器的实现细节以ClaimsAuthorizationRequirement为例ClaimsAuthorizationRequirement.cs它同时实现了IAuthorizationHandler与IAuthorizationRequirement是需求自带处理器的典型遍历context.User.Claims声明类型按OrdinalIgnoreCase匹配若指定了AllowedValues声明值须按Ordinal精确命中其中之一命中则调用context.Succeed(requirement)。RolesAuthorizationRequirement、NameAuthorizationRequirement、DenyAnonymousAuthorizationRequirement、AssertionRequirement等均位于 Core/src 下可对照阅读。策略授权管道Policy 子目录的中间件与评估器Policy/src 负责将 Core 的能力接入 HTTP 请求管道。服务注册AddAuthorization 与 AddAuthorizationBuilderPolicyServiceCollectionExtensions.cs 提供三个注册入口AddAuthorizationCore(services)位于 Core 工程见 AuthorizationServiceCollectionExtensions.cs注册IAuthorizationService默认DefaultAuthorizationServiceImpl、IAuthorizationPolicyProvider、IAuthorizationHandlerProvider、IAuthorizationEvaluator、IAuthorizationHandlerContextFactory及内置的PassThroughAuthorizationHandler并顺带AddOptions()与AddMetrics()后者支持授权指标AuthorizationMetrics见 AuthorizationMetrics.csAddAuthorization(...)在 Core 之上追加IPolicyEvaluator默认PolicyEvaluator、IAuthorizationMiddlewareResultHandler默认AuthorizationMiddlewareResultHandler以及策略缓存AuthorizationPolicyCacheAddAuthorizationBuilder()返回AuthorizationBuilder支持更紧凑的链式配置。日常代码中最常见的builder.Services.AddAuthorization(options { ... })即调用第二个入口其中的options回调用于配置上文所述的AuthorizationOptions。中间件接入UseAuthorizationAuthorizationAppBuilderExtensions.UseAuthorization()AuthorizationAppBuilderExtensions.cs向管道注入AuthorizationMiddleware。文档明确指出在使用端点路由时UseAuthorization必须放在UseRouting()与UseEndpoints(...)之间。该方法还会校验AuthorizationPolicyMarkerService是否已注册即必须先调用AddAuthorization否则抛出InvalidOperationException提示缺少服务注册。中间件执行流程AuthorizationMiddleware.InvokeAuthorizationMiddleware.cs是整条管线的核心若当前有端点则在HttpContext.Items打上__AuthorizationMiddlewareWithEndpointInvoked标记供端点路由中间件确认授权已执行尝试从AuthorizationPolicyCache命中已缓存的端点策略仅当策略提供方允许缓存时未命中则调用AuthorizationPolicy.CombineAsync(_policyProvider, endpoint.Metadata)一次性合成端点上的全部授权元数据并写入缓存若无有效策略直接await _next(context)放行通过IPolicyEvaluator.AuthenticateAsync(policy, context)完成认证IPolicyEvaluator为瞬时生命周期服务故从请求级RequestServices解析若端点标记了IAllowAnonymous跳过失败/挑战处理直接放行但仍会先完成认证以填充User调用policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource)执行授权其中resource默认是HttpContext可通过 AppContext 开关Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource改为端点对象最后交给IAuthorizationMiddlewareResultHandler.HandleAsync(...)默认实现AuthorizationMiddlewareResultHandler统一处理成功、Challenge未认证与 Forbid已认证但被拒绝三种结果。该文件注释还特别提醒中间件的授权逻辑变化需同步镜像到 MVC 的AuthorizeFilter以保证 MVC 与端点路由行为一致。测试覆盖test 目录的验证体系test/ 下的测试工程文件 Microsoft.AspNetCore.Authorization.Test.csproj为上述机制提供了可复现的验证样本可按需阅读AuthorizationPolicyFacts.cs策略构建与合并的行为验证DefaultAuthorizationServiceTests.cs授权服务完整评估流程AuthorizationMiddlewareTests.cs/AuthorizationMiddlewareResultHandlerTests.cs中间件及各结果分支成功/Challenge/ForbidPolicyEvaluatorTests.cs策略评估器行为RolesAuthorizationRequirementTests.cs、ClaimsAuthorizationRequirementTests.cs、NameAuthorizationRequirementTests.cs、DenyAnonymousAuthorizationRequirementTests.cs、OperationAuthorizationRequirementTests.cs、AssertionRequirementsTests.cs各内置需求与处理器的单元测试AuthorizationBuilderTests.cs、AuthorizationAppBuilderExtensionsTests.cs、AuthorizationEndpointConventionBuilderExtensionsTests.cs服务注册与管道接入测试MetadataTest.cs端点授权元数据解析。本地构建与测试命令src/Security/Authorization/README.md的 Development Setup 部分给出了两种命令构建整个安全目录含 Authorization在security父目录即src/Security/下执行 ./build.cmd运行测试 ./build.cmd -t更详细的构建代码子集与在命令行运行测试的完整步骤可参见仓库根目录的 docs/BuildFromSource.md其中Building a subset of the code与Running tests on command line两节分别说明了如何只构建指定项目、以及如何在对应目录下执行测试此外也可以在test目录旁直接以dotnet test运行单个工程的测试。构建过程依赖仓库根目录的 global.json 指定的 SDK 版本与 NuGet.config 配置的源建议按 docs/BuildFromSource.md 的前置步骤准备环境。延伸阅读安全组件总览与设计说明src/Security/README.md含ASP.NET Security 不内置 Basic Authentication 中间件等设计取舍说明ASP.NET Core 仓库总览README.md如需深入了解 Authorization 的官方行为约定如默认策略、回退策略语义可结合本文引用的AuthorizationOptions、AuthorizationPolicy.CombineAsync源码与test/下的测试用例交叉印证。本指南聚焦的是 aspnetcore 仓库内授权组件的实现与用法自定义 Handler、动态策略提供方自定义IAuthorizationPolicyProvider等进阶能力均可在 Core/src 与 Policy/src 的公开接口上直接扩展实现。【免费下载链接】aspnetcoreASP.NET Core is a cross-platform .NET framework for building modern cloud-based web applications on Windows, Mac, or Linux.项目地址: https://gitcode.com/GitHub_Trending/as/aspnetcore创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进