ASP.NET CORE中使用Cookie身份認證


大家在使用ASP.NET的時候一定都用過FormsAuthentication做登錄用戶的身份認證,FormsAuthentication的核心就是Cookie,ASP.NET會將用戶名存儲在Cookie中。

現在到了ASP.NET CORE的時代,但是ASP.NET CORE中沒有FormsAuthentication這個東西,那么怎么做身份認證呢?答案是ASP.NET CORE已經為我們內置了Cookie身份認證的功能,而且使用起來非常方便,注意本文是基於ASP.NET CORE 2.0版本來闡述Cookie認證方式的。

 

1.從ASP.NET CORE OWIN框架中啟用Cookie身份認證功能


要在ASP.NET CORE中使用Cookie身份認證,第一步就是在項目中的OWIN框架文件Startup.cs中啟用Cookie身份認證中間件。

首先我們在Startup中的ConfigureServices方法中使用services.AddAuthentication注冊Cookie認證服務,如下代碼所示:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();

    //注冊Cookie認證服務
    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
}

然后在Startup中的Configure方法中使用app.UseAuthentication啟用Cookie認證中間件(注意其中app.UseAuthentication和app.UseMvc的調用順序不能反),如下代碼所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseBrowserLink();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    //注意app.UseAuthentication方法一定要放在下面的app.UseMvc方法前面,否者后面就算調用HttpContext.SignInAsync進行用戶登錄后,使用
    //HttpContext.User還是會顯示用戶沒有登錄,並且HttpContext.User.Claims讀取不到登錄用戶的任何信息。
    //這說明Asp.Net OWIN框架中MiddleWare的調用順序會對系統功能產生很大的影響,各個MiddleWare的調用順序一定不能反
    app.UseAuthentication();

    app.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });

            
}

這里順便說一下app.UseAuthentication是用來干什么的,app.UseAuthentication會啟用Authentication中間件,該中間件會根據當前Http請求中的Cookie信息來設置HttpContext.User屬性(后面會用到),
所以只有在app.UseAuthentication方法之后注冊的中間件才能夠從HttpContext.User中讀取到值,這也是為什么上面強調app.UseAuthentication方法一定要放在下面的app.UseMvc方法前面,因為只有這樣
ASP.NET Core的MVC中間件中才能讀取到HttpContext.User的值。

ASP.NET Core 3.0

由於在ASP.NET Core 3.0中,app.UseMvcapp.UseRoutingapp.UseEndpoints替代,所以app.UseAuthenticationapp.UseAuthorization,要放在app.UseRoutingapp.UseCors之后,並且在app.UseEndpoints之前,如下所示:

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}

app.UseStaticFiles();

app.UseRouting();
app.UseCors();

app.UseAuthentication();
app.UseAuthorization();

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

詳情可以查看:Migrate from ASP.NET Core 2.2 to 3.0

 

2.登錄用戶


在ASP.NET CORE中使用Cookie認證登錄用戶的方法和傳統的FormsAuthentication不太一樣,大致步驟如下:

  • 創建Claim類型的數組,將登錄用戶的所有信息(比如用戶名)存儲在Claim類型的字符串鍵值對中
  • 將上面創建的Claim類型的數組傳入ClaimsIdentity中,用來構造一個ClaimsIdentity對象
  • 將上面創建的ClaimsIdentity對象傳入ClaimsPrincipal中,用來構造一個ClaimsPrincipal對象
  • 調用HttpContext.SignInAsync方法,傳入上面創建的ClaimsPrincipal對象,完成用戶登錄

所以我們可以看到整個ASP.NET CORE的Cookie認證登錄流程比以前ASP.NET的FormsAuthentication還是要復雜許多,畢竟以前一個FormsAuthentication.SetAuthCookie方法就搞定了。

 

在本文的例子中我們在項目中默認的HomeController中創建了一個Acion方法Login,來實現用戶登錄的代碼。當然這里我們實現的是最簡的Cookie登錄,下面代碼中實際上還可以設置Cookie是否持久化、Cookie多久過期、存儲登錄用戶信息的Cookie的名字是什么等,我們就不做過多介紹了,大家可以閱讀本文最后推薦的兩份官方文檔了解更多。

Login方法的代碼如下:

/// <summary>
/// 該Action登錄用戶Wangdacui到Asp.Net Core
/// </summary>
public IActionResult Login()
{
//下面的變量claims是Claim類型的數組,Claim是string類型的鍵值對,所以claims數組中可以存儲任意個和用戶有關的信息,
//不過要注意這些信息都是加密后存儲在客戶端瀏覽器cookie中的,所以最好不要存儲太多特別敏感的信息,這里我們只存儲了用戶名到claims數組,
//表示當前登錄的用戶是誰
var claims = new[] { new Claim("UserName", "Wangdacui") };

var claimsIdentity = new ClaimsIdentity(
claims,
CookieAuthenticationDefaults.AuthenticationScheme);

ClaimsPrincipal user = new ClaimsPrincipal(claimsIdentity);

Task.Run(async () =>
{
//登錄用戶,相當於ASP.NET中的FormsAuthentication.SetAuthCookie
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, user);

//可以使用HttpContext.SignInAsync方法的重載來定義持久化cookie存儲用戶認證信息,例如下面的代碼就定義了用戶登錄后60分鍾內cookie都會保留在客戶端計算機硬盤上,
//即便用戶關閉了瀏覽器,60分鍾內再次訪問站點仍然是處於登錄狀態,除非調用Logout方法注銷登錄。
//注意其中的AllowRefresh屬性,如果AllowRefresh為true,表示如果用戶登錄后在超過50%的ExpiresUtc時間間隔內又訪問了站點,就延長用戶的登錄時間(其實就是延長cookie在客戶端計算機硬盤上的保留時間),
//例如本例中我們下面設置了ExpiresUtc屬性為60分鍾后,那么當用戶登錄后在大於30分鍾且小於60分鍾內訪問了站點,那么就將用戶登錄狀態再延長到當前時間后的60分鍾。但是用戶在登錄后的30分鍾內訪問站點是不會延長登錄時間的,
//因為ASP.NET Core有個硬性要求,是用戶在超過50%的ExpiresUtc時間間隔內又訪問了站點,才延長用戶的登錄時間。
//如果AllowRefresh為false,表示用戶登錄后60分鍾內不管有沒有訪問站點,只要60分鍾到了,立馬就處於非登錄狀態(不延長cookie在客戶端計算機硬盤上的保留時間,60分鍾到了客戶端計算機就自動刪除cookie)
/*
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
user, new AuthenticationProperties()
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(60),
AllowRefresh = true
});
*/

}).Wait();

return View();
}

如果當前Http請求本來登錄了用戶A,現在調用HttpContext.SignInAsync方法登錄用戶B,那么相當於注銷用戶A,登錄用戶B

3.讀取登錄用戶信息

那么用戶登錄后怎么將登錄用戶的信息(比如用戶名)讀取出來呢?我們在HomeController的Index方法中演示了如何判斷當前用戶是否已經登錄,並且讀出登錄用戶的用戶名,Index方法的代碼如下所示:

/// <summary>
/// 該Action判斷用戶是否已經登錄,如果已經登錄,那么讀取登錄用戶的用戶名
/// </summary>
public IActionResult Index()
{
//如果HttpContext.User.Identity.IsAuthenticated為true,
//或者HttpContext.User.Claims.Count()大於0表示用戶已經登錄
if (HttpContext.User.Identity.IsAuthenticated)
{
//這里通過 HttpContext.User.Claims 可以將我們在Login這個Action中存儲到cookie中的所有
//claims鍵值對都讀出來,比如我們剛才定義的UserName的值Wangdacui就在這里讀取出來了
var userName = HttpContext.User.Claims.First().Value;
}

return View();
}

 

注意,最好還是用HttpContext.User.Identity.IsAuthenticated來判斷用戶是否已經登錄

 

4.注銷用戶


那么登錄用戶后怎么注銷登錄呢?我們在HomeController的Logout方法中演示了如何注銷登錄的用戶,代碼如下所示:

/// <summary>
/// 該Action從Asp.Net Core中注銷登錄的用戶
/// </summary>
public IActionResult Logout()
{
Task.Run(async () =>
{
//注銷登錄的用戶,相當於ASP.NET中的FormsAuthentication.SignOut
await HttpContext.SignOutAsync();
}).Wait();

return View();
}

如果當前Http請求本來就沒有登錄用戶,那么調用HttpContext.SignOutAsync方法時也不會報錯

 

5.負載均衡


 

警告:
ASP.NET Core使用 ASP.NET Core data protection stack 來實現Cookie身份認證。如果在服務器集群中必須配置 ASP.NET Core Data Protection,有關詳細信息,請參閱 Configuring data protection。如果你的ASP.NET Core站點使用了負載均衡部署了多個實例,就要做ASP.NET Core Data Protection的配置,否則ASP.NET CORE跨多個實例進行Cookie身份認證會失敗。

還可以參考:Host ASP.NET Core in a web farm 以及 Share authentication cookies among ASP.NET apps

如何管理ASP.NET Core Data Protection的過期key,可以查看:Data Protection - how to manage expired key? 

 

 

前面說了實際上在ASP.NET CORE的Cookie認證中還可以設置Cookie的名字、是否持久化存儲等,可以參考如下兩篇官方文檔了解:

Using Cookie Authentication without ASP.NET Core Identity

Cutting Edge - Cookies, Claims and Authentication in ASP.NET Core

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM