c#关于JWT跨域身份验证解决方案
学习程序,不是记代码,而是学习一种思想,以及对代码的理解和思考。
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案。为了网络应用环境间传递声明而执行的一种基于JSON的开发标准(RFC 7519),
该token被设计为紧凑且安全的,特别适用于分布式站点的单点登陆(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,
以便于从资源服务器获取资源,该token也可直接被用于认证,也可被加密。
一、JWT的组成
下面是JWT的一段示例,分为三个部分,分别是头部(header),载荷(payload)}和签证(signature),他们之间用点隔开。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.
eyJpc3MiOiLmtYHmnIjml6Dlj4wiLCJleHAiOjE1NzExMDIxNTMsInN1YiI6InRlc3RKV1QiLCJhdWQiOiJVU0VSIiwiaWF0IjoiMjAxOS8xMC8xNSA5OjE1OjQzIiwiZGF0YSI6eyJuYW1lIjoiMTExIiwiYWdlIjoxMSwiYWRkcmVzcyI6Imh1YmVpIn19.
25IbZpAbSXBQsr2k3h0IzKRAC6z3OJTWg38VDtcEER8
二、和传统session的对比
JWT是基于json的鉴权机制,而且是无状态的,服务器端是没有如传统那样保存客户端的登录信息的,这就为分布式开发提供了便利,
因为传统的方式是在服务端保存session信息,session是保存在内存中的,当客户量变大的时候,对服务器的压力自然会增大,
最关键的是在集群分布式中,每一次登录的服务器可能不一样,那么可能导致session保存在其中一个服务器,而另外一个服务器被请求的
时候还是无状态,除非你再次登录,这就造成了很大的麻烦,也有人说把session存放在专门的服务器,每次都去那个服务器请求,
我不认为这是很好的解决方案,本来集群就是为了高可用,如果你配置session的服务器坏了,大家都跟着完蛋,所以JWT这种无状态的方式
就非常适合这种分布式的系统。
三、代码 JwtHelper
光说不练假把式,下面还是来一段代码。
还是老方式,先用NuGet把JWT引用进来,这里需要引入JWT和newtonsoft.json
如下图所示:

然后就是生成JWT的方法。
static IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//HMACSHA256加密
static IJsonSerializer serializer = new JsonNetSerializer();//序列化和反序列
static IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//Base64编解码
static IDateTimeProvider provider = new UtcDateTimeProvider();//UTC时间获取
const string secret = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4aKpVo2OHXPwb1R7duLgg";//服务端
public static string CreateJWT(Dictionary<string, object> payload)
{
IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
return encoder.Encode(payload, secret);
}
看到这段代码,你说觉得怎么这么简单,没错,就是这么简单,这个方法是被我们引用进来的这个JWT给封装了,所以看起来很简单
当时我看到这里也是有点吃惊,不过我还是对源码进行了研究,下面贴出一段源码给大家看看
如下所示,这段代码是比较核心的代码,在没有传递header的时候,他帮你默认加了header,
其实下面的这段代码很容易看懂,无非就是对header和payload进行base64加密(其实这里说加密也不是很恰当)。
这里的header你可以自己传递进来。
public string Encode(IDictionary<string, object> extraHeaders, object payload, byte[] key)
{
if (payload is null)
throw new ArgumentNullException(nameof(payload)); var segments = new List<string>(); var header = extraHeaders is null ? new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase) : new Dictionary<string, object>(extraHeaders, StringComparer.OrdinalIgnoreCase);
header.Add("typ", "JWT");
header.Add("alg", _algorithm.Name); var headerBytes = GetBytes(_jsonSerializer.Serialize(header));
var payloadBytes = GetBytes(_jsonSerializer.Serialize(payload)); segments.Add(_urlEncoder.Encode(headerBytes));
segments.Add(_urlEncoder.Encode(payloadBytes)); var stringToSign = String.Join(".", segments.ToArray());
var bytesToSign = GetBytes(stringToSign); var signature = _algorithm.Sign(key, bytesToSign);
segments.Add(_urlEncoder.Encode(signature)); return String.Join(".", segments.ToArray());
}
下面一段就是对JWT进行验证的代码,这里的写法都差不多,反正都是调用JWT里面的方法,我们传递参数即可。
public static bool ValidateJWT(string token, out string payload, out string message)
{
bool isValidted = false;
payload = "";
try
{
IJwtValidator validator = new JwtValidator(serializer, provider);//用于验证JWT的类
IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder);//用于解析JWT的类
payload = decoder.Decode(token, secret, verify: true);
isValidted = true;
message = "验证成功";
}
catch (TokenExpiredException)//当前时间大于负载过期时间(负荷中的exp),会引发Token过期异常
{
message = "过期了!";
}
catch (SignatureVerificationException)//如果签名不匹配,引发签名验证异常
{
message = "签名错误!";
}
return isValidted;
}
四、调用
class Program
{
static void Main(string[] args)
{
//载荷(payload)
var payload = new Dictionary<string, object>
{
{ "iss","流月无双"},//发行人
{ "exp", DateTimeOffset.UtcNow.AddSeconds().ToUnixTimeSeconds() },//到期时间
{ "sub", "testJWT" }, //主题
{ "aud", "USER" }, //用户
{ "iat", DateTime.Now.ToString() }, //发布时间
{ "data" ,new { name="",age=,address="hubei"} }
};
//生成JWT
Console.WriteLine("******************生成JWT*******************");
string JWTString = JwtHelper.CreateJWT(payload);
Console.WriteLine(JWTString);
Console.WriteLine(); //校验JWT
Console.WriteLine("*******************校验JWT,获得载荷***************");
string ResultMessage;//需要解析的消息
string Payload;//获取负载
if (JwtHelper.ValidateJWT(JWTString, out Payload, out ResultMessage))
{
Console.WriteLine(Payload);
}
Console.WriteLine(ResultMessage);//验证结果说明
Console.WriteLine("*******************END*************************");
}
}
结果如图:

五、总结
1、因为json是通用的,所以jwt可以在绝大部分平台可以通用,如java,python,php,.net等
2、基于jwt是无状态的,jwt可以用于分布式等现在比较流行的一些框架中。
3、jwt本身不是加密的,所以安全性不是很高,别人知道了你的token就可以解析了,
当然你自己也可以对jwt进行加密,设置的过期时间不宜过长,同时不要保存一些重要的信息,如密码。
4、尽量使用https,这也是为了安全。
5、JWT字节占用很少,非常的轻便,所以便于传输。
6、JWT一般放在http的头部Header中传输。
---如有错误欢迎指出,大家相互进步。
c#关于JWT跨域身份验证解决方案的更多相关文章
- JWT跨域身份验证解决方案
JSON Web Token(JWT)是目前最流行的跨域身份验证解决方案.本文介绍JWT的原理和用法. 1. 当前跨域身份验证的问题 Internet服务无法与用户身份验证分开.一般过程如下.1.用户 ...
- Cookie、Session、Token与JWT(跨域认证)
之前看到群里有人问JWT相关的内容,只记得是token的一种,去补习了一下,和很久之前发的认证方式总结的笔记放在一起发出来吧. Cookie.Session.Token与JWT(跨域认证) 什么是Co ...
- 第四节:跨域请求的解决方案和WebApi特有的处理方式
一. 简介 前言: 跨域问题发生在Javascript发起Ajax调用,其根本原因是因为浏览器对于这种请求,所给予的权限是较低的,通常只允许调用本域中的资源, 除非目标服务器明确地告知它允许跨域调用. ...
- 跨域通信的解决方案JSONP
在web2.0时代,熟练的使用ajax是每个前端攻城师必备的技能.然而由于受到浏览器的限制,ajax不允许跨域通信. JSONP就是就是目前主流的实现跨域通信的解决方案. 虽然在在jquery中,我们 ...
- ajax 跨域访问的解决方案
ajax 跨域访问的解决方案 一.什么是跨域: 1.什么样的请求属于跨域: 域名,端口有任何一个不相同都属于跨域: 二.跨域的常用几种解决方案: 1.jsonp: 2.iframe: 3.webcon ...
- 跨域问题,解决方案-Nginx反向代理
跨域问题,解决之道 跨域问题,在日常开发过程中,是一个非常熟悉的名词.今天的话题,结合我之前的项目场景,讨论下<跨域问题,解决之道>. 跨域是什么 跨域问题,是由于JavaScript出于 ...
- Ajax跨域问题及解决方案 asp.net core 系列之允许跨越访问(Enable Cross-Origin Requests:CORS) c#中的Cache缓存技术 C#中的Cookie C#串口扫描枪的简单实现 c#Socket服务器与客户端的开发(2)
Ajax跨域问题及解决方案 目录 复现Ajax跨域问题 Ajax跨域介绍 Ajax跨域解决方案 一. 在服务端添加响应头Access-Control-Allow-Origin 二. 使用JSONP ...
- PHP Ajax 跨域问题最佳解决方案 【摘自菜鸟教程】
PHP Ajax 跨域问题最佳解决方案 分类 编程技术 http://www.runoob.com/w3cnote/php-ajax-cross-border.html 本文通过设置Access-Co ...
- 基于JWT的Token身份验证
身份验证,是指通过一定的手段,完成对用户身份的确认.为了及时的识别发送请求的用户身份,我们调研了常见的几种认证方式,cookie.session和token. 1.Cookie cookie是 ...
随机推荐
- 牛客网 Wannafly挑战赛 C 列一列 简单题 (题目有点坑)
链接:https://www.nowcoder.com/acm/contest/71/C来源:牛客网 题目描述 小W在计算一个数列{An},其中A1=1,A2=2,An+2=An+1+An.尽管他计算 ...
- 【Offer】[64] 【求1+2+...+n】
题目描述 思路分析 测试用例 Java代码 代码链接 题目描述 求1+2+...+n,要求不能使用乘除法.for. while if else. switch. case等关键字及条件判断语句( A? ...
- Android源码阅读技巧--查找开发者选项中显示触摸操作源码
在开发者模式下,在开发者选项中,可以勾选“显示触摸操作”,然后只要点击屏幕就会在点击的位置有圈圈显示.如何找到绘制圈圈的代码部分,有什么技巧来阅读代码量这么大的android系统源码呢?以下请跟着小老 ...
- MYSQL学习系列
1.myslq5.7安装以及root密码找回 2.mysql之innodb存储引擎介绍 3.mysql之innodb存储引擎---数据存储结构 4.mysql之innodb存储引擎---BTREE索引 ...
- Optional和Stream的map与flatMap
Optional的map和flatMap Optional存在map和flatMap方法.map源码如下 public<U> Optional<U> map(Function& ...
- 纯css实现乌云密布的天气图标
效果 效果如下 实现思路 使用box-shadow属性画几个灰色的圆,将这些圆错落的组合在一起,形成乌云图案 after伪元素写乌云下的投影 增加动画 dom结构 用两个嵌套的div容器,父容器来 ...
- Java 开发中常用的网站地址
博客地址:http://www.moonxy.com 一.前言 在日常的开发中,通常需要访问或者设置不同的网站来获取需要的数据,不如我们都知道 Linux 系统版本比较多(例如:Ubuntu.Cent ...
- CentOS7 自定义登录前后欢迎信息
博客地址:http://www.moonxy.com 一.摘要 本人当前使用的是阿里云 ECS 服务器,操作系统为 linux,发行版为 CentOS 7.4.1708.系统默认都已经提供了欢迎信息, ...
- 网络编程之socket模块
一.TCP协议 TCP是可靠的.面向连接的协议(eg:打电话).传输效率低全双工通信(发送缓存&接收缓存).面向字节流.使用TCP的应用:Web浏览器:电子邮件.文件传输程序. 二.基于TCP ...
- python里的while循环和if循环
一.循环的概念 循环是程序设计语言中反复执行某些代码的一种计算机处理过程,常见的有按照次数循环和按条件循环. 二.循环的基本格式 (while循环的基本格式) a=1#定义一个数 while a==1 ...