一张大图了解ASP.NET Core 3.1 中的Authentication与Authorization

下面是一张ASP.NET Core 3.1 中关于Authentication与Authorization的主流程框线图,点击这里查看全图:https://johnnyqian.net/images/202004/aspnet-core-3.1-request-processing-pipeline.png

重要组件

一些重要的组件及其源码链接如下:

Authentication

ComponentSource Code
AuthenticationMiddlewaresrc/Security/Authentication/Core/src/AuthenticationMiddleware.cs
AuthenticationHandlersrc/Security/Authentication/Core/src/AuthenticationHandler.cs
    JwtBearerHandlersrc/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs
    RemoteAuthenticationHandlersrc/Security/Authentication/Core/src/RemoteAuthenticationHandler.cs
        OAuthHandlersrc/Security/Authentication/OAuth/src/OAuthHandler.cs
            MicrosoftAccountHandlersrc/Security/Authentication/MicrosoftAccount/src/MicrosoftAccountHandler.cs
            GoogleHandlersrc/Security/Authentication/Google/src/GoogleHandler.cs
            FacebookHandlersrc/Security/Authentication/Facebook/src/FacebookHandler.cs
AuthenticationHandlerProvidersrc/Http/Authentication.Core/src/AuthenticationHandlerProvider.cs
AuthenticationServicesrc/Http/Authentication.Core/src/AuthenticationService.cs

Authorization

ComponentSource Code
AuthorizationMiddlewaresrc/Security/Authorization/Policy/src/AuthorizationMiddleware.cs
AuthorizationHandlersrc/Security/Authorization/Core/src/AuthorizationHandler.cs
DefaultAuthorizationHandlerProvidersrc/Security/Authorization/Core/src/DefaultAuthorizationHandlerProvider.cs
DefaultAuthorizationServicesrc/Security/Authorization/Core/src/DefaultAuthorizationService.cs

Middleware与这些Components之间通过一些扩展方法链接起来:

  • src/Http/Authentication.Abstractions/src/AuthenticationHttpContextExtensions.cs
     

  • src/Security/Authentication/Core/src/AuthAppBuilderExtensions.cs

  • src/Security/Authentication/Core/src/AuthenticationServiceCollectionExtensions.cs

  • src/Http/Authentication.Core/src/AuthenticationCoreServiceCollectionExtensions.cs
     

  • src/Security/Authorization/Policy/src/AuthorizationAppBuilderExtensions.cs

  • src/Security/Authorization/Policy/src/PolicyServiceCollectionExtensions.cs

  • src/Security/Authorization/Core/src/AuthorizationServiceCollectionExtensions.cs

几点分析

  • AuthenticationAuthorization相关的组件基本是对称存在的,有几个命名不一致。

  • AuthenticationHandler相关的具体实现有很多,这是因为认证的逻辑是通用的,可以由外部的身份提供者来完成。

  • AuthorizationMiddleware的路径可以看出,ASP.NET Core中的Authorization是基于Policy的。

  • IAuthenticationHandlerProvider中的接口GetHandlerAsync,它是根据authenticationScheme来获取某一个Handler,只要这个Handler认证成功则整个认证流程完成;相对应的IAuthorizationHandlerProvider中的接口GetHandlersAsync则是获取一批Handlers(注意是复数)来共同决定授权的结果。

  • 个人认为有一些Components放置的目录不合理,例如AuthenticationHandlerProviderAuthenticationServiceAuthenticationCoreServiceCollectionExtensions

  • 基于安全的考虑,ASP.NET Core 不再内置支持Basic Authentication,开发者可以自行编写相应的AuthenticationHandler

  • 这两个Middleware都是面向接口开发的,借助于DI,开发者可以改变Pipeline的处理逻辑。

几个问题

  • Authentication的结果存放在哪里?

    Authentication的结果由AuthenticationMiddleware中的如下代码片段确定:

    var defaultAuthenticate = await Schemes.GetDefaultAuthenticateSchemeAsync();
    if (defaultAuthenticate != null)
    {var result = await context.AuthenticateAsync(defaultAuthenticate.Name);if (result?.Principal != null){context.User = result.Principal;}
    }await _next(context);
    

    这段代码先获取默认的认证Scheme,接着调用HttpContext的扩展方法AuthenticateAsync(该方法实际由IAuthenticationService来提供)来获取AuthenticateResult,然后将认证结果中的Principal赋给HttpContextUser属性,最后将请求传递给下一个Middleware(通常是AuthorizationMiddleware)。

    从上面的代码段可以看出,在一个注册了AuthenticationMiddlewareAuthorizationMiddleware的ASP.NET Core项目中,即使Authentication过程失败了(即context.Usernull),AuthorizationMiddleware也是会运行的。

  • 如何判断Authorization的成功与否?

    同样的,Authorization的成功与否是由AuthorizationMiddleware来确定的,相关的代码片段如下:

    var authorizeResult =await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: endpoint);if (authorizeResult.Challenged)
    {if (policy.AuthenticationSchemes.Count > 0){foreach (var scheme in policy.AuthenticationSchemes){await context.ChallengeAsync(scheme);}}else{await context.ChallengeAsync();}return;
    }
    else if (authorizeResult.Forbidden)
    {if (policy.AuthenticationSchemes.Count > 0){foreach (var scheme in policy.AuthenticationSchemes){await context.ForbidAsync(scheme);}}else{await context.ForbidAsync();}return;
    }await _next(context);
    

    这段代码先调用policyEvaluatorAuthorizeAsync方法(该方法会调用IAuthorizationServiceAuthorizeAsync方法)来获取PolicyAuthorizationResult:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    var result = await _authorization.AuthorizeAsync(context.User, resource, policy);
    if (result.Succeeded)
    {return PolicyAuthorizationResult.Success();
    }// If authentication was successful, return forbidden, otherwise challenge
    return (authenticationResult.Succeeded)? PolicyAuthorizationResult.Forbid(): PolicyAuthorizationResult.Challenge();
    

    需要注意的是,在Authorization的流程中是需要借助于Authentication流程的结果以便确定在Authorization失败后是否返回Challenge(401)还是Forbid(403)。

    然后这段代码根据PolicyAuthorizationResult来调用HttpContext的扩展方法ChallengeAsyncForbidAsync,并终止整个请求处理流程;或者将请求传递给下一个Middleware(通常是EndpointRoutingMiddleware,也即是我们常说的MVC Middleware)。HttpContext的扩展方法ChallengeAsyncForbidAsync是由IAuthenticationService来提供的。

    我们再深入到DefaultAuthorizationService中来了解下多个AuthorizationHandler是如何一起工作的:

    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;}
    }var result = _evaluator.Evaluate(authContext);
    

    从上述代码可以看到,在InvokeHandlersAfterFailuretrue的情况下(默认为true),所有注册了的AuthorizationHandler都会被执行。接着,代码调用IAuthorizationEvaluator中的Evaluate方法对整个授权流程进行评估,本质上是检查AuthorizationHandlerContext中的HasSucceeded属性,其代码如下:

    /// <summary>
    /// Flag indicating whether the current authorization processing has succeeded.
    /// </summary>
    public virtual bool HasSucceeded
    {get{return !_failCalled && _succeedCalled && !PendingRequirements.Any();}
    }
    

    可以看到,授权成功的条件是:

    基本原则是,AuthorizationHandler一般不需要显式调用context.Fail,除非开发者认为某一个requirement必须被当前的AuthorizationHandler满足。针对同一个requirement,其它的AuthorizationHandler可能会依据某些条件认为该requirement是满足的。

    这里有个问题是,如果某一个AuthorizationHandler显式调用了context.Fail,那么整个授权流程的结果就是失败的。那么此时为什么还要继续执行其它的AuthorizationHandlerInvokeHandlersAfterFailure默认为true),而不是快速失败(fail-fast)?官方文档给出的解释如下:
    If a handler calls context.Succeed or context.Fail, all other handlers are still called. This allows requirements to produce side effects, such as logging, which takes place even if another handler has successfully validated or failed a requirement. When set to false, the InvokeHandlersAfterFailure property (available in ASP.NET Core 1.1 and later) short-circuits the execution of handlers when context.Fail is called. InvokeHandlersAfterFailure defaults to true, in which case all handlers are called.

  1. 没有任何一个AuthorizationHandler显式调用了context.Fail

  2. 至少有一个AuthorizationHandler显式调用了context.Succeed

  3. PendingRequirements这个集合为空,也即是所有的requirements都被满足了

  • [AllowAnonymous]属性是如何工作的?

    [AllowAnonymous]属性可以绕开(bypass)整个授权流程,即使相应的Controller或者Action上有[Authorize]属性。这也是由AuthorizationMiddleware中的一段代码来实现的:

    // Allow Anonymous skips all authorization
    if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null)
    {await _next(context);return;
    }
    
  • 参考文章

    • ASP.NET Core Middleware

    • ASP.NET Core authentication

    • ASP.NET Core authorization

    • Policy-based authorization in ASP.NET Core

    • ASP.NET Core - Middleware

    • ASP.NET Core in Action - What is middleware?

    • ASP.NET Core middleware and authorization

    • ASP.NET Core 中的那些认证中间件及一些重要知识点

    • ASP.NET Core 中的管道机制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/310681.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++ class实现完全二叉树的顺序存储结构

代码如下: #include <iostream> using namespace std; const int maxsize 100; typedef char ElemType;class QbTree {public:void CreateBTree(int n);int vislchild(int i);int visrchild(int i);int visparent(int i);ElemType viselem(int i);void LevelOrder();p…

研发协同平台持续集成Jenkins作业设计演进

源宝导读&#xff1a;Jenkins作为一个开源的持续集成工具&#xff0c;被大家广泛使用。本文将分享&#xff0c;Jenkins在明源云研发协同平台中的运用&#xff0c;以及在其作业设计方面的演进历程。一、作业设计1.0起初&#xff0c;为了尽快推出研发协同平台v1.0&#xff0c;我们…

一切都要从华为云 CloudIDE 酷似 VS Code 说起

前不久&#xff0c;有个关于华为云 CloudIDE 的问题在知乎、朋友圈、微博等圈子引起了广泛的讨论&#xff0c;甚至上了知乎热榜。那么&#xff0c;背后的真实情况到底是如何的&#xff1f;且听韩老师娓娓道来。华为云 CloudIDE 酷似 VS Code&#xff1f;首先要明确一点&#xf…

C++ class实现双亲表示法

#include <iostream> using namespace std; typedef char ElemType; const int MAXSIZE 100;class TreeNode {friend class Tree; private:ElemType data;int parent; };class Tree { private:TreeNode elem[MAXSIZE];int n;//树中当前的节点个数 }Tree;

单元测试:如何编写可测试的代码及其重要性

原文来自互联网&#xff0c;由长沙DotNET技术社区编译。如译文侵犯您的署名权或版权&#xff0c;请联系小编&#xff0c;小编将在24小时内删除。限于译者的能力有限&#xff0c;个别语句翻译略显生硬&#xff0c;还请见谅。作者&#xff1a;谢尔盖科洛迪&#xff08;SERGEY KOL…

C++ class实现孩子表示法

代码如下: #include <iostream> using namespace std; typedef char ElemType; const int MAXSIZE 100;class link {friend class Node; private:int child;link *next; };class Node {friend class Tree; private:ElemType data;link *first; };class Tree { private:…

IdentityServer 部署踩坑记

IdentityServer 部署踩坑记Intro周末终于部署了 IdentityServer 以及 IdentityServerAdmin 项目&#xff0c;踩了几个坑&#xff0c;在此记录分享一下。部署架构项目是基于 IdentityServerAdmin 项目修改的&#xff0c;感谢作者的开源付出&#xff0c;有需要 IdentityServer 管…

.Net Core微服务架构技术栈的那些事

一、前言大家一直都在谈论微服务架构&#xff0c;园子里面也有很多关于微服务的文章&#xff0c;前几天也有一些园子的朋友问我微服务架构的一些技术&#xff0c;我这里就整理了微服务架构的技术栈路线图&#xff0c;这里就分享出来和大家一起探讨学习&#xff0c;同时让新手对…

C++ class实现Huffman树(完整代码)

代码如下: #include <iostream> #include <string> using namespace std; const unsigned int n 8;//字符数NUM&#xff0c;这里的字符数为8 const unsigned int m 2 * n - 1;//结点总数 const float MAX 1e8;class HTNode {friend class HuffmanTree; private…

二叉树的遍历(堆栈)

二叉树的遍历&#xff08;堆栈&#xff09; 如何理解用堆栈方式代替递归去遍历二叉树&#xff0c;关键点在于了解每个结点输出时的顺序&#xff0c;以及理解前序中序后序是如何遍历的&#xff0c;这点很重要&#xff0c;可以自己画一个树图&#xff0c;熟练写出遍历的结果 以…

