更轻易地实现 Jwt Token

更轻易地实现一个 Jwt Server

Intro

最近在多个项目中都有用到 Jwt Token 认证,就想着把之前项目里 Jwt Token 的使用封装一下,以便于之后集成起来更加地方便,不用再拷贝代码了

JWT

JWT 是 JSON Web Token 的缩写,是目前最流行的基于 Token 的认证解决方案,JWT 是一种无状态的认证方式,我们不需要依赖 Session,更为简单,对于随时准备扩容缩容的云原生应用来说更加的友好。

JWT token 的格式分成三个部分,他们之间以 “.” 作为分隔

  • Header(头部)

  • Payload(负载)

  • Signature(签名)

6f8c375c9d93d2da7ba12c89ae78d880.png

JWT Token

我们可以在 https://jwt.io 网站上查看 token 的内容,也可以自己写个小工具来查看,token 的内容是 base64 URL 编码的

JWT 作为一个令牌(token),有些场合可能会放到 URL(比如 api.example.com/?token=xxx)。Base64 有三个字符+/=,在 URL 里面有特殊含义,所以要被替换掉:=被省略、+替换成-/替换成_ 。这就是 Base64URL 算法。

JWT Token 内容解析之后如下所示:

cff231f50ebc3b0511bba929fc780c85.png

Header 是 token 所用到的签名算法信息,默认是 HMAC SHA 256(HS256) 以及 RSA SHA 256(RS256)

Payload 就是我们 token 中保存的信息,这些信息是可以解析成明文的,所以内容上不能保存敏感信息,只能保存一些敏感度不高的信息

Signature 是基于 header 和 payload 生成出来的,例如使用 HMAC SHA 256 签名

HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),secret)

Sample

介绍了一些基本知识,我们再来看示例吧

首先需要集成 WeihanLi.Web.Extensions 这个 NuGet 包

我们只需要注册服务即可:

services.AddJwtTokenService(options =>
{options.SecretKey = Guid.NewGuid().ToString();options.Issuer = "https://id.weihanli.xyz";options.Audience = "SparkTodo";
});

SecretKey 是用来生成 token 和 token 签名校验的,默认签名方式 是 HMAC SHA256

Issuer 是签发人,是指定谁颁发的 token

Audience 是受众,是指 token 是给谁用的

注册好服务之后,我们就可以从依赖注入服务中获取 ITokenService 来进行 token 的操作了

[HttpGet("getToken")]
public async Task<IActionResult> GetToken([Required] string userName, [FromServices] ITokenService tokenService)
{var token = await tokenService.GenerateToken(new Claim("name", userName));return token.WrapResult().GetRestResult();
}[HttpGet("validateToken")]
public async Task<IActionResult> ValidateToken(string token, [FromServices] ITokenService tokenService)
{return await tokenService.ValidateToken(token).ContinueWith(r =>r.Result.WrapResult().GetRestResult());
}

GetToken:

16eb1a2cff7c5df9cdf2b85e29de9ccc.png

GetToken

VaidateToken:

d0eb9a74c057ff60615c08a74aff7d13.png

ValidateToken

Implement

我们来看一些实现细节

public class JwtTokenService : ITokenService
{private readonly JwtSecurityTokenHandler _tokenHandler = new();private readonly JwtTokenOptions _tokenOptions;private readonly Lazy<TokenValidationParameters>_lazyTokenValidationParameters;public JwtTokenService(IOptions<JwtTokenOptions> tokenOptions){_tokenOptions = tokenOptions.Value;_lazyTokenValidationParameters = new(() =>_tokenOptions.GetTokenValidationParameters());}public virtual Task<TokenEntity> GenerateToken(params Claim[] claims)=> GenerateTokenInternal(claims);public virtual Task<TokenValidationResult> ValidateToken(string token){return _tokenHandler.ValidateTokenAsync(token, _lazyTokenValidationParameters.Value);}private async Task<TokenEntity> GenerateTokenInternal(bool refreshToken, Claim[] claims){var now = DateTimeOffset.UtcNow;var claimList = new List<Claim>(){new (JwtRegisteredClaimNames.Iat, now.ToUnixTimeMilliseconds().ToString(), ClaimValueTypes.Integer64)};if (claims != null){claimList.AddRange(claims);}var jti = claimList.FirstOrDefault(c => c.Type == JwtRegisteredClaimNames.Jti)?.Value;if (jti is null){jti = _tokenOptions.JtiGenerator?.Invoke() ?? GuidIdGenerator.Instance.NewId();claimList.Add(new(JwtRegisteredClaimNames.Jti, jti));}var jwt = new JwtSecurityToken(issuer: _tokenOptions.Issuer,audience: _tokenOptions.Audience,claims: claimList,notBefore: now.UtcDateTime,expires: now.Add(_tokenOptions.ValidFor).UtcDateTime,signingCredentials: _tokenOptions.SigningCredentials);var encodedJwt = _tokenHandler.WriteToken(jwt);var response = new TokenEntity(){AccessToken = encodedJwt,ExpiresIn = (int)_tokenOptions.ValidFor.TotalSeconds};return response;}
}

