主頁 > .NET開發 > AspNetCore3.1_Secutiry原始碼決議_3_Authentication_Cookies

AspNetCore3.1_Secutiry原始碼決議_3_Authentication_Cookies

2020-09-16 07:07:32 .NET開發

文章目錄

  • 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_授權框架

依賴注入

AuthenticationBuilder AddCookie(this AuthenticationBuilder builder);

AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, string authenticationScheme);

AuthenticationBuilder AddCookie(this AuthenticationBuilder builder, Action<CookieAuthenticationOptions> configureOptions);

提供了幾個多載方法,可以使用默認配置,或者通過委托修改配置類CookieAuthenticationOptions的值,

可以定義登錄、登出、拒絕登錄頁面地址、Cookie過期時間、生命周期各階段事件等,

classDiagram class CookieAuthenticationOptions{ CookieBuilder Cookie IDataProtectionProvider DataProtectionProvider bool SlidingExpiration PathString LoginPath PathString LogoutPath PathString AccessDeniedPath CookieAuthenticationEvents Events ISecureDataFormat TicketDataFormat ITicketStore SessionStore TimeSpan ExpireTimeSpan } class AuthenticationSchemeOptions{ string ClaimsIssuer object Events Type EventsType string ForwardDefault string ForwardAuthenticate string ForwardChallenge string ForwardForbid string ForwardSignIn string ForwardSignOut Func ForwardDefaultSelector } CookieAuthenticationOptions-->AuthenticationSchemeOptions

如果沒有定義配置,則會使用CookieAuthenticationDefaults定義的默認配置

 /// <summary>
    /// Default values related to cookie-based authentication handler
    /// </summary>
    public static class CookieAuthenticationDefaults
    {
        /// <summary>
        /// The default value used for CookieAuthenticationOptions.AuthenticationScheme
        /// </summary>
        public const string AuthenticationScheme = "Cookies";

        /// <summary>
        /// The prefix used to provide a default CookieAuthenticationOptions.CookieName
        /// </summary>
        public static readonly string CookiePrefix = ".AspNetCore.";

        /// <summary>
        /// The default value used by CookieAuthenticationMiddleware for the
        /// CookieAuthenticationOptions.LoginPath
        /// </summary>
        public static readonly PathString LoginPath = new PathString("/Account/Login");

        /// <summary>
        /// The default value used by CookieAuthenticationMiddleware for the
        /// CookieAuthenticationOptions.LogoutPath
        /// </summary>
        public static readonly PathString LogoutPath = new PathString("/Account/Logout");

        /// <summary>
        /// The default value used by CookieAuthenticationMiddleware for the
        /// CookieAuthenticationOptions.AccessDeniedPath
        /// </summary>
        public static readonly PathString AccessDeniedPath = new PathString("/Account/AccessDenied");

        /// <summary>
        /// The default value of the CookieAuthenticationOptions.ReturnUrlParameter
        /// </summary>
        public static readonly string ReturnUrlParameter = "ReturnUrl";
    }

注冊當前schema的處理器類為CookieAuthenticationHandler

處理器類的結構

主干邏輯是層層繼承來實作的,CookieAuthenticationHandler主要是重寫了父類的五個認證動作的Handle方法來實作自己的處理邏輯,

classDiagram class CookieAuthenticationHandler{ HandleAuthenticateAsync() HandleSignInAsync() HandleSignOutAsync() HandleForbiddenAsync() HandleChallengeAsync() FinishResponseAsync() } class SignInAuthenticationHandler{ SignInAsync() HandleSignInAsync() } class IAuthenticationSignInHandler{ SignIn() HandleSignIn() } class SignOutAuthenticationHandler{ SignOutAsync() HandleSignOutAsync() } class IAuthenticationSignOutHandler{ SighOut() HandleSignOut() } class AuthenticationHandler{ AuthenticationScheme Scheme TOptions Options HttpContext Context HttpRequest Request HttpResponse Response PathString OriginalPath PathString OriginalPathBase ILogger Logger UrlEncoder UrlEncoder ISystemClock Clock object Events string ClaimsIssuer string CurrentUri +Task InitializeAsync(AuthenticationScheme scheme, HttpContext context) +Task AuthenticateAsync() +Task ChallengeAsync(AuthenticationProperties properties) +Task ForbidAsync(AuthenticationProperties properties) } class IAuthenticationHandler{ HandleAsync() } CookieAuthenticationHandler-->SignInAuthenticationHandler SignInAuthenticationHandler-->IAuthenticationSignInHandler SignInAuthenticationHandler-->SignOutAuthenticationHandler SignOutAuthenticationHandler-->IAuthenticationSignOutHandler SignOutAuthenticationHandler-->AuthenticationHandler AuthenticationHandler-->IAuthenticationHandler

處理器類詳解

