AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象



title: "AspNetCore3.1_Secutiry源码解析_2_Authentication_核心流程"
date: 2020-03-18T21:19:15+08:00
draft: false
---

系列文章目录

  • AspNetCore3.1_Secutiry源码解析_1_目录
  • AspNetCore3.1_Secutiry源码解析_2_Authentication_核心项目
  • AspNetCore3.1_Secutiry源码解析_3_Authentication_Cookies
  • AspNetCore3.1_Secutiry源码解析_4_Authentication_JwtBear
  • AspNetCore3.1_Secutiry源码解析_5_Authentication_OAuth
  • AspNetCore3.1_Secutiry源码解析_6_Authentication_OpenIdConnect
  • AspNetCore3.1_Secutiry源码解析_7_Authentication_其他
  • AspNetCore3.1_Secutiry源码解析_8_Authorization_核心项目
  • AspNetCore3.1_Secutiry源码解析_9_Authorization_Policy

依赖注入

框架提供了三个依赖注入重载方法。

//注入认证服务
services.AddAuthentication();

//注入认证服务并制定默认架构名
services.AddAuthentication("Cookies");

//注入认证服务并设置配置项
services.AddAuthentication(config =>
{
});

看看注入代码

public static AuthenticationBuilder AddAuthentication(this IServiceCollection services)
    {
        if (services == null)
        {
            throw new ArgumentNullException(nameof(services));
        }

        services.AddAuthenticationCore();
        services.AddDataProtection();
        services.AddWebEncoders();
        services.TryAddSingleton<ISystemClock, SystemClock>();
        return new AuthenticationBuilder(services);
    }

AddAuthenticationCore注入了认证服务的核心对象。这个方法在Authentication.Core项目,这个项目定义了认证服务的核心对象,在Authentication.Abstractions项目中定义了核心接口。

AddAuthenticationCore方法注入了IAuthenticationService,IClaimsTransformation,IAuthenticationHandlerProvider,IAuthenticationSchemeProvider

public static IServiceCollection AddAuthenticationCore(this IServiceCollection services)
{
    if (services == null)
    {
        throw new ArgumentNullException(nameof(services));
    }

    services.TryAddScoped<IAuthenticationService, AuthenticationService>();
    services.TryAddSingleton<IClaimsTransformation, NoopClaimsTransformation>(); // Can be replaced with scoped ones that use DbContext
    services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();
    services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();
    return services;
}

IAuthenticationService

认证服务,定义了五个方法

  • AuthenticateAsync: 认证
  • ChallengeAsync:挑战,校验认证
  • ForbidAsync:禁止认证
  • SignInAsync:登入
  • SignOutAsync:登出

classDiagram
class IAuthenticationService{
+AuthenticateAsync(HttpContext context, string scheme)
+ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties)
+ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties)
+SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
+SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties)
}

通过AuthenticateAsync方法源代码可以看到,AuthenticateService只是做了控制器的角色,校验schema,根据schema获取handler,主要的认证逻辑是由handler处理。其他的方法基本也是这样的逻辑。

 public virtual async Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme)
{
    if (scheme == null)
    {
        var defaultScheme = await Schemes.GetDefaultAuthenticateSchemeAsync();
        scheme = defaultScheme?.Name;
        if (scheme == null)
        {
            throw new InvalidOperationException($"No authenticationScheme was specified, and there was no DefaultAuthenticateScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).");
        }
    }

    var handler = await Handlers.GetHandlerAsync(context, scheme);
    if (handler == null)
    {
        throw await CreateMissingHandlerException(scheme);
    }

    var result = await handler.AuthenticateAsync();
    if (result != null && result.Succeeded)
    {
        var transformed = await Transform.TransformAsync(result.Principal);
        return AuthenticateResult.Success(new AuthenticationTicket(transformed, result.Properties, result.Ticket.AuthenticationScheme));
    }
    return result;
}

IClaimsTransformation

classDiagram
class IClaimsTransformation{
+TransformAsync(ClaimsPrincipal principal)
}

