首页 > 编程学习 > .NET 6 支持Cookie与JWT混合认证、授权的方法

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

发布时间:2022/11/27 10:47:25

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

目录

  • 前言
  • Cookie 认证
  • JWT认证
  • 总结

前言

不知道大家有没有过这样的需求,为了方便快捷,网站电脑端与移动端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();

代码中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?}"
        );

});

HomeController 上添加认证特性

 [Authorize]
 public class HomeController : Controller
 {
     public IActionResult Index()
     {
         return View();
     }
 }

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

[Authorize]
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }
        //登录页
        [AllowAnonymous]
        public IActionResult Login()
        {
            return View();
        }

    }

注意:这里的登录页加了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();
        }

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

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

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

JWT认证

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

Install-Package Microsoft.AspNetCore.Authentication.JwtBearer

然后添加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
    };
});

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

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public class APIController : Controller
    {
        //....
    }

需要注意的地方:认证方案指定 为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;
}

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

[HttpGet]
public string Test()
{
	 return "get vaue";
}

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

Authorization:'Bearer {token}'

总结

暂无,下次再会!

Copyright © 2010-2022 dgrt.cn 版权所有 |关于我们| 联系方式