Microsoft.AspNetCore.Authentication.Cookies從入門到精通 (一)


Microsoft.AspNetCore.Authentication.Cookies從入門到精通 (一)

Microsoft.AspNetCore.Authentication.Cookies是一個存儲組件,它的主要作用是通過Cookie機制將授權認證的回話信息保存到客戶端中,這與我之前的文章AspNetCore中基於session的身份認證中的HttpSession原理相同,只不過在AspNetCore中基於session的身份認證這篇文章中我們是自己做的一套驗證方案,而篇文章使用的是Asp.Net Core提供的認證方案而已。

開始一個Demo

Demo源碼地址

1.創建一個Razor Page項目:dotnet new razor -n CookieSample

2.打開Startup.cs文件,添加認證代碼

public void ConfigureServices(IServiceCollection services)
{
  	.......
    services.AddAuthentication()
        .AddCookie();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
	......
    app.UseAuthentication();
	......
}

只需要幾行代碼我們就在項目中添加了授權認證功能,下面我們看如何在頁面中使用授權認證

3.打開Index.cshtml.cs文件,添加我們的認證代碼

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public class IndexModel : PageModel
{
	public void OnGet()
}

只需要一行代碼,我的頁面就成了一個需要授權認證后才能訪問的頁面,運行項目訪問該頁面查看效果。

4.添加Login頁面,並在該頁面實現登陸認證

當你打開Index頁面的時候你會發現被重定向了到了/Account/Login,此時我們的項目中還沒有這個頁面,現在我們創建Login頁面並添加一些登陸代碼,這里所謂登陸並不是真正的從數據庫里面驗證用戶信息,當然從數據驗證的過程應該在該操作之前,這里的登陸是將我們希望保存在Cookie中的信息傳遞給Asp.Net Core認證組件,並由該組件將信息序列化到Cookie中,由此可見Microsoft.AspNetCore.Authentication.Cookies只是為了存儲

public class LoginModel : PageModel
{
    public void OnPost()
    {
    	//這里可能需要去數據驗證一些信息
    	......
    	//數據庫驗證通過后,我們需要將部分信息保存到Cookie中
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name,"Tst")
        };
        var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));

    }
}

這就是我們Demo的全部代碼,是不是很簡單。

使我們的Demo更接近真實的項目

案例需求

通常我們的網站會區分前台與后台,普通用戶可以訪問的我們叫前台,管理員可以訪問的我們叫后台。

Demo源碼地址

1. 我們將基於之前的Demo進行改造,現在我們的項目分為兩類用戶而且每類用戶訪問的頁面還不相同。

2. 我們來創建管理員可以訪問的頁面:/Admin/Index,現在我們有了兩個頁面分別供兩類用戶訪問,但是我們只有一個Login頁面那么怎么才能讓兩類用戶公用也一個登陸頁面呢?

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ......
    services.AddAuthentication()
       	.AddCookie()
        .AddCookie("Admin","Admin",options=>{}); 
    ......
}

上面代碼我添加一個了一個Admin認證方案用於管理員訪問並在/Admin/Index頁面中顯式設置認證方案:

/Admin/Index

[Authorize(AuthenticationSchemes = "Admin")]
public class IndexModel : PageModel{}

3. 現在我們來修改Login頁面代碼,我們需要根據認證方案來做不同的認證登錄,目的是為了生成認證的cookie信息

public class LoginModel : PageModel
{
	//保存認證方案以及友好顯示名稱
    [BindProperty]
    public IDictionary<string, string> Schemes { get; set; } = new Dictionary<string, string>();
	
	//認證后我們要跳轉到的頁面
    [BindProperty]
    public string RedirectToUrl { get; set; }

    IAuthenticationSchemeProvider _authenticationSchemeProvider;

    //構造函數注入方式獲取IAuthenticationSchemeprovider實例
    public LoginModel(IAuthenticationSchemeProvider authenticationSchemeProvider)
    {
        //也可以通過從服務中查找的方式獲取IAuthenticationSchemeprovider實例
        //_authenticationSchemeProvider = (IAuthenticationSchemeProvider)HttpContext.RequestServices.GetService(typeof(IAuthenticationSchemeProvider));
        _authenticationSchemeProvider = authenticationSchemeProvider;
    }
    public async Task OnGetAsync(string ReturnUrl)
    {
        RedirectToUrl = ReturnUrl;
        var authenticationSchemes = await _authenticationSchemeProvider.GetAllSchemesAsync();
        foreach (var item in authenticationSchemes)
        {
        	//如果我們沒有設置DisplayName,就是用認證方案名稱替換
            Schemes.Add(item.Name, item.DisplayName??item.Name);
        }
    }

    public IActionResult OnPost(string scheme,string redirectUrl)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.Name,scheme)
        };
        //生成不同認證方案的身份信息
        var claimsIdentity = new ClaimsIdentity(claims, scheme);
        //將認證信息保存到cookie中
        HttpContext.SignInAsync(scheme, new ClaimsPrincipal(claimsIdentity));
        return LocalRedirect(redirectUrl);
    }
}

我們來回顧一下代碼做了什么事:

首先,我們在構造函數中注入了IAuthenticationSchemeProvider的實例,該實例主要用來獲取認所有的證方案。

然后,我們將選擇的認證方案以及認證后要跳轉的地址Post到Login頁面(這里也需要你提交用戶名密碼等從數據驗證),驗證后並將一些信息寫入Cookie中。

插播一點個人的想法:有人可能會想我們分兩個項目不行嗎?我們搞成微服務不行嗎?我的回答是不行:因為這里的一切教程都是圍繞Microsoft.AspNetCore.Authentication.Cookies的功能進行講解,實現認證的方式有很多種,每個人都會有自己的想法和實現,但我們只講Asp.Net Core提供的東西,這樣有利於統一,也有利於減少學習成本,學習成本少了才有時間去創新。

需求更新:為認證添加過期時間

​ 要求普通用戶認證信息在最后一次訪問的10分鍾后過期,而管理員需要在最后一次訪問的1天后過期。

public void ConfigureServices(IServiceCollection services)
{
    ......
    services.AddAuthentication()
        .AddCookie(options=>{
			options.SlidingExpiration = true;
			options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
        })
        .AddCookie("Admin","Admin",options=>{
			options.SlidingExpiration = true;
			options.ExpireTimeSpan = TimeSpan.FromDays(1);
        }); 
    ......
}

我們通過兩個屬性實現了授權過期

SlidingExpiration:通過設置這個參數為Ture可以將過期時間變成滾動(滑動)過期,也就是按最后一次訪問重新計算過期時間,只有設置了滑動Cookie我們的認證信息才更像一個回話狀態。

ExpireTimeSpan:設置過期時間

需求更新:要求使用持久Cookie

在上面的需求中,每當我們關閉瀏覽器,Cookie的狀態就丟失了,這不符合我們的要求,現在我們來修改讓Cookie持久的保存在客戶端。在之前的文章理解cookies中我們介紹了如何讓cookie持久化,原理就是顯式設置ExpiresMaxAge

public void ConfigureServices(IServiceCollection services)
{
    ......
    services.AddAuthentication()
        .AddCookie(options=>{
			options.SlidingExpiration = true;
			options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
            //這里我們將Cookie過期時間設置成了365天,你也可以通過MaxAge屬性來設置,不過這里有點需要注意的是,MaxAge會替代Expiration的值
            options.Cookie.Expiration = TimeSpan.FromDays(365);
            //options.Cookie.MaxAge = TimeSpan.FromDays(365);
        })
        .AddCookie("Admin","Admin",options=>{
			options.SlidingExpiration = true;
			options.ExpireTimeSpan = TimeSpan.FromDays(1);
            options.Cookie.Expiration = TimeSpan.FromDays(365);
        }); 
    ......
}

只需要一行代碼我們就讓Cookie變成了持久化Cookie,但有個問題,我們將普通用戶的認證Cookie設置為10分鍾過期,但卻將Cookie設置為365天(這里的認證Cookie與Cookie是一個東西,認證Cookie的過期是認證服務驗證的,而Cookie本身是瀏覽器驗證的,如果瀏覽器認為Cookie過期則認證服務根本獲取不到Cookie信息),當訪問頁面的間隔大於10分鍾時,Cookie依然會失效,此時雖然Cookie值還在但已經是無意義的一段數據了,所以我們將這三個值options.ExpireTimeSpanoptions.Cookie.Expirationoptions.Cookie.MaxAge設置為相同似乎更合理點。

總結

  1. 我們介紹了如何在項目中使用基於Cookie的授權認證。
  2. 我們介紹了如何配置認證方案以及認證方案的友好提示名稱,並介紹了如何獲取所有的認證方案展示到頁面中。
  3. 我們介紹了如何配置認證的滑動過期時間以及如何配置持久Cookie。

未完待續......


免責聲明!

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



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