该接口只有一个方法,用于转换Claims。默认注入的NoopClaimsTransformation,不会做任何操作。如果需要对Claims做一些处理,实现IClaimsTransformation并覆盖注入就可以了。

public class NoopClaimsTransformation : IClaimsTransformation
{
    /// <summary>
    /// Returns the principal unchanged.
    /// </summary>
    /// <param name="principal">The user.</param>
    /// <returns>The principal unchanged.</returns>
    public virtual Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        return Task.FromResult(principal);
    }
}

IAuthenticationHandlerProvider

classDiagram
class IAuthenticationHandlerProvider{
+GetHandlerAsync(HttpContext context, string authenticationScheme)
}

上面提到过handler处理了主要的认证业务逻辑,这个接口可以根据schema获取handler。

IAuthenticationSchemeProvider

classDiagram
class IAuthenticationSchemeProvider{
+GetAllSchemesAsync()
+GetSchemeAsync(string name)
+GetDefaultAuthenticateSchemeAsync()
+GetDefaultChallengeSchemeAsync()
+GetDefaultForbidSchemeAsync()
+GetDefaultSignInSchemeAsync()
+GetDefaultSignOutSchemeAsync()
+AddScheme(AuthenticationScheme scheme)
+RemoveScheme(string name)
+GetRequestHandlerSchemesAsync()
}

该接口主要定义了一些schema的操作方法。

AuthenticationScheme主要有三个属性,通过HandlerType与handler建立了关联。

classDiagram
class AuthenticationScheme{
Name
DisplayName
HandlerType
}

认证流程

graph TD
A(AuthenticationOptions定义五个认证动作的Schema)
A --> B1(Authenticate)
A --> B2(Challenge)
A --> B3(Forbid)
A --> B4(SignIn)
A --> B5(SingOut)
C(IAuthenticationSchemeProvider获取Schema)
B1 --> C
B2 --> C
B3 --> C
B4 --> C
B5 --> C
C --> D(IAuthenticationHandlerProvider获取Schema对应的Handler)
D --> E(处理请求)

其他

除了核心对象,还注入了用于数据保护和解码的辅助对象

services.AddDataProtection();
services.AddWebEncoders();

Authentication中间件

中间件会优先在容器中找IAuthenticationRequestHandler的实现,如果handler不为空的话,则执行handler的HandleRequestAsync方法。IAuthenticationRequestHandler通常在远程认证(如:OAuth, OIDC等)中使用。

如果没有IAuthenticationRequestHandler的实现,则会找默认schema,执行默认schema对应handler的AuthenticationAsync方法,认证成功后,给HttpContext的User对象赋值。

public async Task Invoke(HttpContext context)
    {
        context.Features.Set<IAuthenticationFeature>(new AuthenticationFeature
        {
            OriginalPath = context.Request.Path,
            OriginalPathBase = context.Request.PathBase
        });

        // Give any IAuthenticationRequestHandler schemes a chance to handle the request
        var handlers = context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>();
        foreach (var scheme in await Schemes.GetRequestHandlerSchemesAsync())
        {
            var handler = await handlers.GetHandlerAsync(context, scheme.Name) as IAuthenticationRequestHandler;
            if (handler != null && await handler.HandleRequestAsync())
            {
                return;
            }
        }

        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);
    }


AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象

原文地址:https://www.cnblogs.com/holdengong/p/12521089.html

时间: 2024-11-09 02:18:46

AspNetCore3.1_Secutiry源码解析_2_Authentication_核心对象的相关文章

jQuery源码解析(jQuery对象的实例属性和方法)

1.记录版本号 以及 修正constructor指向 jquery: core_version, constructor: jQuery, 因为jQuery.prototype={ ... } 这种写法将自动生成的jQuery.prototype.constructor属性覆盖删除,所以需要重新修正(指向其构造函数 jQuery).2.init() 初始化方法: init()方法最终返回的是this -jQuery(其实是jQuery.prototype.init)方法的实例对象. 实例对象继承

jQuery 源码解析(七) jQuery对象和DOM对象的互相转换

jQuery对象是一个类数组对象,它保存的是对应的DOM的引用,我们可以直接用[]获取某个索引内的DOM节点,也可以用get方法获取某个索引内的DOM节点,还可以用toArray()方法把jQuery对象一次性转换成一个数组,例如: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title

SPRING源码解析-SPRING 核心-IOC

IoC 和 AOP是Spring的核心, 是Spring系统中其他组件模块和应用开发的基础.透过这两个模块的设计和实现可以了解Spring倡导的对企业应用开发所应秉承的思路: 易用性. POJO开发企业应用, 直接依赖于Java语言,而不是容器和框架. 提升程序的可测试性,提高软件质量. 提供一致性编程模型,面向接口的编程 降低应用的负载和框架的侵入性.IoC和AOP实现. 不作为现有解决方案的替代,而是集成现有. IoC和AOP这两个核心组件,特别是IoC容器,使用户在使用Spring完成PO

Qt元对象系统源码解析

Qt元对象系统源码解析 https://blog.51cto.com/9291927/2070348 一.Qt元对象系统简介 1.元对象系统简介 Qt 的信号槽和属性系统基于在运行时进行内省的能力,所谓内省是指面向对象语言的一种在运行期间查询对象信息的能力, 比如如果语言具有运行期间检查对象型别的能力,那么是型别内省(type intropection)的,型别内省可以用来实施多态.C++的内省比较有限,仅支持型别内省, C++的型别内省是通过运行时类型识别(RTTI)(Run-Time Typ

Android EventBus源码解析, 带你深入理解EventBus

上一篇带大家初步了解了EventBus的使用方式,详见:Android EventBus实战 没听过你就out了,本篇博客将解析EventBus的源码,相信能够让大家深入理解该框架的实现,也能解决很多在使用中的疑问:为什么可以这么做?为什么这么做不好呢? 1.概述 一般使用EventBus的组件类,类似下面这种方式: [java] view plain copy public class SampleComponent extends Fragment { @Override public vo

【转】Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例

概要 这一章,我们对TreeMap进行学习.我们先对TreeMap有个整体认识,然后再学习它的源码,最后再通过实例来学会使用TreeMap.内容包括:第1部分 TreeMap介绍第2部分 TreeMap数据结构第3部分 TreeMap源码解析(基于JDK1.6.0_45)第4部分 TreeMap遍历方式第5部分 TreeMap示例 转载请注明出处:http://www.cnblogs.com/skywang12345/admin/EditPosts.aspx?postid=3310928 第1部

Volley 源码解析(转)

项目:Volley,分析者:grumoon,校对者:Trinea 本文为 Android 开源项目源码解析 中 Volley 部分项目地址:Volley,分析的版本:35ce778,Demo 地址:Volley Demo分析者:grumoon,校对者:huxian99.Trinea,校对状态:完成 1. 功能介绍 1.1. Volley Volley 是 Google 推出的 Android 异步网络请求框架和图片加载框架.在 Google I/O 2013 大会上发布. 名字由来:a burs

给jdk写注释系列之jdk1.6容器(2)-LinkedList源码解析

LinkedList是基于链表结构的一种List,在分析LinkedList源码前有必要对链表结构进行说明. 1.链表的概念 链表是由一系列非连续的节点组成的存储结构,简单分下类的话,链表又分为单向链表和双向链表,而单向/双向链表又可以分为循环链表和非循环链表,下面简单就这四种链表进行图解说明.           1.1.单向链表 单向链表就是通过每个结点的指针指向下一个结点从而链接起来的结构,最后一个节点的next指向null.      1. 2.单向循环链表           单向循环

【转】Java HashMap 源码解析(好文章)

- .fluid-width-video-wrapper { width: 100%; position: relative; padding: 0; } .fluid-width-video-wrapper iframe, .fluid-width-video-wrapper object, .fluid-width-video-wrapper embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } [