www.91084.com

GVKun编程网logo

php实现JWT验证的实例教程(php-jwt)

17

在本文中,我们将给您介绍关于php实现JWT验证的实例教程的详细内容,并且为您解答php-jwt的相关问题,此外,我们还将为您提供关于Angular之jwt令牌身份验证的实现、C#JWT权限验证的实现

在本文中,我们将给您介绍关于php实现JWT验证的实例教程的详细内容,并且为您解答php-jwt的相关问题,此外,我们还将为您提供关于Angular之jwt令牌身份验证的实现、C# JWT权限验证的实现、C#JWT验证、c#关于JWT跨域身份验证的实现代码的知识。

本文目录一览:

php实现JWT验证的实例教程(php-jwt)

php实现JWT验证的实例教程(php-jwt)

JWT,全称 Json web token,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

PHP实现JWT,本例使用thinkphp框架,代码如下:

在vendor包中建立Jwt.PHP,建立类文件

class Jwt {
 
 //头部
 private static $header=array(
  'alg'=>'HS256', //生成signature的算法
  'typ'=>'JWT' //类型
 );
 
 //使用HMAC生成信息摘要时所使用的密钥
 private static $key='123456';
 
 
 /**
  * 获取jwt token
  * @param array $payload jwt载荷 格式如下非必须
  * [
  * 'iss'=>'jwt_admin', //该JWT的签发者
  * 'iat'=>time(), //签发时间
  * 'exp'=>time()+7200, //过期时间
  * 'nbf'=>time()+60, //该时间之前不接收处理该Token
  * 'sub'=>'www.admin.com', //面向的用户
  * 'jti'=>md5(uniqid('JWT').time()) //该Token唯一标识
  * ]
  * @return bool|string
  */
 public static function getToken($payload)
 {
  if(is_array($payload))
  {
   $base64header=self::base64UrlEncode(json_encode(self::$header,JSON_UnesCAPED_UNICODE));
   $base64payload=self::base64UrlEncode(json_encode($payload,JSON_UnesCAPED_UNICODE));
   $token=$base64header.'.'.$base64payload.'.'.self::signature($base64header.'.'.$base64payload,self::$key,self::$header['alg']);
   return $token;
  }else{
   return false;
  }
 }
 
 
 /**
  * 验证token是否有效,默认验证exp,nbf,iat时间
  * @param string $Token 需要验证的token
  * @return bool|string
  */
 public static function verifyToken($Token)
 {
  $tokens = explode('.', $Token);
  if (count($tokens) != 3)
   return false;
 
  list($base64header, $base64payload, $sign) = $tokens;
 
  //获取jwt算法
  $base64decodeheader = json_decode(self::base64UrlDecode($base64header), JSON_OBJECT_AS_ARRAY);
  if (empty($base64decodeheader['alg']))
   return false;
 
  //签名验证
  if (self::signature($base64header . '.' . $base64payload, self::$key, $base64decodeheader['alg']) !== $sign)
   return false;
 
  $payload = json_decode(self::base64UrlDecode($base64payload), JSON_OBJECT_AS_ARRAY);
 
  //签发时间大于当前服务器时间验证失败
  if (isset($payload['iat']) && $payload['iat'] > time())
   return false;
 
  //过期时间小宇当前服务器时间验证失败
  if (isset($payload['exp']) && $payload['exp'] < time())
   return false;
 
  //该nbf时间之前不接收处理该Token
  if (isset($payload['nbf']) && $payload['nbf'] > time())
   return false;
 
  return $payload;
 }
 
 
 
 
 /**
  * base64UrlEncode https://jwt.io/ 中base64UrlEncode编码实现
  * @param string $input 需要编码的字符串
  * @return string
  */
 private static function base64UrlEncode($input)
 {
  return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
 }
 
 /**
  * base64UrlEncode https://jwt.io/ 中base64UrlEncode解码实现
  * @param string $input 需要解码的字符串
  * @return bool|string
  */
 private static function base64UrlDecode($input)
 {
  $remainder = strlen($input) % 4;
  if ($remainder) {
   $addlen = 4 - $remainder;
   $input .= str_repeat('=', $addlen);
  }
  return base64_decode(strtr($input, '-_', '+/'));
 }
 
 /**
  * HMACSHA256签名 https://jwt.io/ 中HMACSHA256签名实现
  * @param string $input 为base64UrlEncode(header).".".base64UrlEncode(payload)
  * @param string $key
  * @param string $alg 算法方式
  * @return mixed
  */
 private static function signature($input, $key, $alg = 'HS256')
 {
  $alg_config=array(
   'HS256'=>'sha256'
  );
  return self::base64UrlEncode(hash_hmac($alg_config[$alg], $input, $key,true));
 }
}

调用JWT验证的方法,代码如下:

1.构建token方法

public function maketoken(){
     $uname=$this->uname;    $currtime=time();
     if(empty($this->uname)){ echo json_encode(array('code'=>-1,'msg'=>'[主账号]参数为空'),JSON_UnesCAPED_UNICODE);    exit(); }    
     ....
     //jwt验证
     vendor("Jwt.Jwt");
     $jwt = new \Jwt();
//这里构造jwt参数,可以参照jwt规范,各字段可以自行定义内容     $payload=array('iss'=>'xesport','sub'=>'xxx_player','name'=>$playerName,'iat'=>$currtime,'jti'=>md5(uniqid('JWT').$currtime));
     $token=$jwt->getToken($payload); $this->token=$token;
     $url='http://xxx?token='.$token;
     $data=array('url'=>$url);
     
     echo json_encode(array('code'=>1,'data'=>$data,),JSON_UnesCAPED_UNICODE); exit();
 
    }

2.验证token的方法

//验证token
public function verifyToken(){
     $token=$_REQUEST['token'];
     if(empty($token)){ echo json_encode(array('code'=>-1,'msg'=>'[token]参数为空!'),JSON_UnesCAPED_UNICODE);    exit(); }
  vendor("Jwt.Jwt");
     $jwt = new \Jwt();     
     $res_token=$jwt->verifyToken($token);
  //var_dump('res_token==',$res_token);
     if(empty($res_token)){ echo json_encode(array('code'=>-2,'msg'=>'[token]验证失败!'),JSON_UnesCAPED_UNICODE);    exit(); }
     $playerName=$res_token['name'];
     //echo $playerName; die;
     这里可以写从数据库查询验证user是否存在,返回 $userInfo 
     if(empty($userInfo)){ echo json_encode(array('code'=>-3,'msg'=>'[token]验证用户无效!'),JSON_UnesCAPED_UNICODE);    exit(); }
     $data=array('username'=>$playerName);
     echo json_encode(array('code'=>1,'data'=>$data,'msg'=>'[token]验证成功'),JSON_UnesCAPED_UNICODE);    exit();
    }

这样,我们通过控制器方法调用该方法,传递参数token,就可以解析token中包含的认证凭据信息,从而做后续业务处理逻辑。

Angular之jwt令牌身份验证的实现

Angular之jwt令牌身份验证的实现

Angular之jwt令牌身份验证

demo https://gitee.com/powersky/jwt

介绍

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

起源

在讲 JWT 之前一定要讲讲基于 token 和 session 的区别。

传统的session认证

http 协议本身是一种无状态的协议,就是意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为 cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于 session 认证。

但是这种基于 session 的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于 session 认证应用的问题就会暴露出来。

工作原理

当 client 通过用户名、密码请求server并通过身份认证后,server就会生成身份认证相关的 session 数据,并且保存在内存或者内存数据库。并将对应的 sesssion_id返回给 client,client会把保存session_id(可以加密签名下防止篡改)在cookie。此后client的所有请求都会附带该session_id(毕竟默认会把cookie传给server),以确定server是否存在对应的session数据以及检验登录状态以及拥有什么权限,如果通过校验就该干嘛干嘛,否则就重新登录。

前端退出的话就清cookie。后端强制前端重新认证的话就清或者修改session。

优点与弊端

优点:

  • 相比JWT,最大的优势就在于可以主动清除session。
  • session保存在服务器端,相对较为安全。
  • 结合cookie使用,较为灵活,兼容性较好。

弊端:

每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

如果是分布式部署,需要做多机共享session机制,实现方法可将session存储到数据库中或者redis中

容易被CSRF,因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

cookie + session在跨域场景表现并不好

session、cookie、sessionStorage、localstorage的区别

session:

主要存放在服务器端,相对安全。

cookie:

可设置有效时间,默认是关闭浏览器后失效,主要存放在客户端,并且不是很安全,可存储大小约为4kb。

sessionStorage:

仅在当前会话下有效,关闭页面或浏览器后被清除。

localstorage:

除非被清除,否则永久保存。

基于JWT token的验证机制

JWT基本上由“.”分隔的三部分组成,分别是头部,有效载荷和签名。 一个简单的JWT的例子,如下所示:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySUQiOjEsImlhdCI6MTU4MTMyMjE4MCwiZXhwIjoxNTgxMzI5MzgwfQ.6PVma3dLCbiXYgBJld5McFJ-q-QydCY7YVtrKPBsRi8

这部分字符串实际上是由三部分构成的,重点使用点符号分割的,在JWT中分别代表:Header、Payload、Signature。

Header

JWT 的 Header 通常包含两个字段,分别是:typ(type) 和 alg(algorithm)。

typ: token的类型,这里固定为 JWT。

alg: 加密的算法,通常直接使用 HMAC SHA256

完整的头部声明如下:

{
 ''typ'': ''JWT'',
 ''alg'': ''HS256''
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Playload

载荷就是存放有效信息的地方,这些有效信息包含如下三个部分:

  • 标准注册声明
  • 公共声明
  • 私有声明

标准注册声明

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间。
  • nbf: 定义在什么时间之前,该 JWT 都是不可用的。
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

时间戳一般使用 unix 时间戳表示。

公共声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可解密。

私有声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

定义一个简单的 payload,如下:

{
  userID: ''1'',
  exp: ''1581329380'',
  iat: ''1581322180''
}

然后将其进行base64加密,得到JWT的第二部分。

eyJ1c2VySUQiOjEsImlhdCI6MTU4MTMyMjE4MCwiZXhwIjoxNTgxMzI5MzgwfQ

在线base64转换工具 地址。

Signature

JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64加密后的)
  • payload (base64加密后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行和secret组合加密,然后就构成了JWT的第三部分。

例如:

// javascript
var encodedString = base64UrlEncode(header) + ''.'' + base64UrlEncode(payload);

var signature = HMACSHA256(encodedString, ''secret'');

secret是保存在服务器端的,JWT的签发生成也是在服务器端的,secret就是用来进行JWT的签发和JWT的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发JWT了,那么你的程序将可能会招到攻击。

优点与弊端

优点:

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
  • 它不需要在服务端保存会话信息, 所以它易于应用的扩展。

弊端:

  • 需要设计token续签问题
  • 需要设计用户退出后token依然有效等问题
  • 密码修改后token依然有效等问题
  • 还有很多小问题,但是我觉得是利大于弊吧

一般是在请求头里加入Authorization,并加上Bearer标注:

fetch(''api/user/1'', {
 headers: {
  ''Authorization'': ''Bearer '' + token
 }
})

工作原理如图:

Angular中使用JWT进行身份验证

这里使用一TODO案例来进行演示。

设计API

  • /auth POST 提交用户名 username 和密码 password 进行登陆认证,返回 JWT 字符串。
  • /todos GET 返回待办事项清单。
  • /todos/{id} GET 返回指定的待办事项。
  • /users GET 返回用户列表。

程序操作流程简述

首先程序有一个登录界面,用户需要输入用户和用户密码。当提交表单后,前端会将数据发送到后端的 /auth 路径。后端采取合适的查询方式对这个用户进行验证,验证成功后会返回token 字符串。

后端数据声明

// 定义用户
const USERS = [
  { id: 1, username: ''vincent'', password: ''123456''},
  { id: 2, username: ''bob'', password: ''123456''},
  { id: 3, username: ''peter'', password: ''123456''},
];

// 创建TODO列表,json格式
const TODOS = [
  { id: 1, userId: 1, name: "Play LOL", completed: false },
  { id: 2, userId: 1, name: "Do homework", completed: true },
  { id: 3, userId: 2, name: "Play basketball", completed: false },
  { id: 4, userId: 3, name: "Finish Angular JWT", completed: false },
];

密码切记不能放在 payload 中的,因为这样很不安全。

后端代码实现

导入所需要的库

const _ = require(''lodash'');
const express = require(''express'')
const bodyParser = require(''body-parser'');
const jwt = require(''jsonwebtoken'');
const expressJwt = require(''express-jwt'');

定义函数

// 获取用户相关的所有Todo事项函数
function getTodos(userID) {
  var todos = _.filter(TODOS, [''userId'', userID]);
  return todos;
}

// 获取指定id的todo事项
function getTodo(todoID) {
  var todo = _.find(TODOS, (todo) => { return todo.id == todoID; })

  return todo;
}

// 获取所有用户
function getUsers() {
  let users = Array(USERS.length);
  for (let i = 0; i < USERS.length; i++) {
    users[i] = {id: USERS[i].id, username: USERS[i].username};
  }
  return users;
}

使用 expressJwt 生成 token

todo-shared-secret是秘钥字符串,这个注意一定要存储在后端。
具体代码可以到 https://gitee.com/powersky/jwt 这里来找。

实现其他的API

前端代码实现

前端主要分为以下几个部分:

服务:

  • user service 用于获取用户数据
  • todo service 用于获取todo数据
  • auth service 用于验证用户获取token
  • auth guard 用于路由守卫,判断是否能够进行路由跳转

组件:

  • user list 用户展示界面
  • todo list 用户展示todo待办事项界面
  • login 用户登录界面

下面依次展示。

user.service.ts

todo.service.ts

auth.service.ts

auth.guard.ts

UserListComponenthtml

TodoListComponenthtml

LoginComponenthtml

AppComponenthtml

AppRoutingModule

为了能够使用代理需要增加一个配置文件:

proxy.conf.json

{
 "/api/*": {
  "target": "http://localhost:4000",
  "secure": false,
  "logLevel": "debug",
  "changeOrigin": true
 }
}

然后在package.json中加入:

"name": "jwt",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"start": "ng serve --proxy-config proxy.conf.json",
"build": "ng build",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},

然后命令行执行下面命令开启前端:

npm start

执行下面命令启动后端:

node server/app.js

到此这个案例就结束了。

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

您可能感兴趣的文章:
  • python中JWT用户认证的实现
  • SpringSecurity Jwt Token 自动刷新的实现
  • 详解Django配置JWT认证方式
  • django使用JWT保存用户登录信息
  • Django如何使用jwt获取用户信息
  • 基于springboot+jwt实现刷新token过程解析
  • 浅谈ASP.NET Core 中jwt授权认证的流程原理
  • PHP如何使用JWT做Api接口身份认证的实现
  • Python 基于jwt实现认证机制流程解析

C# JWT权限验证的实现

C# JWT权限验证的实现

什么是JWT,它是一种对API的保护方案,为什么要进行保护呢

  • 防泄漏:你肯定不希望你的数据能被别人随意调用,比如公司的机密信息,不可能每个人都可以访问到
  • 防攻击:防止被人伪装恶意调用接口,利用网关就把请求拦截在外面,防止对服务器造成资源压力
  • 防止被人篡改,导致请求不到信息,防重放攻击(案例:在公共网络环境中,请求被截获,稍后被重放或多次重放)

设计原则

  • 轻量级
  • 易于开发、测试和部署
  • 适合于异构系统(跨操作系统、多语言简易实现)
  • 所有写操作接口(增、删、改 操作)
  • 非公开的读接口(如:涉密/敏感/隐私 等)

第一步:创建token

/// <summary>
        /// 创建token
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult CreateJWT1()
        {
            //创建声明Token数组
            var claim = new Claim[]
                {
                new Claim("userid","123"),
                new Claim("userCode","kevinMa"),
                new Claim("projectID","62"),
                new Claim("isValid","1"),
                new Claim("userName","马鹏"),
                new Claim("address","深圳"),
                new Claim("datetime",DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")),
                new Claim("expires",DateTime.Now.AddHours(1).ToString("yyyy-MM-dd HH:mm:ss")),
                };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("yanglingcong@qq.com"));//密钥大小要超过128bt,最少要16位

            //实例化一个token对象
            //第一种方式
            //var token = new JwtSecurityToken(claims: claim);

            //第二种方式
            var token = new JwtSecurityToken(
                issuer: "kevin",//发起人:当前项目
                audience: "kevin project",//订阅:我们需要谁去使用这个Token
                claims: claim,//声明的数组
                expires: DateTime.Now.AddHours(1),//当前时间加一小时,一小时后过期
                signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)//数字签名 第一部分是密钥,第二部分是加密方式
                );

            //生成token
            var jwtToken = new JwtSecurityTokenHandler().WriteToken(token);
            return ToSuccessJson(new { token = jwtToken });
        }

