实践剖析.NET Core如何支持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();}......
}

我们启动程序先看看效果

71746e46102d2bcaa7e2d84d43d3f0f5.png

如上图,自动跳转至登录页,此时我们点击模拟登录按钮,发起请求去模拟登录(发起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();
}

上述无非就是构建身份以及该身份下所具有的身份属性,类似个人身份证唯一标识个人,身份证上各个信息即表示如上声明

同时呢,肯定要调用上下文去登录,在整个会话未过期之前,根据认证方案获取对应处理方式,最后将相关信息进行存储等等,有兴趣的童鞋可以去了解其实现细节哈

a1eadf49bde600a205fd96cc11309cb1.png

当我们请求过后,再次访问首页,将看到生成当前会话信息,同时我们将会话过期设置为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,因为会抛出异常

18b0a8f08ae3f81f1e971c2eb874a49a.png

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吗?结果会是怎样的呢?

aa2916d3b8fd0ebeeba81bc6694f6d43.png

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

46b51eeea501fb467008994dc7311abb.png

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

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

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

07b15ec025d2bd5eb2795d2342fb9afa.png

滑动过期思考扩展

若我们实现基于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天,则自动重定向至登录页,最后将上述扩展事件进行注册即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

简单音乐播放实例的实现,Android Service AIDL 远程调用服务

2019独角兽企业重金招聘Python工程师标准>>> Android Service是分为两种&#xff1a; 本地服务&#xff08;Local Service&#xff09;&#xff1a; 同一个apk内被调用 远程服务&#xff08;Remote Service&#xff09;&#xff1a;被另一个apk调用 远程服务需要借…

C# 使用int.TryParse,Convert.ToInt32,(int)将浮点类型转换整数时的区别

int.TryParse,Convert.ToInt32,(int) 这几种类型在将浮点类型转换整数时是有差别Convert.ToInt32则会进行四舍五入int.TryParse只能转换整数,即浮点类型全部会返回0(int)不会进行四舍五入,只取整数部分,小数点部分完全舍弃using System;public class DoubleToInt{public …

每个女孩子起床后做的第一件事......

1 假如你暴富了&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼2 当客服到底有多难&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 挺好的&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 每个女孩子起床后做的第一件事&#xff…

国产知名老牌 PDF 工具正式开源

文 | Travis出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013&#xff09;「PDF 补丁丁」是开发者 wmjordan 所开发的一款适用于 Windows 系统的多功能 PDF 文档工具箱&#xff0c;开发者最早于 2009 年开始了该程序的开发&#xff0c;如今已有十二年历史&#xff0c;…

.net Repeater知识知多少

&#xff08;一&#xff09;.net中使用Repeater绑定数据&#xff0c;并使用repeater循环出的两个值&#xff0c;赋给repeater中的div的value值。详细如下&#xff1a; 前端.net代码&#xff1a; <div class"wytz_xmlb_nr clear"><asp:Repeater ID"RpBi…

目瞪口呆!137亿年的宇宙演化,竟然如此震撼!简直颠覆想象....

▲ 点击查看1968年圣诞节&#xff0c;阿波罗8号在环月球轨道上拍摄了一张照片。这是地球拥有的第一张自拍。也让人类第一次感受到&#xff0c;原来在广阔无垠的宇宙中&#xff0c;地球不过是一个美丽而又珍贵的孤岛。1990年&#xff0c;旅行者1号完成了所有的观测使命&#xff…

Martin Fowler:数字化时代,远程与本地协同工作孰优孰劣?| IDCF

作者&#xff1a;Martin Fowler译者&#xff1a;冬哥原文&#xff1a;https://martinfowler.com/articles/remote-or-co-located.html远程工作与同地工作之间不是简单的二分法&#xff0c;相反&#xff0c;团队有多种分布模式&#xff0c;每种模式都有不同的权衡和适合的有效技…

android:自己实现能播放网络视频url的播放器

2019独角兽企业重金招聘Python工程师标准>>> android原生自带的播放器一般只能播放本地视频&#xff0c;而没有播放url的功能。不过android系统中有一个VideoView的控件可以实现这一功能。 简单实现如下&#xff1a; public class MyVideoPlay extends Activity i…

iOS调用系统相册、相机 显示中文标题

2019独角兽企业重金招聘Python工程师标准>>> 最终在info.plist设置解决问题 发现在项目的info.plist里面添加Localized resources can be mixed 设置为&#xff1a; YES&#xff08;表示是否允许应用程序获取框架库内语言&#xff09;即可解决这个问题。 转载于:htt…

使用云原生应用和开源技术的创新攻略

Kubernetes 和云原生应用的增长以及普及是现象级的。根据 IDC 的数据&#xff0c;到2025年&#xff0c;90%以上的新应用程序将是云原生的。许多客户已受益于云原生设计模型&#xff0c;让新一代应用程序更加敏捷、可靠、可扩展&#xff0c;还兼顾了安全。说到服务的开发&#x…

SVM支持向量机原理及核函数

原文链接&#xff1a;SVM支持向量机原理及核函数 转载请注明出处 支持向量机原理 大距离分类算法 1、名词解释&#xff1a; 分割超平面&#xff1a;如下图所示&#xff0c;构造一个分割线把圆形的点和方形的点分开&#xff0c;这个线称为分割超平面。支持向量&#xff1a;…

SQL对Xml字段的操作

转&#xff1a;http://www.cnblogs.com/youring2/archive/2008/11/27/1342288.html T-Sql操作Xml数据 一、前言 SQL Server 2005 引入了一种称为 XML 的本机数据类型。用户可以创建这样的表&#xff0c;它在关系列之外还有一个或多个 XML 类型的列&#xff1b;此外&#xff0c;…

URL 路径长度限制(错误:指定的文件或文件夹名称太长)

本节讨论 URL 的构成、SharePoint 2010 构建 URL 的方式、URL 的编码和加长以及作为其他 URL 中的参数传递的方式。 SharePoint URL 的构成 SharePoint URL 的总长度等于文件夹或文件路径的长度&#xff0c;包括协议和服务器名称和文件夹或文件名称&#xff0c;以及作为 URL 的…

sklearn线性回归详解

图片若未能正常显示&#xff0c;点击下面链接&#xff1a; http://ihoge.cn/2018/Logistic-regression.html 在线性回归中&#xff0c;我们想要建立一个模型&#xff0c;来拟合一个因变量 y 与一个或多个独立自变量(预测变量) x 之间的关系。 给定&#xff1a; 数据集 {(x…

DateOnly和TimeOnly类型居然不能序列化!!! .Net 6下实现自定义JSON序列化

前言.Net 6引入了DateOnly和TimeOnly结构&#xff0c;可以存储日期和时间。但在实际使用时&#xff0c;发现一个很尴尬的问题&#xff0c;DateOnly和TimeOnly居然不能被序列化&#xff1a;var builder WebApplication.CreateBuilder(args);var app builder.Build();app.MapGe…

使用插件创建 .NET Core 应用程序

使用插件创建 .NET Core 应用程序本教程展示了如何创建自定义的 AssemblyLoadContext 来加载插件。AssemblyDependencyResolver 用于解析插件的依赖项。该教程正确地将插件依赖项与主机应用程序隔离开来。将了解如何执行以下操作&#xff1a;构建支持插件的项目。创建自定义…

支持向量机SVC

原文&#xff1a; http://ihoge.cn/2018/SVWSVC.html 支持向量机(support vector machine)是一种分类算法&#xff0c;但是也可以做回归&#xff0c;根据输入的数据不同可做不同的模型&#xff08;若输入标签为连续值则做回归&#xff0c;若输入标签为分类值则用SVC()做分类&…

Beetlex官网迁移完成

由于beetlex.io域名无法指向国内&#xff0c;使用国内的服务器很多时候有抽风情况出现&#xff0c;所以把网站迁回国内&#xff1b;新的域名也申请完成并且申请备案通过&#xff0c;现在可以通过https://beetlex-io.com来访问Beetlex的官网.接下把涉及的费用和部署情况也说一下…

SVM支持向量机绘图

原文&#xff1a; http://ihoge.cn/2018/SVM绘图.html %matplotlib inline import matplotlib.pyplot as plt import numpy as np class1 np.array([[1, 1], [1, 3], [2, 1], [1, 2], [2, 2]]) class2 np.array([[4, 4], [5, 5], [5, 4], [5, 3], [4, 5], [6, 4]]) plt.f…