More

默认是基于 HS256 的签名方式,你也可以很轻松地切换成使用基于 RSA 的 RS256 方式,可以自己探索一下

更多实现细节可以参考源码:https://github.com/WeihanLi/WeihanLi.Web.Extensions/tree/dev/src/WeihanLi.Web.Extensions/Authorization/Jwt

下一篇文章我们介绍如何使用 RefreshToken

References

  • https://github.com/WeihanLi/SparkTodo/blob/master/SparkTodo.API/Program.cs#L40

  • https://github.com/WeihanLi/WeihanLi.Web.Extensions/blob/dev/samples/WeihanLi.Web.Extensions.Samples/Program.cs#L40

  • https://github.com/WeihanLi/WeihanLi.Web.Extensions

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

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

相关文章

android之实现各个组件点击事件处理

android之实现各个组件点击事件处理&#xff1a;注意&#xff1a;&#xff08;TextView这个组件要点击产生效果的话&#xff0c;要设置&#xff0c;android:clickable"true"这个属性&#xff09;布局&#xff1a;layout/activity_main.xml<LinearLayout xmlns:and…

Android开发最佳实践《IT蓝豹》

Android开发最佳实践 移动开发Android经验分享应用GoogleMaterial Design摘要&#xff1a;前 段时间&#xff0c;Google公布了Android开发最佳实践的一系列课程&#xff0c;涉及到一些平时开发过程中应该保持的良好习惯以及如何使用最新的Android Design Support Library来快速…

.NET MAUI 已在塔架就位 ,4月份发布RC

最美人间三月天&#xff0c;春光不负赶路人。在充满无限希望的明媚春天里&#xff0c;一路风雨兼程的.NET 团队正奋力实现新的突破。根据计划&#xff0c;新一代移动开发平台MAUI 将于4月份 发布RC。目前&#xff0c;MAUI的测试工作和火箭发射前各项准备工作在github 上按计划有…

如何把照片正面变成反面_没有锁边机如何做衣服(五种方法)

这么多年一直没有锁边机&#xff0c;但是也做了很多衣服&#xff0c;今天给大家分享一些我曾经用过的方法。来去缝来去缝适合缝制轻薄面料&#xff0c;如雪纺、真丝、欧根纱等。反反相对&#xff0c;缝份0.5厘米把缝份剪掉0.2厘米翻过来使正面相对&#xff0c;留0.5厘米的缝份车…

linux线程池资料

2019独角兽企业重金招聘Python工程师标准>>> http://www.360doc.com/content/13/0728/13/13308646_303116654.shtml http://blog.csdn.net/turkeyzhou/article/details/8755976 http://blog.csdn.net/zhoubl668/article/details/8927090 http://blog.csdn.net/zypue…

Xamarin效果第二篇之公众号App

前面简单摸索一下Xamarin然后简单做了一个时间轴;这不这几天再次基于Xamarin实现了一下公众号App;我也就是瞎折腾,闲话不多扯,上效果:主Page直接用TabbedPage(类似WPF中的TabControl)然后后台添加内容Page:”互动“页使用CollectionView和模板选择器&#xff1a;"发表&quo…

K8S原来如此简单(一)K8S核心组件与基本原理

k8s视频课程K8S核心组件与工作原理k8s官方文档&#xff1a;https://kubernetes.io/zh/docs/home/前提掌握容器技术&#xff1a;Docker&#xff0c;Containerd等K8S优势使用简单&#xff0c;少量人/小团队可以轻松维护大型分布式系统全面拥抱微服务架构&#xff0c;快速迭代&…

docker supervisor管理进程

Supervisor管理进程Docker容器在启动的时候开启单个进程&#xff0c;比如&#xff0c;一个ssh或者apache的daemon服务。但我们经常需要在一个机器上开启多个服务&#xff0c;这可以有很多方法&#xff0c;最简单的就是把多个启动命名放到一个启动脚本里面&#xff0c;启动的时候…

理解Linux系统中的load average

一、什么是load average&#xff1f;linux系统中的Load对当前CPU工作量的度量 (WikiPedia: the system load is a measure of the amount of work that a computer system is doing)。也有简单的说是进程队列的长度。Load Average 就是一段时间 (1 分钟、5分钟、15分钟) 内平均…

【贯穿】.NET6结合Docker傻瓜式实现容器编排

常规开发部署的痛点一个项目的开发上线有很多纷繁复杂的问题&#xff0c;例如&#xff1a;操作系统运行环境以及各种应用配置、集群环境搭建等等。特别是各种版本的迭代导致的不兼容&#xff0c;这些对于曾经的架构师而言也十分苦恼。而Docker的出现实现了从“蚂蚁搬家”到“乾…

bootstrapt 表格自适应_一起聊B端设计 - 如何设计表格?

一、 数据查看让我们先来回顾一下表格的基本构成&#xff0c;最上面的为表头&#xff0c;横为行&#xff0c;纵为列&#xff0c;内容区每一组展示数据区域为单元格。 表格的设计&#xff0c;虽然看似简单&#xff0c;但是作为用户最常用的组件之一&#xff0c;我们需要对视觉和…

.NET 6 攻略大全(二)

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;15分钟)接上篇内容&#xff0c;本篇文章将介绍&#xff1a;Arm64、容器、支持 OpenTelemetry 指标、Windows Forms 的相关攻略。 Arm64这些天来&#xff0c;对于笔记本电脑、云硬件和其他设备来说&#xff0c;Arm64 令…

ubuntu 开启 apache mod_rewrite

2019独角兽企业重金招聘Python工程师标准>>> ci里需要隐藏index.php的输入需要使用apache的rewrite模块,按照下面的步骤开启mod_rewrite http://www.dev-metal.com/enable-mod_rewrite-ubuntu-14-04-lts/ 转载于:https://my.oschina.net/u/1177171/blog/354202

composer切换源_Composer具体安装方法

composer 作为依赖管理工具&#xff0c;使用频率还是挺高的。特别是对于我这种比较懒的程序猿&#xff0c;有现成轮子的时候坚决不自己重复造轮子。它主要有三部分构成&#xff1a;命令行工具&#xff0c;包仓库&#xff0c;代码库。包仓库就是我们常说的 composer 源&#xff…

C# 操作FireBird 附源码

写了一个C#操作firebird数据库的小Demo&#xff0c;有需要的可以研究研究, 步骤&#xff1a; 1.创建数据库 2.建数据表&#xff0c;插入数据&#xff0c;并读取、 写的时候碰到N多奇葩问题&#xff0c;记录了一些 解决方案&#xff1a; 程序集-生成-目标平台 改成 x86 源码地址…

.NET 6 攻略大全(三)

点击上方蓝字关注我们&#xff08;本文阅读时间&#xff1a;15分钟).NET 6 继续与大家相约周日啦。本篇文章将介绍&#xff1a;单文件应用、IL 修整、System.Text.Json、源代码构建、库AIP的相关攻略。 单文件应用 在 .NET 6中&#xff0c;已为 Windows 和 macOS 启用内存中单文…

测试眉形的有哪个软件_这五款自动化软件测试工具,你最喜欢用哪个?

对测试自动化的依赖性增加导致大量自动化软件测试工具的出现&#xff0c;使得很难确定哪些是最好的。为了帮助您完成自动化工作&#xff0c;我们根据自己和他人的经验创建了五大最佳自动化软件测试工具列表。1. SeleniumSelenium可以说是web开发人员和测试人员中最受欢迎的自动…

本科 8年经验,20k的Offer,接还是不接?

伴随着疫情的此起彼伏&#xff0c;今年的金三银四跳槽季比往年要低沉很多&#xff0c;近日一条朋友圈火遍社区&#xff0c;“坐标一线城市&#xff0c;本科毕业&#xff0c;8年经验&#xff0c;15天仅5场面试&#xff0c;最终接了20k的offer&#xff0c;今年真难&#xff01;”…

CAD中批量打印

同事在网上找各种软件来实现CAD图的批量打印&#xff0c;总是问题多多。于是&#xff0c;我想到一个更方便的解决方法&#xff0c;即只要我将一个打印出来&#xff0c;然后就可以用批量处理来实现。 1.在CAD中输入plot命令&#xff08;或快捷键CtrlP&#xff09;&#xff0c;即…

Photoshop脚本 使用ExtendScript编写Ps脚本

源自&#xff1a;http://coolketang.com/tutorials/menu1lesson3.php本节课程将演示如何使用ExtendScript编写脚本&#xff0c;它是由Adobe公司开发的一款脚本语言工具包。以后的所有课程也将使用这款工具编写脚本。您可以在开始菜单(Windows电脑)或Application目录(Mac电脑)上…