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

目录
  • 前言
  • Cookie认证
  • JWT认证
  • 滑动过期思考扩展
  • 总结

前言

为防止JWT Token被窃取,我们将Token置于Cookie中,但若与第三方对接,调用我方接口进行认证、授权此时仍需将Token置于请求头,通过实践并联系理论,我们继续开始整活!首先我们实现Cookie认证,然后再次引入JWT,最后在结合二者使用时联系其他我们可能需要注意的事项

Cookie认证

在startup中我们添加cookie认证服务,如下:

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
    options.ExpireTimeSpan = TimeSpan.FromMinutes(1);
    options.Cookie.Name = "user-session";
    options.SlidingExpiration = true;
});

接下来则是使用认证和授权中间件,注意将其置于路由和终结点终结点之间,否则启动也会有明确异常提示

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
  ......
});

我们给出测试视图页,并要求认证即控制器添加特性

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

当进入首页,未认证默认进入account/login,那么接下来创建该视图

public class AccountController : Controller
{
    [AllowAnonymous]
    public IActionResult Login()
    {
      return View();
    }
    ......
}

我们启动程序先看看效果

如上图,自动跳转至登录页,此时我们点击模拟登录按钮,发起请求去模拟登录(发起ajax请求代码就占不用篇幅给出了)

/// <summary>
/// 模拟登录
/// </summary>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> TestLogin()
{
    var claims = new Claim[]
    {
      new Claim(ClaimTypes.Name, "Jeffcky"),
    };
    var claimsIdentity = new ClaimsIdentity(claims, "Login");
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
    return Ok();
}

上述无非就是构建身份以及该身份下所具有的身份属性,类似个人身份证唯一标识个人,身份证上各个信息即表示如上声明,同时呢,肯定要调用上下文去登录,在整个会话未过期之前,根据认证方案获取对应处理方式,最后将相关信息进行存储等等,有兴趣的童鞋可以去了解其实现细节哈

当我们请求过后,再次访问首页,将看到生成当前会话信息,同时我们将会话过期设置为1分钟,在1分钟内未进行会话,将自动重定向至登录页,注意如上标注并没有值,那么这个值可以设置吗?当然可以,在开始配置时我们并未给出,那么这个属性又代表什么含义呢?

options.Cookie.MaxAge = TimeSpan.FromMinutes(2);

那么结合ExpireTimeSpan和MaxAge使用,到底代表什么意思呢?我们暂且撇开滑动过期设置

ExpireTimeSpan表示用户身份认证票据的生命周期,它是认证cookie的有效负载,存储的cookie值是一段加密字符串,在每次请求时,web应用程序都会根据请求对其进行解密

MaxAge控制着cookie的生命周期,若cookie过期,浏览器将会自动清除,如果没有设置该值,实质上它的生命周期就是ExpireTimeSpan,那么它到底有何意义呢?

上述我们设置票据的生命周期为1分钟,同时我们控制cookie的生命周期为2分钟,若在2分钟内关闭浏览器或重启web应用程序,此时cookie生命周期并未过期,所以仍将处于会话状态即无需登录,若未设置MaxAge,关闭浏览器或重启后将自动清除其值即需登录,当然一切前提是未手动清除浏览器cookie

问题又来了,在配置cookie选项中,还有一个也可以设置过期的属性

options.Cookie.Expiration = TimeSpan.FromMinutes(3);

当配置ExpireTimeSpan或同时配置MaxAge时,无需设置Expiration,因为会抛出异常

JWT认证

上述已经实现Cookie认证,那么在与第三方进行对接时,我们要使用JWT认证,我们又该如何处理呢?首先我们添加JWT认证服务

.AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters
    {
      ValidateIssuerSigningKey = true,
      IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456")),
      ValidateIssuer = true,
      ValidIssuer = "http://localhost:5000",
      ValidateAudience = true,
      ValidAudience = "http://localhost:5001",
      ValidateLifetime = true,
      ClockSkew = TimeSpan.FromMinutes(5)
    };
});

将JWT Token置于cookie中,此前文章已有讲解,这里我们直接给出代码,先生成Token

private string GenerateToken(Claim[] claims)
{
    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456"));
    var token = new JwtSecurityToken(
      issuer: "http://localhost:5000",
      audience: "http://localhost:5001",
      claims: claims,
      notBefore: DateTime.Now,
      expires: DateTime.Now.AddMinutes(5),
      signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
    );
    return new JwtSecurityTokenHandler().WriteToken(token);
}

在登录方法中,将其写入响应cookie中,如下这般

/// <summary>
/// 模拟登录
/// </summary>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> TestLogin()
{
    var claims = new Claim[]
    {
      new Claim(ClaimTypes.Name, "Jeffcky"),
    };
    var claimsIdentity = new ClaimsIdentity(claims, "Login");
    Response.Cookies.Append("x-access-token", GenerateToken(claims),
      new CookieOptions()
      {
        Path = "/",
        HttpOnly = true
      });
    await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
 return Ok();
}

那么JWT是如何验证Token的呢?默认是从请求去取Bearer Token值,若成功取到这赋值给如下context.Token,所以此时我们需要手动从cookie中取出token并赋值

options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        var accessToken = context.Request.Cookies["x-access-token"];
        if (!string.IsNullOrEmpty(accessToken))
        {
            context.Token = accessToken;
        }
        return Task.CompletedTask;
    }
};

一切已就绪,接下来我们写个api接口测试验证看看

[Authorize("Bearer")]
[Route("api/[controller]/[action]")]
[ApiController]
public class JwtController : ControllerBase
{
    [HttpGet]
    public IActionResult Test()
    {
      return Ok("test jwt");
    }
}

思考一下,我们通过Postman模拟测试,会返回401吗?结果会是怎样的呢?

问题不大,主要在于该特性参数为声明指定策略,但我们需要指定认证方案即scheme,修改成如下:

如此在与第三方对接时,请求返回token,后续将token置于请求头中即可验证通过,同时上述取cookie中token并手动赋值,对于对接第三方则是多余,不过是为了诸多其他原因而已

[Authorize(AuthenticationSchemes = "Bearer,Cookies")]

注意混合认证方案设置存在顺序,后者将覆盖前者即如上设置,此时将走cookie认证

滑动过期思考扩展

若我们实现基于Cookie滑动过期,同时使用signalr进行数据推送,势必存在问题,因为会一直刷新会话,那么将导致会话永不过期问题,从安全层面角度考虑,我们该如何处理呢?

我们知道票据生命周期存储在上下文AuthenticationProperties属性中,所以在配置Cookie选项事件中我们可以进行自定义处理

public class CookieAuthenticationEventsExetensions : CookieAuthenticationEvents
{
    private const string TicketIssuedTicks = nameof(TicketIssuedTicks);
    public override async Task SigningIn(CookieSigningInContext context)
    {
        context.Properties.SetString(
          TicketIssuedTicks,
          DateTimeOffset.UtcNow.Ticks.ToString());
        await base.SigningIn(context);
    }
    public override async Task ValidatePrincipal(
      CookieValidatePrincipalContext context)
    {
        var ticketIssuedTicksValue = context
          .Properties.GetString(TicketIssuedTicks);
        if (ticketIssuedTicksValue is null ||
          !long.TryParse(ticketIssuedTicksValue, out var ticketIssuedTicks))
        {
          await RejectPrincipalAsync(context);
          return;
        }
        var ticketIssuedUtc =
          new DateTimeOffset(ticketIssuedTicks, TimeSpan.FromHours(0));
        if (DateTimeOffset.UtcNow - ticketIssuedUtc > TimeSpan.FromDays(3))
        {
          await RejectPrincipalAsync(context);
          return;
        }
        await base.ValidatePrincipal(context);
    }
    private static async Task RejectPrincipalAsync(
      CookieValidatePrincipalContext context)
    {
        context.RejectPrincipal();
        await context.HttpContext.SignOutAsync();
    }
}

在添加Cookie服务时,有对应事件选项,使用如下

options.EventsType = typeof(CookieAuthenticationEventsExetensions);

扩展事件实现表示在第一次会话到当前时间截止超过3天,则自动重定向至登录页,最后将上述扩展事件进行注册即可

总结

暂无,下次再会!

你所看到的并非事物本身,而是经过诠释后所赋予的意义

