本系列将分析ASP.NET Core运行原理

在认证阶段通过用户令牌获取到用户的Claims,而授权就是对这些Claims的验证。

目录

  1. 授权核心

    1. AuthorizationOptions
    2. AuthorizationPolicy
    3. AuthorizationPolicyBuilder
  2. 执行授权
    1. AuthorizeFilter
    2. IPolicyEvaluator
    3. IAuthorizationService
  3. 总结

授权核心

services.AddAuthorization(opt => opt.AddPolicy("isAdmin", builder => builder.RequireUserName("admin")));

通过上面的代码,可以添加一个isAdmin的授权。

对于第一个参数opt:

public class AuthorizationOptions
{
private IDictionary<string, AuthorizationPolicy> PolicyMap { get; } = new Dictionary<string, AuthorizationPolicy>(); public void AddPolicy(string name, AuthorizationPolicy policy)
{
PolicyMap[name] = policy;
} public void AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
{
var policyBuilder = new AuthorizationPolicyBuilder();
configurePolicy(policyBuilder);
AddPolicy(name,policyBuilder.Build());
} public AuthorizationPolicy GetPolicy(string name)
{
return PolicyMap.ContainsKey(name) ? PolicyMap[name] : null;
}
}

实际上,AuthorizationOptions相当于AuthorizationPolicy的集合

AuthorizationPolicy则是一个具体的授权策略对象

public class AuthorizationPolicy
{
public IReadOnlyList<IAuthorizationRequirement> Requirements { get; }
public IReadOnlyList<string> AuthenticationSchemes { get; }
}

AuthorizationPolicyBuilder通过Build方法可以构建一个AuthorizationPolicy,其内部有很多常用的添加IAuthorizationRequirement的方法:

public AuthorizationPolicy Build()
{
return new AuthorizationPolicy(this.Requirements, this.AuthenticationSchemes);
}
public AuthorizationPolicyBuilder RequireUserName(string userName)
{
this.Requirements.Add(new NameAuthorizationRequirement(userName));
} ... Require() ...

IAuthorizationRequirement是授权策略AuthorizationPolicy的一个授权条件,策略下的所有授权条件满足,则授权成功。

public interface IAuthorizationRequirement
{
} public class NameAuthorizationRequirement : IAuthorizationRequirement
{
public string RequiredName { get; }
}

IAuthorizationHandler是授权条件IAuthorizationRequirement的具体处理器,授权条件下的任意1个处理器授权成功,则授权成功。(默认情况下:AuthorizationOptions的InvokeHandlersAfterFailure = true)

public interface IAuthorizationHandler
{
Task HandleAsync(AuthorizationHandlerContext context);
} public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler where TRequirement : IAuthorizationRequirement
{
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (TRequirement requirement in context.Requirements)
await HandleRequirementAsync(context, requirement);
} protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
} public class NameAuthorizationRequirement : AuthorizationHandler<NameAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement)
{
if (context.User?.Identities.Any(identity => identity.Name == requirement.RequiredName))
context.Succeed((IAuthorizationRequirement) requirement);
return Task.CompletedTask;
}
}

授权的最终实现代码在IAuthorizationHandler

执行授权

解释了授权策略的原理,再谈谈授权策略的触发。通常我们在MVC中使用授权功能,而触发授权也是在注册MVC代码中,一并注册了。

public static IMvcBuilder AddMvc(this IServiceCollection services)
{
IMvcCoreBuilder builder = services.AddMvcCore();
builder.AddAuthorization();
} internal static void AddAuthorizationServices(IServiceCollection services)
{
services.AddAuthenticationCore();
services.AddAuthorization();
services.AddAuthorizationPolicyEvaluator();
services.TryAddEnumerable(ServiceDescriptor.Transient<IApplicationModelProvider, AuthorizationApplicationModelProvider>());
}

在MVC中,ApplicationModel用来描述MVC中的模型,而IApplicationModelProvider则是初始化MVC的模型:

public class ApplicationModel
{
public IList<ControllerModel> Controllers { get; } public IList<IFilterMetadata> Filters { get; }
}
public interface IApplicationModelProvider
{
int Order { get; }
void OnProvidersExecuting(ApplicationModelProviderContext context);
void OnProvidersExecuted(ApplicationModelProviderContext context);
}

其中AuthorizationApplicationModelProvider会初始化ApplicationModel的授权部分,注册到Filters属性上(AuthorizeFilter 和 AllowAnonymousFilter)。

public interface IAsyncAuthorizationFilter : IFilterMetadata
{
Task OnAuthorizationAsync(AuthorizationFilterContext context);
} public class AuthorizeFilter : IAsyncAuthorizationFilter
{
public virtual async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var policyEvaluator = GetRequiredService<IPolicyEvaluator>();
var authenticationResult = await policyEvaluator.AuthenticateAsync(effectivePolicy, context.HttpContext);
var authorizationResult = await policyEvaluator.AuthorizeAsync(effectivePolicy, authenticationResult, context.HttpContext, context);
if (authorizationResult.Challenged)
{
context.Result = (IActionResult) new ChallengeResult((IList<string>) effectivePolicy.AuthenticationSchemes.ToArray<string>());
}
else if (authorizationResult.Forbidden)
{
context.Result = (IActionResult) new ForbidResult((IList<string>) effectivePolicy.AuthenticationSchemes.ToArray<string>());
}
}
}

AuthorizeFilter的OnAuthorizationAsync方法会在Action执行前触发,内部调用IPolicyEvaluator执行

public interface IPolicyEvaluator
{
Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context);
Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource);
} public class PolicyEvaluator : IPolicyEvaluator
{
private readonly IAuthorizationService _authorization;
public virtual async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context)
{
}
public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource)
{
var result = await _authorization.AuthorizeAsync(context.User, resource, policy);
if (result.Succeeded) return PolicyAuthorizationResult.Success();
return (authenticationResult.Succeeded) ? PolicyAuthorizationResult.Forbid() : PolicyAuthorizationResult.Challenge();
}
}

在AuthenticateAsync方法中,将合并policy的所有scheme认证结果。

在AuthorizeAsync方法中,将调用IAuthorizationService来实现授权。

public interface IAuthorizationService
{
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);
Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);
} public class DefaultAuthorizationService : IAuthorizationService
{
public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName)
{
var policy = await _policyProvider.GetPolicyAsync(policyName);
return await this.AuthorizeAsync(user, resource, policy);
} public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements)
{
var authContext = _contextFactory.CreateContext(requirements, user, resource);
var handlers = await _handlers.GetHandlersAsync(authContext);
foreach (var handler in handlers)
{
await handler.HandleAsync(authContext);
if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed)
break;
}
return _evaluator.Evaluate(authContext);
}
}

在IAuthorizationService类中,将调用policy的所有Requirement的Handle处理

总结

授权核心:AuthorizationOptionsAuthorizationPolicyAuthorizationPolicyBuilder

AuthorizationOptions 用于保存 AuthorizationPolicy

AuthorizationPolicyBuilder 用于创建 AuthorizationPolicy

AuthorizationPolicy 包含 IAuthorizationRequirement 和 AuthenticationSchemes

IAuthorizationRequirement 包含授权逻辑 IAuthorizationHandler

执行授权:AuthorizeFilterIPolicyEvaluatorIAuthorizationService

AuthorizeFilter的OnAuthorizationAsync方法会在Action执行前触发,内部调用IPolicyEvaluator执行

IPolicyEvaluator 先根据 Schemes 获取Claims,然后调用 IAuthorizationService 的授权方法

IAuthorizationService 调用 Requirement 对应的Handle授权逻辑

个人觉得源码的一个待优化的地方:在DefaultAuthorizationHandlerProviderGetHandlersAsync方法按需返回IAuthorizationHandler更合适。

本文链接:http://www.cnblogs.com/neverc/p/8204339.html