HandleSignInAsync - 處理登錄

  1. 業務方校驗完用戶之后之后,構造ClaimsPrincipal物件傳入SignIn方法,如果user為null則拋出例外
  2. IssuedUtc如果未指定的話則使用當前時間,ExpiresUtc過期時間如果沒有指定的話則用IssuedUtc和ExpireTimeSpan計算出過期時間
  3. 觸發SigningIn事件
  4. 構造AuthenticationTicket憑證
  5. 如果SessionStore不為空,將憑證資訊存入SessionStore
  6. TicketDataFormat對ticket進行加密
  7. CookieManager將t加密后的資訊寫入cookie
  8. 觸發SignedIn事件
  9. 如果LoginPath有值并且等于OriginalPath,則需要跳轉,跳轉地址在Properties.RedirectUri
protected async override Task HandleSignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
    {
        if (user == null)
        {
            throw new ArgumentNullException(nameof(user));
        }

        properties = properties ?? new AuthenticationProperties();

        _signInCalled = true;

        // Process the request cookie to initialize members like _sessionKey.
        await EnsureCookieTicket();
        var cookieOptions = BuildCookieOptions();

        var signInContext = new CookieSigningInContext(
            Context,
            Scheme,
            Options,
            user,
            properties,
            cookieOptions);

        DateTimeOffset issuedUtc;
        if (signInContext.Properties.IssuedUtc.HasValue)
        {
            issuedUtc = signInContext.Properties.IssuedUtc.Value;
        }
        else
        {
            issuedUtc = Clock.UtcNow;
            signInContext.Properties.IssuedUtc = issuedUtc;
        }

        if (!signInContext.Properties.ExpiresUtc.HasValue)
        {
            signInContext.Properties.ExpiresUtc = issuedUtc.Add(Options.ExpireTimeSpan);
        }

        await Events.SigningIn(signInContext);

        if (signInContext.Properties.IsPersistent)
        {
            var expiresUtc = signInContext.Properties.ExpiresUtc ?? issuedUtc.Add(Options.ExpireTimeSpan);
            signInContext.CookieOptions.Expires = expiresUtc.ToUniversalTime();
        }

        var ticket = new AuthenticationTicket(signInContext.Principal, signInContext.Properties, signInContext.Scheme.Name);

        if (Options.SessionStore != null)
        {
            if (_sessionKey != null)
            {
                await Options.SessionStore.RemoveAsync(_sessionKey);
            }
            _sessionKey = await Options.SessionStore.StoreAsync(ticket);
            var principal = new ClaimsPrincipal(
                new ClaimsIdentity(
                    new[] { new Claim(SessionIdClaim, _sessionKey, ClaimValueTypes.String, Options.ClaimsIssuer) },
                    Options.ClaimsIssuer));
            ticket = new AuthenticationTicket(principal, null, Scheme.Name);
        }

        var cookieValue = https://www.cnblogs.com/holdengong/p/Options.TicketDataFormat.Protect(ticket, GetTlsTokenBinding());

        Options.CookieManager.AppendResponseCookie(
            Context,
            Options.Cookie.Name,
            cookieValue,
            signInContext.CookieOptions);

        var signedInContext = new CookieSignedInContext(
            Context,
            Scheme,
            signInContext.Principal,
            signInContext.Properties,
            Options);

        await Events.SignedIn(signedInContext);

        // Only redirect on the login path
        var shouldRedirect = Options.LoginPath.HasValue && OriginalPath == Options.LoginPath;
        await ApplyHeaders(shouldRedirect, signedInContext.Properties);

        Logger.AuthenticationSchemeSignedIn(Scheme.Name);
    }

HandleAuthentication - 處理認證

  1. 從Cookie中讀取憑證:首先TicketDataFormat類將Cookie解碼,如果SessionStore不為null,說明解碼值是只是session的key,從SessionStore中取出值,
  2. 構建CookieValidatePrincipalContext,觸發ValidatePrincipal事件
  3. 如果ShouldRenew位true,則會重繪cookie(ShoudRenew默認為false,可以通過訂閱ValidatePrincipal事件來修改)
  4. 認證成功,發放憑證AuthenticationTicket,包括context.Principal, context.Properties, Scheme.Name這些資訊
 protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
    var result = await EnsureCookieTicket();
    if (!result.Succeeded)
    {
        return result;
    }

    var context = new CookieValidatePrincipalContext(Context, Scheme, Options, result.Ticket);
    await Events.ValidatePrincipal(context);

    if (context.Principal == null)
    {
        return AuthenticateResult.Fail("No principal.");
    }

    if (context.ShouldRenew)
    {
        RequestRefresh(result.Ticket, context.Principal);
    }

    return AuthenticateResult.Success(new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name));
}

HandleSignOutAsync - 處理登出

  1. 獲取憑證
  2. SessionStore不為null的話則從SessionStore移除會話
  3. 觸發SigningOut事件
  4. CookieManager洗掉cookie
  5. 如果源地址是LogoutPath,則跳轉到登出后地址