到此这篇关于.NET Core如何支持Cookie和JWT混合认证、授权的文章就介绍到这了,更多相关.NET Core 混合认证、授权内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • asp.net core3.1cookie和jwt混合认证授权实现多种身份验证方案

    目录 认证授权 身份认证 授权 默认授权 选择授权 总结 开发了一个公司内部系统,使用asp.net core 3.1.在开发用户认证授权使用的是简单的cookie认证方式,然后开发好了要写几个接口给其它系统调用数据.并且只是几个简单的接口不准备再重新部署一个站点,所以就直接在MVC的项目里面加了一个API区域用来写接口.这时候因为是接口所以就不能用cookie方式进行认证,得加一个jwt认证,采用多种身份验证方案来进行认证授权. 认证授权 身份验证是确定用户身份的过程. 授权是确定用户是否有权

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

    目录 前言 Cookie认证 JWT认证 滑动过期思考扩展 总结 前言 为防止JWT Token被窃取,我们将Token置于Cookie中,但若与第三方对接,调用我方接口进行认证.授权此时仍需将Token置于请求头,通过实践并联系理论,我们继续开始整活!首先我们实现Cookie认证,然后再次引入JWT,最后在结合二者使用时联系其他我们可能需要注意的事项 Cookie认证 在startup中我们添加cookie认证服务,如下: services.AddAuthentication(options

  • ASP.NET Core使用JWT认证授权的方法

    demo地址: https://github.com/william0705/JWTS 名词解析 认证 : 识别用户是否合法 授权: 赋予用户权限 (能访问哪些资源) 鉴权: 鉴定权限是否合法 Jwt优势与劣势 优势 1. 无状态 token 存储身份验证所有信息 , 服务端不需要保存用户身份验证信息, 减少服务端压力 , 服务端更容易水平扩展, 由于无状态, 又会导致它最大缺点 , 很难注销 2. 支持跨域访问 Cookie是不允许垮域访问的,token支持 3. 跨语言 基于标准化的 JSO

  • mall整合SpringSecurity及JWT实现认证授权实战

    目录 摘要 项目使用框架介绍 SpringSecurity JWT JWT的组成 JWT实例 JWT实现认证和授权的原理 Hutool 项目使用表说明 整合SpringSecurity及JWT 在pom.xml中添加项目依赖 添加JWT token的工具类 添加SpringSecurity的配置类 相关依赖及方法说明 添加RestfulAccessDeniedHandler 添加RestAuthenticationEntryPoint 添加AdminUserDetails 添加JwtAuthen

  • Vue路由之JWT身份认证的实现方法

    一.JWT身份认证简介 JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案,相较于session机制,服务器就不需要保存任何 session 数据了,也就是说,服务器变成无状态了,从而比较容易实现扩展.JWT 实际上是一个令牌(Token),服务器会将一些元数据.指定的secret进行签名并生成token,并返回给客户端,客户端得到这个服务器返回的令牌后,需要将其存储到 Cookie 或 localStorage 中,此后,每次与服务器通信都要带上这个令牌,可以把它放到 C

  • ASP.NET Core 6.0 添加 JWT 认证和授权功能

    目录 序言 相关名词 认证(Authentication) 基本步骤 1 安装 Nuget 包 2 准备配置信息 3 添加服务 4 调用中间件 5 JwtHelper 类实现 6 控制器配置 7 测试调用 授权(Authorization) 相关标签(Attribute) 授权方式 1 Policy(策略) 2 Role(角色) 3 Scheme(方案) 3 定义权限项 4 实现 Requirement 5 实现授权处理程序 Handler 6 添加授权处理程序 7 添加授权策略 8 控制器配置

  • ASP.NET Core学习之使用JWT认证授权详解

    概述 认证授权是很多系统的基本功能 , 在以前PC的时代 , 通常是基于cookies-session这样的方式实现认证授权 , 在那个时候通常系统的用户量都不会很大, 所以这种方式也一直很好运行, 随着现在都软件用户量越来越大, 系统架构也从以前垂直扩展(增加服务器性能) -> 水平扩展(增加服务器数量) cookies-session 工作方式 客户端提交用户信息 -> 服务器识别用户 -> 服务端保存用户信息 -> 返回session-id客户端 -> 客户端保存ses

  • swagger上传文件并支持jwt认证的实现方法

    什么是 Swagger? Swagger的目标是为REST APIs 定义一个标准的,与语言无关的接口,使人和计算机在看不到源码或者看不到文档或者不能通过网络流量检测的情况下能发现和理解各种服务的功能.当服务通过Swagger定义,消费者就能与远程的服务互动通过少量的实现逻辑.类似于低级编程接口,Swagger去掉了调用服务时的很多猜测. 背景 由于swagger不仅提供了自动实现接口文档的说明而且支持页面调试,告别postman等工具,无需开发人员手动写api文档,缩减开发成本得到大家广泛认可

  • gateway和jwt网关认证实现过程解析

    这篇文章主要介绍了gateway和jwt网关认证实现过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 思路: 全局过滤器对所有的请求拦截(生成token有效期30分钟,放入redis设置有效期3天.3天之类可以通过刷新接口自动刷新,超过3天需要重新登录.) 前端在调用接口之前先判断token是否过期(3o分钟),过期则先调刷新接口,换取新token, 1引入相关jar <dependency> <groupId>org.sp

  • python中JWT用户认证的实现

    在前后端分离开发时为什么需要用户认证呢?原因是由于HTTP协定是不储存状态的(stateless),这意味着当我们透过帐号密码验证一个使用者时,当下一个request请求时它就把刚刚的资料忘了.于是我们的程序就不知道谁是谁,就要再验证一次.所以为了保证系统安全,我们就需要验证用户否处于登录状态. 一.传统方式 前后端分离通过Restful API进行数据交互时,如何验证用户的登录信息及权限.在原来的项目中,使用的是最传统也是最简单的方式,前端登录,后端根据用户信息生成一个token,并保存这个t

随机推荐