c#关于JWT跨域身份验证的实现代码

 更新时间:2019年10月16日 09:09:08   作者:流月无双  
这篇文章主要介绍了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>(3);

      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(10).ToUnixTimeSeconds() },//到期时间
        { "sub", "testJWT" }, //主题
        { "aud", "USER" }, //用户
        { "iat", DateTime.Now.ToString() }, //发布时间 
        { "data" ,new { name="111",age=11,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中传输。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Base64编码解码原理及C#编程实例

    Base64编码解码原理及C#编程实例

    这篇文章主要介绍了Base64编码解码原理及C#编程实例,本文讲解了Base64编码由来、Base64编码原理、C#编程实现,需要的朋友可以参考下
    2014-10-10
  • 区分WCF与WebService的异同、优势

    区分WCF与WebService的异同、优势

    这篇文章主要帮助大家区分WCF与WebService的异同、优势,分为三大方面进行研究学习,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • C#实现字符串转换成字节数组的简单实现方法

    C#实现字符串转换成字节数组的简单实现方法

    这篇文章主要介绍了C#实现字符串转换成字节数组的简单实现方法,仅一行代码即可搞定,非常简单实用,需要的朋友可以参考下
    2015-05-05
  • C#生成随机数实例

    C#生成随机数实例

    这篇文章主要介绍了C#生成随机数的方法,实例分析了随机数的生成原理与使用技巧,需要的朋友可以参考下
    2015-01-01
  • 自定义时间格式转换代码分享

    自定义时间格式转换代码分享

    自定义时间格式转换,如"2012年5月14日"的日期字符串,大家参考使用吧
    2013-12-12
  • 详解c# 委托链

    详解c# 委托链

    这篇文章主要介绍了c# 委托链的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • 详解C# 利用反射根据类名创建类的实例对象

    详解C# 利用反射根据类名创建类的实例对象

    这篇文章主要介绍了详解C# 利用反射根据类名创建类的实例对象,“反射”其实就是利用程序集的元数据信息,感兴趣的小伙伴们可以参考一下。
    2017-03-03
  • unity与vue交互(无第三方插件)

    unity与vue交互(无第三方插件)

    这篇文章主要讲述了如何使用vue在通过不是用第三方插件的情况下与Unity进行交互,该篇包含详细的图文讲解,内容比较详细,希望对你有所帮助
    2021-06-06
  • C#中using语句的用法

    C#中using语句的用法

    这篇文章介绍了C#中using语句的用法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-03-03
  • Unity实现UI光晕效果(发光效果)

    Unity实现UI光晕效果(发光效果)

    这篇文章主要为大家详细介绍了Unity实现UI光晕效果,发光效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-01-01

最新评论