protected async override Task HandleSignOutAsync(AuthenticationProperties properties)
    {
        properties = properties ?? new AuthenticationProperties();

        _signOutCalled = true;

        // Process the request cookie to initialize members like _sessionKey.
        await EnsureCookieTicket();
        var cookieOptions = BuildCookieOptions();
        if (Options.SessionStore != null && _sessionKey != null)
        {
            await Options.SessionStore.RemoveAsync(_sessionKey);
        }

        var context = new CookieSigningOutContext(
            Context,
            Scheme,
            Options,
            properties,
            cookieOptions);

        await Events.SigningOut(context);

        Options.CookieManager.DeleteCookie(
            Context,
            Options.Cookie.Name,
            context.CookieOptions);

        // Only redirect on the logout path
        var shouldRedirect = Options.LogoutPath.HasValue && OriginalPath == Options.LogoutPath;
        await ApplyHeaders(shouldRedirect, context.Properties);

        Logger.AuthenticationSchemeSignedOut(Scheme.Name);
    }

HandleForbidAsync -- 處理禁止訪問

如果是ajax請求會回傳403狀態碼,否則跳轉到配置的AccessDeniedPath

 protected override async Task HandleForbiddenAsync(AuthenticationProperties properties)
{
    var returnUrl = properties.RedirectUri;
    if (string.IsNullOrEmpty(returnUrl))
    {
        returnUrl = OriginalPathBase + OriginalPath + Request.QueryString;
    }
    var accessDeniedUri = Options.AccessDeniedPath + QueryString.Create(Options.ReturnUrlParameter, returnUrl);
    var redirectContext = new RedirectContext<CookieAuthenticationOptions>(Context, Scheme, Options, properties, BuildRedirectUri(accessDeniedUri));
    await Events.RedirectToAccessDenied(redirectContext);
}

public Func<RedirectContext<CookieAuthenticationOptions>, Task> OnRedirectToAccessDenied { get; set; } = context =>
    {
        if (IsAjaxRequest(context.Request))
        {
            context.Response.Headers[HeaderNames.Location] = context.RedirectUri;
            context.Response.StatusCode = 403;
        }
        else
        {
            context.Response.Redirect(context.RedirectUri);
        }
        return Task.CompletedTask;
    };

其他

ICookieManager - Cookie管理類

默認實作是ChunkingCookieManager,如果cookie過長,該類會將cookie拆分位多個chunk,

 /// <summary>
/// This is used by the CookieAuthenticationMiddleware to process request and response cookies.
/// It is abstracted from the normal cookie APIs to allow for complex operations like chunking.
/// </summary>
public interface ICookieManager
{
    /// <summary>
    /// Retrieve a cookie of the given name from the request.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="key"></param>
    /// <returns></returns>
    string GetRequestCookie(HttpContext context, string key);

    /// <summary>
    /// Append the given cookie to the response.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="key"></param>
    /// <param name="value"></param>
    /// <param name="options"></param>
    void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options);

    /// <summary>
    /// Append a delete cookie to the response.
    /// </summary>
    /// <param name="context"></param>
    /// <param name="key"></param>
    /// <param name="options"></param>
    void DeleteCookie(HttpContext context, string key, CookieOptions options);
}

ITicketStore - 實作Cookie持久化

ITicketStore默認是沒有實作的,如果實作該介面并注入的話,可以將cookie持久化,這樣暴露在瀏覽器的只是一個cookie的id,

/// <summary>
/// This provides an abstract storage mechanic to preserve identity information on the server
/// while only sending a simple identifier key to the client. This is most commonly used to mitigate
/// issues with serializing large identities into cookies.
/// </summary>
public interface ITicketStore
{
    /// <summary>
    /// Store the identity ticket and return the associated key.
    /// </summary>
    /// <param name="ticket">The identity information to store.</param>
    /// <returns>The key that can be used to retrieve the identity later.</returns>
    Task<string> StoreAsync(AuthenticationTicket ticket);

    /// <summary>
    /// Tells the store that the given identity should be updated.
    /// </summary>
    /// <param name="key"></param>
    /// <param name="ticket"></param>
    /// <returns></returns>
    Task RenewAsync(string key, AuthenticationTicket ticket);

    /// <summary>
    /// Retrieves an identity from the store for the given key.
    /// </summary>
    /// <param name="key">The key associated with the identity.</param>
    /// <returns>The identity associated with the given key, or if not found.</returns>
    Task<AuthenticationTicket> RetrieveAsync(string key);

    /// <summary>
    /// Remove the identity associated with the given key.
    /// </summary>
    /// <param name="key">The key associated with the identity.</param>
    /// <returns></returns>
    Task RemoveAsync(string key);
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/54802.html

標籤:.NET Core

上一篇:使用Github Packages功能上傳nuget包到Github

下一篇:.netcore2.1 統一介面回傳屬性名稱

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more