• .NET 6 支持Cookie与JWT混合认证、授权的方法


    从.NET 5开始,.Net Core 与.NET Fremework 合并成了 .NET 5,所以标题也很让人尴尬,不知道该写成是.NET Core还是.NET X。因为这个方法支持.NET 5、6、7。

    前言

    不知道大家有没有过这样的需求,为了方便快捷,网站电脑端与移动端API共用一个项目。这样可以节省大量的时间,减少代码的编写和维护量。而网站电脑端使用Cookie提供会员登录,移动端使用JWT提供会员登录。这时,这个网站项目就需要同时支持Cookie和JWT。本文使用的环境是.NET 6。

    Cookie 认证

    先添加Cookie认证。

    var builder = WebApplication.CreateBuilder(args);
    var configuration = builder.Configuration;
    builder.Services.AddControllersWithViews();
    
    builder.Services.AddAuthentication(options =>
    {
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignOutScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    })//Cookie认证
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.Cookie.Name = "ApplicationCookie";
        options.Cookie.HttpOnly = true;
        //如果不指定,将会跳转到.NET 的默认登录页 account/login
        options.LoginPath = new PathString("/Home/Login");
    });
    
    
    var app = builder.Build();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    代码中options.DefaultChallengeSchemeoptions.DefaultAuthenticateSchemeoptions.DefaultSignInSchemeoptions.DefaultSignOutScheme 使用的都是默认值。也可以自定义指定的值。

    接下来添加认证和授权中间件。UseAuthenticationUseAuthorization需要注意的是,需要把他们放在路由和路由端点(路由终结点)之间。

    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}"
            );
    
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    HomeController 上添加认证特性

     [Authorize]
     public class HomeController : Controller
     {
         public IActionResult Index()
         {
             return View();
         }
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    这时,访问Home/Index,如果未认证,就进入我们指定的登录页,如果未指定登录页,进入默认的登录页account/login
    构造一个简单的登录页

    [Authorize]
        public class HomeController : Controller
        {
            public IActionResult Index()
            {
                return View();
            }
            //登录页
            [AllowAnonymous]
            public IActionResult Login()
            {
                return View();
            }
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    注意:这里的登录页加了AllowAnonymous特性,不然是访问不了的。启动程序后,自动跳转到Home/Login页。
    在这里插入图片描述

    点击立即登录,发起登录请求(ajax代码就不写了~)直接贴出登录方法:

    [AllowAnonymous]
            [HttpPost]
            public async Task<IActionResult> UserLogin(string username,string password)
            {
                var claims = new List<Claim>()
                        {
                            new Claim("UserName", username)
                            
                        };
               
                var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
                ClaimsPrincipal principal = new ClaimsPrincipal(identity);
                await HttpContext.SignInAsync(
                    CookieAuthenticationDefaults.AuthenticationScheme,
                    principal,
                    new AuthenticationProperties()
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1),
                        AllowRefresh = true
                    }
                );
                return Ok();
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    先创建一个Listclaims,然后将claims添加到认证方法中。然后在上下文中进行处理,最后进行存储。这里不细讲了。有兴趣的同学可以去了解一下细节。代码将登录过期时间设置成了1天。并且自动刷新登录凭据。也就是AllowRefresh = true ,这个自动刷新登录凭据是用户在登录后超过50%的ExpiresUtc 又一次登录,就自动延长登录时间。假设ExpiresUtc属性设置60分钟后,那么当用户登录后在大于30分钟且小于60分钟内访问了站点,那么就将用户登录状态再延长到当前时间后的60分钟。但是用户在登录后的30分钟内访问站点是不会延长登录时间的。
    当登录后,返回首页,显示登录成功了
    在这里插入图片描述
    获取当前用户的方式是:

    User.Claims.Where(c=>c.Type=="UserName").FirstOrDefault().Value
    
    • 1

    上面已经实现了Cookie认证的全部过程。接下来,在继续集成JWT认证

    JWT认证

    要使用JWT认证,该如何处理呢?首先安装JWT依赖:

    Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
    
    • 1

    然后添加JWT服务。

    //JWT认证
    .AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = false;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ClockSkew = TimeSpan.Zero, //到时间立即过期
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("xxxxxxxxxxxx")), //key
            ValidateIssuer = false,
            ValidateAudience = false
        };
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这里的.AddJwtBearer写到.AddCookie({…})后面的。
    创建一个控制器:APIController,然后在APIController控制器上添加认证特性。

    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
        public class APIController : Controller
        {
            //....
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    需要注意的地方:认证方案指定 为JwtBearerDefaults.AuthenticationScheme。MVC控制器无需指定方案名称,因为默认就是CookieAuthenticationDefaults.AuthenticationScheme。这样程序才能分清楚到底使用什么认证。

    写一个登录方法,使用JWT方式。

    [HttpPost]
    [AllowAnonymous]
    public async Task<string> SubmitLogin(string username, string password)
    {
    var UserId = await GetUserId(username,password);//这里仅做演示。方法需要自行实现
    var claims = new List<Claim>()
                {
                    new Claim("UserId",UserId)
                };
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("xxxxxxxxx"));
    var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
    var expires = DateTime.Now.AddHours(60 * 30);
    var jwtToken = new JwtSecurityToken(
    	string.Empty,
        string.Empty,
        claims,
        expires: expires,
        signingCredentials: credentials
    );
    var token = new JwtSecurityTokenHandler().WriteToken(jwtToken);
    return token;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    前端就可以通过登录方法获取token。在使用token去获取数据就可以了。

    [HttpGet]
    public string Test()
    {
    	 return "get vaue";
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    不用去理会如何进行认证的。后续将token置于请求头中即可验证通过。默认请求头:

    Authorization:'Bearer {token}'
    
    • 1

    总结

    暂无,下次再会!

  • 相关阅读:
    点云处理【三】(点云降采样)
    SuperMap iServer 产品包类型说明
    大家都能看得懂的源码 - ahooks 是怎么处理 DOM 的?
    c#设计模式-结构型模式 之 组合模式
    Scroll View到达底部加载新页
    【附源码】计算机毕业设计JAVA在线图书超市
    Ubuntu网络管理命令:route
    [每周一更]-(第73期):介绍容器监控工具-CAdvisor
    【无标题】
    石油化工行业商业供应链管理系统:标准化供应商管理,优化企业供应链采购流程
  • 原文地址:https://blog.csdn.net/sd2208464/article/details/128049442