ASP.NET Core分布式项目实战(第三方ClientCredential模式调用)--学习笔记

任务10&#xff1a;第三方ClientCredential模式调用创建一个控制台程序dotnet new console --name ThirdPartyDemo添加 Nuget 包&#xff1a;IdentityModel添加之后还原dotnet restoreClientusing System; using System.Net.Http; using System.Threading.Tasks; using Identit…

C++ class实现邻接矩阵存储的图(完整代码)

代码如下: #include <iostream> #include <queue> using namespace std; typedef int VertexType; typedef int EdgeType; const int MaxVertexNum 30;class MGraph { public:MGraph(){CreatGraph();};void CreatGraph();void Visit(int v);void BFS(int v);void…

二叉搜索树(创建,插入,删除):基础篇,适合新手观看。

1.1 二叉搜索树的插入 二叉搜索树的概念相信大家都很清楚&#xff0c;无非就是左小右大 创建二叉搜索树&#xff0c;其实就是多次调用二叉搜索树的插入方法&#xff0c;所以首先我们来讲讲如何插入节点到二叉搜索树里&#xff0c;假设一颗二叉搜索树如下&#xff0c;现在要插入…

.NET 的过去、现在和未来

作为一名使用了十多年.NET 开发平台的开发者来说&#xff0c;多年来笔者鲜少在各类博客媒体推广布道 .NET平台&#xff0c;但也默默地关注着 .NET 平台的发展变化&#xff0c;为每一次新技术的出现欢呼&#xff0c;为近年来 .NET 的沉默感到惋惜&#xff0c;也为开放开源的 .NE…

AVL树(平衡二叉树)讲解,入门篇,适合新手观看

1.1 概念 平衡二叉树就是为了让二叉搜索树的平均查找长度更短&#xff0c;时间复杂度更靠近logN,如果一个二叉搜索树不平衡了就会出现图1情况&#xff0c;完全变成一个数组&#xff0c;时间复杂度也变为了O(N)。 平衡因子&#xff1a;平衡因子就是针对于树中某一结点&#xff…

读源码,对开发者重要吗?

.NET 5.0 Peview 2发布4月2日&#xff0c;微软发布了.NET 5.0 Preview 2&#xff0c;带来功能和性能方面的改进。这一版本包括.NET 5.0.0 Preview 2与.NET SDK 5.0.100 Preview 2。.NET 5是.NET Framework和.NET Core的未来&#xff0c;最终将成为一个统一平台&#xff0c;.NET…

Redis和DB数据一致性解决方案

问题出现原因 并发时候无法保证读写的先后顺序&#xff0c;如果删掉了缓存还没来得及写库&#xff0c;另外一个县城就多来读取&#xff0c;发现缓存为空就去读取数据库并且写入缓存&#xff0c;这时候缓存中就是脏数据如果先写库&#xff0c;在删除缓存前&#xff0c;写库的线…

数据结构堆的时间复杂度(最大堆,最小堆)

创建堆的方式有两种&#xff0c;一种是一边插入结点&#xff0c;一边调用堆的插入方法调整堆&#xff0c;这样的时间复杂度就是 O(NlogN)&#xff0c;而第二种方式就把时间复杂度缩减到了O(N)&#xff0c;它是采用先把结点插入好了&#xff0c;然后再来调整堆&#xff0c;并不是…

中国速度之二神山建设(3):有力的技术保障,基建世界里的云原生缩影 | IDCF DevOps案例研究...

内容来源&#xff1a;DevOps案例深度研究第4期 – 火神山雷神山 DevOps实践研究战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;全程视频请移步文末&#xff09;本案例内容贡献者&#xff1a;赖泽薇、张扬、邓茜芸、韦一、刘德权、候利涛、冯利娟、常相宇、张力、韩丰…

Rx2.0后台开发分享

Rxjava2.x 微软的一个函数库&#xff0c;Rx是一个编程模型&#xff0c;模板是提供一致的编程接口&#xff0c;帮助开发者更方便的处理异步数据流&#xff0c;现在Rx已经支持几乎全部的流行编程语言。比较流行的有Rxjava&#xff0c;RxJs&#xff0c;Rx.NET&#xff0c;社区网站…