第二步:解析token

/// <summary>
        /// 解析token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPost]
        public IActionResult JXToken(string token)
        {
            
            //第一种直接用JwtSecurityTokenHandler提供的read方法
            var jwtHander = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtSecurityToken = jwtHander.ReadJwtToken(token);
            
            GetTokenModel tokenModel = new GetTokenModel();
            var currentInfo = jwtSecurityToken.Claims;
            if (currentInfo.Count() > 0)
            {
                tokenModel.userid = currentInfo.FirstOrDefault(f => f.Type == "userid").Value;
                tokenModel.userCode = currentInfo.FirstOrDefault(f => f.Type == "userCode").Value;
                tokenModel.projectID = currentInfo.FirstOrDefault(f => f.Type == "projectID").Value;
                tokenModel.userName = currentInfo.FirstOrDefault(f => f.Type == "userName").Value;
                tokenModel.address = currentInfo.FirstOrDefault(f => f.Type == "address").Value;
                tokenModel.datetime = currentInfo.FirstOrDefault(f => f.Type == "datetime").Value;
                tokenModel.expires = currentInfo.FirstOrDefault(f => f.Type == "expires").Value;
            }
            return ToSuccessJson(new { tokenModel });
        }

到此这篇关于C# JWT权限验证的实现的文章就介绍到这了,更多相关C# JWT权限验证内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

您可能感兴趣的文章:
  • C#实现JWT无状态验证的实战应用解析
  • C#基于jwt实现分布式登录
  • c#关于JWT跨域身份验证的实现代码

C#JWT验证

C#JWT验证

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using JWT;
using Newtonsoft.Json;

namespace ConsoleApplication39
{
class Program
{
static void Main(string[] args)
{
UU u = new UU() { iae = "AA", Inat = "BB", mme = "CC" };
string token = new AA().GetToken(u);
UU w = new AA().GetUU(token);
Console.Read();
}
}
class AA
{
//密钥
private string key = "glawefof";
public string GetToken(UU u)
{
JWT.Algorithms.IJwtAlgorithm Algorithm = new JWT.Algorithms.HMACSHA256Algorithm();
JWT.IJsonSerializer json = new JS();
JWT.IBase64UrlEncoder Base64 = new JWT.JwtBase64UrlEncoder();

JwtEncoder en = new JwtEncoder(Algorithm, json, Base64);
byte[] keyBytes = Encoding.UTF8.GetBytes(key);
return en.Encode(u, keyBytes);
}

public UU GetUU(string token)
{
IJsonSerializer js = new JS();
IJwtValidator validator = new JwtValidator(js, new JWT.UtcDateTimeProvider());
JWT.IBase64UrlEncoder Base64 = new JWT.JwtBase64UrlEncoder();
JwtDecoder en = new JwtDecoder(js,validator, Base64);
return en.DecodeToObject<UU>(token);
}
}
class UU
{
public string mme { get; set; }
public string Inat { get; set; }
public string iae { get; set; }
}

class JS : JWT.IJsonSerializer
{
public T Deserialize<T>(string json)
{
return JsonConvert.DeserializeObject<T>(json);
}

public string Serialize(object obj)
{
return JsonConvert.SerializeObject(obj);
}
}
}

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

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中传输。

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

您可能感兴趣的文章:
  • C# winform登陆框验证码的实现方法
  • C#实现发送手机验证码功能
  • C#生成漂亮验证码完整代码类
  • C#实现JWT无状态验证的实战应用解析

今天关于php实现JWT验证的实例教程php-jwt的讲解已经结束,谢谢您的阅读,如果想了解更多关于Angular之jwt令牌身份验证的实现、C# JWT权限验证的实现、C#JWT验证、c#关于JWT跨域身份验证的实现代码的相关知识,请在本站搜索。

本文标签: