zoukankan      html  css  js  c++  java
  • 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。

    未完待续......

  • 相关阅读:
    JS学习笔记ZT
    一条经典的汇总的sql
    sql 日期的转换
    微软.net安装失败时出现的问题
    sql 换行
    js 代码
    学习笔记
    decimal 的使用
    功能最完善,代码最简洁的选项卡代码(div+css)
    sql字母排序
  • 原文地址:https://www.cnblogs.com/guodf/p/9707959.html
Copyright © 2011-2022 走看看