首页 文章详情

Web通用令牌JwtBuilder

DotNetCore实战 | 274 2021-04-29 22:00 0 0 0
UniSMS (合一短信)

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

Nuget包:NewLife.Core、NewLife.Secrurity

源码地址:

https://github.com/NewLifeX/X/blob/master/NewLife.Core/Web/JwtBuilder.cs


功能特性

主要功能特性:

  1. Json格式简单易用,JWT目前已经成为最常见的web验证方式;

  2. 主体部分可以按需增加多种数据,满足不同业务场景需要;

  3. 支持多种数字签名方式,HS256/HS384/HS512密钥短小,RS256/RS384/RS512安全性更高;

  4. 支持外扩数字签名方式,NewLife.Security 支持ES256/ES384/ES512;


应用场景

使用JWT实现的SSO单点登录工作流程

用户首先前往SSO用户中心进行身份验证,获取JWT令牌,即可携带令牌访问各应用服务器。

令牌具有有效期,一般2小时过期。应用服务器遇到过期令牌时,应该拒绝提供服务。

SSO用户中心实际上颁发两个令牌,访问令牌用于访问各应用服务器,刷新令牌用于在令牌过期之前请求SSO刷新令牌。


示例详解

JwtBuilder设置Secret密钥后(默认算法HS256),通过Encode编码匿名对象数据,得到JWT令牌。

解码时只需要设置密钥,然后TryDecode即可,TryDecode返回JWT令牌验证是否通过,如果不通过,message输出参数指示错误内容。

var builder = new JwtBuilder{    IssuedAt = 1516239022.ToDateTime(),    Expire = DateTime.MinValue,    Secret = "Smart",};
var token = builder.Encode(new { sub = "0201", name = "stone" });Assert.NotNull(token);Assert.NotEmpty(token);
var ts = token.Split('.');Assert.Equal(3, ts.Length);Assert.Equal("eyJhbGciOiJIUzI1NiJ9", ts[0]);Assert.Equal("eyJzdWIiOiIwMjAxIiwibmFtZSI6InN0b25lIiwiaWF0IjoxNTE2MjM5MDIyfQ", ts[1]);Assert.Equal("mY2_rvQORkyYpK3f84liG2EDpaYY7pO43sRgcli381U", ts[2]);
var builder2 = new JwtBuilder{ Secret = builder.Secret,};
ts = builder2.Parse(token);Assert.NotNull(ts);Assert.Equal(3, ts.Length);
var rs = builder2.TryDecode(token, out var msg);Assert.True(rs);Assert.Null(msg);
Assert.Null(builder2.Type);Assert.Equal("0201", builder2.Subject);Assert.Equal("stone", builder2["name"]);


ES512扩展

HS512安全性不够,RS512密钥太长导致令牌也很长。

此时最合适使用ES512,该算法封装在 NewLife.Security 中,引用nuget包后,需要注册算法:

JwtBuilder.RegisterAlgorithm("ES512", ECDsaHelper.SignSha512, ECDsaHelper.VerifySha512)

JwtBuilder.RegisterAlgorithm("ES256", ECDsaHelper.SignSha256, ECDsaHelper.VerifySha256);JwtBuilder.RegisterAlgorithm("ES384", ECDsaHelper.SignSha384, ECDsaHelper.VerifySha384);JwtBuilder.RegisterAlgorithm("ES512", ECDsaHelper.SignSha512, ECDsaHelper.VerifySha512);
var prvKey = @"-----BEGIN PRIVATE KEY-----MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G-----END PRIVATE KEY-----";var pubKey = @"-----BEGIN PUBLIC KEY-----MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEEVs/o5+uQbTjL3chynL4wXgUg2R9q9UU8I5mEovUf86QZ7kOBIjJwqnzD1omageEHWwHdBO6B+dFabmdT9POxg==-----END PUBLIC KEY-----";
var builder = new JwtBuilder{ Algorithm = "ES512", Type = "JWT",
IssuedAt = 1516239022.ToDateTime(), Expire = DateTime.MinValue, Secret = prvKey,};
var token = builder.Encode(new { sub = "1234567890", name = "NewLife", admin = true });Assert.NotNull(token);Assert.NotEmpty(token);
var ts = token.Split('.');Assert.Equal(3, ts.Length);Assert.Equal("eyJhbGciOiJFUzUxMiIsInR5cCI6IkpXVCJ9", ts[0]);Assert.Equal("eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ik5ld0xpZmUiLCJhZG1pbiI6dHJ1ZSwiaWF0IjoxNTE2MjM5MDIyfQ", ts[1]);//Assert.Equal("xyCWz7tNjH4UUkxi7BqlWE4V857XA6SYC-ZFukvexvIgsGQt9SBcpdglz3NfhhrslOwF7HzWZHOJu3RrIFrDFA", ts[2]);
var builder2 = new JwtBuilder{ Algorithm = "ES512",
Secret = pubKey,};var rs = builder2.TryDecode(token, out var msg);Assert.True(rs);Assert.Null(msg);
Assert.Equal("JWT", builder2.Type);Assert.Equal("1234567890", builder2.Subject);Assert.Equal("NewLife", builder2["name"]);Assert.True(builder2["admin"].ToBoolean());


总结

应用自己颁发自己验证使用的场景,推荐使用HS512,简单安全,且令牌长度较短,这是最常见的JWT在Web应用场景。

应用颁发令牌给多个第三方使用时,安全起见不能把HS512密钥给对方,此时推荐使用ES512,安全性很高,并且令牌长度远比RS512要短,(但比HS512要长一些)。



往期精彩回顾




【推荐】.NET Core开发实战视频课程 ★★★

.NET Core实战项目之CMS 第一章 入门篇-开篇及总体规划

【.NET Core微服务实战-统一身份认证】开篇及目录索引

Redis基本使用及百亿数据量中的使用技巧分享(附视频地址及观看指南)

.NET Core中的一个接口多种实现的依赖注入与动态选择看这篇就够了

10个小技巧助您写出高性能的ASP.NET Core代码

用abp vNext快速开发Quartz.NET定时任务管理界面

在ASP.NET Core中创建基于Quartz.NET托管服务轻松实现作业调度

现身说法:实际业务出发分析百亿数据量下的多表查询优化

关于C#异步编程你应该了解的几点建议

C#异步编程看这篇就够了


good-icon 0
favorite-icon 0
收藏
回复数量: 0
    暂无评论~~
    Ctrl+Enter