主頁 > .NET開發 > 在 ASP.NET Core 應用中使用 Cookie 進行身份認證

在 ASP.NET Core 應用中使用 Cookie 進行身份認證

2021-02-02 06:07:12 .NET開發

Overview

身份認證是網站最基本的功能,最近因為業務部門的一個需求,需要對一個已經存在很久的小工具網站進行改造,因為在逐步的將一些離散的系統遷移至 .NET Core,所以趁這個機會將這個老的 .NET Framework 4.0 的專案進行升級

老的專案是一個 MVC 的專案并且有外網訪問的需求,大部門的微服務平臺因為和內部的業務執行比較密切,介于資安要求與外網進行了隔離,因此本次升級就不會遷移到該平臺上進行前后端分離改造

使用頻次不高,不存在高并發,實作周期短,所以就沒有必要為了用某些組件而用,因此這里還是選擇沿用 MVC 框架,對于網站的身份認證則采用單體應用最常見的 Cookie 認證來實作,本篇文章則是如何實作的一個基礎的教程,僅供參考

Step by Step

在涉及到系統權限管理的相關內容時,必定會提到兩個長的很像的單詞,authentication(認證) 和 authorization(授權)

  • authentication:用一些資料來證明你就是你,登錄系統、指紋、面部解鎖就是一種認證的程序
  • authorization:授予一些用戶去訪問一些特殊資源或功能的程序,系統包含管理員和普通用戶兩種角色,只有管理員才可以執行某些操作,賦予管理員角色某些操作的程序就是授權

只有認證和授權一起配合,才可以完成對于整個系統的權限管控

2.1、前期準備

假定現在已經存在了一個 ASP.NET Core MVC 應用,這里以 VS 創建的默認專案為例,對于一個 MVC or Web API 應用,要求用戶必須登錄之后才能進行訪問,最簡單的方式,在需要認證的 Controller 或 Action 上添加 Authorize 特性,然后在 Startup.Configure 方法中通過 UseAuthorization 添加中間件即可

[Authorize]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }
}
public class Startup
{
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                "default",
                "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

當然,當系統只包含一個兩個 Controller 時還好,當系統比較復雜的時候,再一個個的添加 Authorize 特性就比較麻煩了,因此這里我們可以通過在 Startup.ConfigureServices 中添加全域的 AuthorizeFilter 過濾器,實作對于全域的認證管控

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews()
            .AddMvcOptions(options => { options.Filters.Add(new AuthorizeFilter()); });

    }
}

此時,對于一些不需要進行認證就可以訪問的頁面,只需要添加 AllowAnonymous 特性即可

public class AuthenticationController : Controller
{
    [AllowAnonymous]
    public IActionResult Login()
    {
        return View();
    }
}

2.2、配置認證策略

當然,如果只是這樣修改的話,其實是有問題的,可以看到,當添加上全域過濾器后,系統已經無法正常的進行訪問

啟用授權中間件

對于 authorization(授權) 來說,它其實是在 authentication(認證)通過之后才會進行的操作,也就是說這里我們缺少了對于系統認證的配置,依據報錯資訊的提示,我們首先需要通過使用 AddAuthentication 方法來定義系統的認證策略

認證策略

AddAuthentication 方法位于 Microsoft.AspNetCore.Authentication 類別庫中,通過在 Nuget 中搜索就可以發現,.NET Core 已經基于業界通用的規范實作了多個認證策略

因為這里使用的 Cookie 認證已經包含在默認的專案模板中了,所以就不需要再參考了

添加認證服務

基于 .NET Core 標準的服務使用流程,首先,我們需要在 Startup.ConfigureServices 方法來中通過 AddAuthentication 來定義整個系統所使用的一個授權策略,以及,基于我們采用 Cookie 授權的方式,結合目前互聯網針對跨站點請求偽造 (CSRF) 攻擊的防范要求,我們需要對網站的 Cookie 進行一些設定

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 定義授權策略
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                // 無權訪問的頁路徑
                options.AccessDeniedPath = new PathString("/permission/forbidden");

                // 登錄路徑
                options.LoginPath = new PathString("/authentication/login");

                // 登出路徑
                options.LogoutPath = new PathString("/authentication/logout");

                // Cookie 過期時間(20 分鐘)
                options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
            });

        // 配置 Cookie 策略
        services.Configure<CookiePolicyOptions>(options =>
        {
            // 默認用戶同意非必要的 Cookie
            options.CheckConsentNeeded = context => true;

            // 定義 SameSite 策略,Cookies允許與頂級導航一起發送
            options.MinimumSameSitePolicy = SameSiteMode.Lax;
        });
    }
}

如代碼所示,在定義授權策略時,我們定義了三個重定向的頁面,去告訴 Cookie 授權策略這里對應的頁面在何處,同時,因為身份驗證 Cookie 的默認過期時間會持續到關閉瀏覽器為止,也就是說,只要用戶不點擊退出按鈕并且不關閉瀏覽器,用戶會一直處于已經登錄的狀態,所以這里我們設定 20 分鐘的過期時間,避免一些不必要的風險

至此,對于 Cookie 認證策略的配置就完成了,現在就可以在 Startup.Configure 方法中添加 UseAuthentication 中間件到 HTTP 管道中,實作對于網站認證的啟用,這里需要注意,因為是先認證再授權,所以中間件的添加順序不可以顛倒

public class Startup
{
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();

        // 添加認證授權(順序不可以顛倒)
        //
        app.UseAuthentication();
        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                "default",
                "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

此時,當我們再次訪問系統時,因為沒有經過認證,自動觸發了重定向到系統登錄頁面的操作,而這里重定向跳轉的頁面就是上文代碼中配置的 LoginPath 的屬性值

登錄重定向

2.3、登錄、登出實作

當認證策略配置完成之后,就可以基于選擇的策略來進行登錄功能的實作,這里的登錄頁面上的按鈕,模擬了一個登錄表單提交,當點擊之后會觸發系統的認證邏輯,實作代碼如下所示,這里別忘了將登錄事件的 Action 上加上 AllowAnonymous 特性從而允許匿名訪問

[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LoginAsync()
{
    // 1、Todo:校驗賬戶、密碼是否正確,獲取需要的用戶資訊

    // 2、創建用戶宣告資訊
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.Name, "張三"),
        new Claim(ClaimTypes.MobilePhone, "13912345678")
    };

    // 3、創建宣告身份證
    var claimIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);

    // 4、創建宣告身份證的持有者
    var claimPrincipal = new ClaimsPrincipal(claimIdentity);

    // 5、登錄
    await HttpContext.SignInAsync(claimPrincipal);

    return Redirect("/");
}

在整塊的代碼中,涉及到三個主要的物件,ClaimClaimsIdentityClaimsPrincipal,通過對于這三個物件的使用,從而實作將用戶登錄成功后系統所需的用戶資訊包含在 Cookie 中

三個物件之間的區別,借用理解ASP.NET Core驗證模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不讀的英文博文這篇博客的解釋來說明

  • Claim:被驗證主體特征的一種表述,比如:登錄用戶名是...,email是...,用戶Id是...,其中的“登錄用戶名”,“email”,“用戶Id”就是 ClaimType
  • ClaimsIdentity:一組 claims 構成了一個 identity,具有這些 claims 的 identity 就是 ClaimsIdentity ,駕照就是一種 ClaimsIdentity,可以把 ClaimsIdentity理解為“證件”,駕照是一種證件,護照也是一種證件
  • ClaimsPrincipal:ClaimsIdentity 的持有者就是 ClaimsPrincipal ,一個 ClaimsPrincipal 可以持有多個 ClaimsIdentity,就比如一個人既持有駕照,又持有護照

最后,通過呼叫 HttpContext.SignInAsync 方法就可以完成登錄功能,可以看到,當 Cookie 被清除后,用戶也就處于登出的狀態了,當然,我們也可以通過手動的呼叫 HttpContext.SignOutAsync 來實作登出

登錄實作

2.4、獲取用戶資訊

對于添加在 Claim 中的資訊,我們可以通過指定 ClaimType 的方式獲取到,在 View 和 Controller 中,我們可以直接通過下面的方式進行獲取,這里使用到的 User 其實就是上文中提到的 ClaimsPrincipal

var userName = User.FindFirst(ClaimTypes.Name)?.Value;

User 物件

而當我們需要在一個獨立的類別庫中獲取存盤的用戶資訊時,我們需要進行如下的操作

第一步,在 Startup.ConfigureServices 方法中注入 HttpContextAccessor 服務

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 注入 HttpContext
        services.AddHttpContextAccessor();

    }
}

第二步,在你需要使用的類別庫中通過 Nuget 參考 Microsoft.AspNetCore.Http,之后就可以在具體的類中通過注入 IHttpContextAccessor 來獲取到用戶資訊,當然,也可以在此處實作登錄、登出的方法

namespace Sample.Infrastructure
{
    public interface ICurrentUser
    {
        string UserName { get; }

        Task SignInAsync(ClaimsPrincipal principal);

        Task SignOutAsync();

        Task SignOutAsync(string scheme);
    }

    public class CurrentUser : ICurrentUser
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        private HttpContext HttpContext => _httpContextAccessor.HttpContext;

        public CurrentUser(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));
        }

        public string UserName => HttpContext.User.FindFirst(ClaimTypes.Name)?.Value;

        public Task SignInAsync(ClaimsPrincipal principal) => HttpContext.SignInAsync(principal);

        public Task SignOutAsync() => HttpContext.SignOutAsync();

        public Task SignOutAsync(string scheme) => HttpContext.SignOutAsync(scheme);
    }
}

至此,整塊的認證功能就已經實作了,希望對你有所幫助

Reference

  1. SameSite cookies
  2. Work with SameSite cookies in ASP.NET Core
  3. What does the CookieAuthenticationOptions.LogoutPath property do in ASP.NET Core 2.1?
  4. 理解ASP.NET Core驗證模型(Claim, ClaimsIdentity, ClaimsPrincipal)不得不讀的英文博文
  5. Introduction to Authentication with ASP.NET Core

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

標籤:.NET技术

上一篇:C# 實作語音聊天

下一篇:巧用Dictionary實作日志資料批量插入

標籤雲
其他(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