【ASP.NET Core】运行原理(4):授权的更多相关文章

  1. ASP.NET Core 运行原理解剖[5]:Authentication

    在现代应用程序中,认证已不再是简单的将用户凭证保存在浏览器中,而要适应多种场景,如App,WebAPI,第三方登录等等.在 ASP.NET 4.x 时代的Windows认证和Forms认证已无法满足现 ...

  2. ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)

    ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...

  3. ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行

    ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...

  4. ASP.NET Core 运行原理解剖[1]:Hosting

    ASP.NET Core 是新一代的 ASP.NET,第一次出现时代号为 ASP.NET vNext,后来命名为ASP.NET 5,随着它的完善与成熟,最终命名为 ASP.NET Core,表明它不是 ...

  5. ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍

    在上一章中,我们介绍了 ASP.NET Core 的启动过程,主要是对 WebHost 源码的探索.而本文则是对上文的一个补充,更加偏向于实战,详细的介绍一下我们在实际开发中需要对 Hosting 做 ...

  6. ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成

    在 ASP.NET 中,我们知道,它有一个面向切面的请求管道,有19个主要的事件构成,能够让我们进行灵活的扩展.通常是在 web.config 中通过注册 HttpModule 来实现对请求管道事件监 ...

  7. ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界

    HttpContext是ASP.NET中的核心对象,每一个请求都会创建一个对应的HttpContext对象,我们的应用程序便是通过HttpContext对象来获取请求信息,最终生成响应,写回到Http ...

  8. ASP.NET Core 运行原理剖析

    1. ASP.NET Core 运行原理剖析 1.1. 概述 1.2. 文件配置 1.2.1. Starup文件配置 Configure ConfigureServices 1.2.2. appset ...

  9. ASP.NET Core 运行原理剖析 (转载)

    1.1. 概述 在ASP.NET Core之前,ASP.NET Framework应用程序由IIS加载.Web应用程序的入口点由InetMgr.exe创建并调用托管.以初始化过程中触发HttpAppl ...

随机推荐

  1. 原型模式(Prototype)

    原型模式(Prototype) 原型模式虽然是创建型的模式,但是与工程模式没有关系,从名字即可看出,该模式的思想就是将一个对象作为原型,对其进行复制.克隆,产生一个和原对象类似的新对象.本小结会通过对 ...

  2. 关于PHP输出字符串多了两个字节的BUG

    近日IOS开发那边小伙伴跟我说,解析服务器发回的字符信息时候出现bug. 明明利用Log输出来的是字符串"hello"  可是利用length计算就是多出来两个字节,比如这里是7. ...

  3. 【JSOI2008】最大数

    https://www.luogu.org/problem/show?pid=1198 之前刚学完Splay想找题练手的时候做的,写完Splay交上去了才发现这应该是线段树裸题23333 Splay解 ...

  4. SpringCloud Feign对Hystrix(断路由)的支持

    第一步:首先开启Feign对Hystrix的支持,在properties文件中添加以下配置: feign.hystrix.enabled=true. 第二步:在上一篇Feign的基础上添加Hystri ...

  5. 》》QQ-注册

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. ajax xmlhttp 局部显示另一个页面

    function loadXMLDoc(url) { var xmlhttp; if (window.XMLHttpRequest) { // IE7+, Firefox, Chrome, Opera ...

  7. Cocos2d-X使用CCAnimation创建动画

    动画在游戏中是很常见的 程序1:创建一个简单的动画 首先须要在project文件夹下的Resource文件夹中放一张有各种不同动作的图片 在程序中加入以下的代码 #include "Anim ...

  8. 联通假4G欺骗消费者!

    之前预约了联通4G升级,官网说从4月18日開始到5月1月生效.4月18日到5月1日之间10010会联系预约用户更改套餐.24号收到联通业务员打来电话,明白告知:联通4G仅仅是套餐是4G的.网络还是3G ...

  9. Ubuntu Linux訪问小米手机存储卡

    操作系统: 麒麟14.04 安装工具 sudo apt-get install mtpfs libfuse-dev libmad0-dev sudo mkdir /media/mtp 重新启动与使用 ...

  10. Shiro学习之身份验证

    身份验证,即在应用中谁能证明他就是他本人.一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明. 在shiro中,用户需要提供principals (身份)和cre ...