本系列将分析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. 35.Linux-分析并制作环形缓冲区

    在上章34.Linux-printk分析.使用printk调试驱动里讲述了: printk()会将打印信息存在内核的环形缓冲区log_buf[]里, 可以通过dmesg命令来查看log_buf[] 1 ...

  2. XSS攻击原理及防御措施

    概述 XSS攻击是Web攻击中最常见的攻击方法之一,它是通过对网页注入可执行代码且成功地被浏览器 执行,达到攻击的目的,形成了一次有效XSS攻击,一旦攻击成功,它可以获取用户的联系人列 表,然后向联系 ...

  3. swiper3插件无缝滚动配置

    <html> <head> <link rel="stylesheet" href="https://cdn.bootcss.com/Swi ...

  4. MySQL系列:基于binlog的增量订阅与消费(一)

    在一些业务场景中,像在数据分析中我们有时候需要捕获数据变化(CDC):在数据审计中,我们也往往需要知道数据从这个点到另一个点的变化:同样在实时分析中,我们有时候需要看到某个值得实时变化等. 要解决以上 ...

  5. 自己主动化 远程登陆linuxserver并运行命令 —— expect

    原文地址:http://blog.csdn.net/wangyuling1234567890/article/details/41149429 LinuxserverA登陆LinuxserverB s ...

  6. freemarker四种变量

    freemarker四种变量 1.简单介绍说明 (1)数据模型中的变量:root中的变量 (2)模板中的变量:使用<#assign>定义的变量 (3)局部变量:在指令中的变量 (4)循环变 ...

  7. XML解析之SAX

    今天在敲代码的时候,想要实现地址选择功能,就是那个能够选择省.市.县的一个,用到的一个开源框架Android-PickerView,当然他这个里面尽管实现了能够选择的城市列表.可是他这是自己创建的,可 ...

  8. Ration Rose2003安装及破解

    曾经学习UML的时候,用的是EA. 近期在看Head First想着画绘图装一下Ration Rose吧.于是就着手開始装.本来网上关于Ration Rose的安装及破解教程非常多,可是我在安装的过程 ...

  9. Intellij IDEA 使用小结

    快捷键 核心快捷键 IntelliJ IDEA 作为一个以快捷键为中心的 IDE,为大多数操作建议了键盘快捷键.在这个主题中,您可以找到最不可缺少的列表,使 IntelliJ IDEA 轻松实现第一步 ...

  10. 自学Python1.1-简介

    1.python语言介绍 python的创始人:Guido Van Rossum 2.python是一门什么样的语言 2.1  编程语言主要从以下几个角度进行分类:编译型,静态型,动态性,强类型定义语 ...