php JWT在web端中的使用方法教程


Posted in PHP onSeptember 06, 2018

解释一下JWT

JWT就是一个字符串,经过加密处理与校验处理的字符串,由三个部分组成。基于token的身份验证可以替代传统的cookie+session身份验证方法。三个部分分别如下:

header.payload.signature

header部分组成

header 格式为:

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

这就是一个json串,两个字段都是必须的,alg字段指定了生成signature的算法,默认值为 HS256,可以自己指定其他的加密算法,如RSA.经过base64encode就可以得到 header.

payload 部分组成

playload 基本组成部分:

简单点:

$payload=[
  'iss' => $issuer, //签发者
  'iat' => $_SERVER['REQUEST_TIME'], //什么时候签发的
  'exp' => $_SERVER['REQUEST_TIME'] + 7200 //过期时间
  'uid'=>1111
 ];

复杂点:官方说法,三个部分组成(Reserved claims,Public claims,Private claims)

$token = [
  #非必须。issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者。
  "iss" => "http://example.org",
  #非必须。issued at。 token创建时间,unix时间戳格式
  "iat" => $_SERVER['REQUEST_TIME'],
  #非必须。expire 指定token的生命周期。unix时间戳格式
  "exp" => $_SERVER['REQUEST_TIME'] + 7200,
  #非必须。接收该JWT的一方。
  "aud" => "http://example.com",
  #非必须。该JWT所面向的用户
  "sub" => "jrocket@example.com",
  # 非必须。not before。如果当前时间在nbf里的时间之前,则Token不被接受;一般都会留一些余地,比如几分钟。
  "nbf" => 1357000000,
  # 非必须。JWT ID。针对当前token的唯一标识
  "jti" => '222we',
  # 自定义字段
  "GivenName" => "Jonny",
  # 自定义字段
  "name" => "Rocket",
  # 自定义字段
  "Email" => "jrocket@example.com",
  
 ];

payload 也是一个json数据,是表明用户身份的数据,可以自己自定义字段,很灵活。你也可以简单的使用,比如简单的方式。经过json_encode和base64_encode就可得到payload

signature组成部分

将 header和 payload使用header中指定的加密算法加密,当然加密过程还需要自定秘钥,自己选一个字符串就可以了。
官网实例:

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

自己使用:

<?php

 public static function encode(array $payload, string $key, string $alg = 'SHA256')
 {
 $key = md5($key);
 $jwt = self::urlsafeB64Encode(json_encode(['typ' => 'JWT', 'alg' => $alg])) . '.' . self::urlsafeB64Encode(json_encode($payload));
 return $jwt . '.' . self::signature($jwt, $key, $alg);
 }

 public static function signature(string $input, string $key, string $alg)
 {
 return hash_hmac($alg, $input, $key);
 }

这三个部分使用.连接起来就是高大上的JWT,然后就可以使用了.

JWT使用流程

官方使用流程说明:

php JWT在web端中的使用方法教程

翻译一下:

  • 初次登录:用户初次登录,输入用户名密码
  • 密码验证:服务器从数据库取出用户名和密码进行验证
  • 生成JWT:服务器端验证通过,根据从数据库返回的信息,以及预设规则,生成JWT
  • 返还JWT:服务器的HTTP RESPONSE中将JWT返还
  • 带JWT的请求:以后客户端发起请求,HTTP REQUEST HEADER中的Authorizatio字段都要有值,为JWT

JWT 验证过程

因为自己写的,没有使用框架,所以还是得简单记录一下验证过程

客户端在请求头中带有JWT信息,后端获取$_SERVER[HTTP_AUTHORIZATION]:

php JWT在web端中的使用方法教程

不过注意一点,我这个Authorization没有加Bearer,官方使用中就使用了Bearer,你也可以自己使用:

Authorization: Bearer <token>

php 验证伪代码:

<?php
public static function decode(string $jwt, string $key)
 {
  $tokens = explode('.', $jwt);
  $key = md5($key);

  if (count($tokens) != 3)
   return false;

  list($header64, $payload64, $sign) = $tokens;

  $header = json_decode(self::urlsafeB64Decode($header64), JSON_OBJECT_AS_ARRAY);
  if (empty($header['alg']))
   return false;

  if (self::signature($header64 . '.' . $payload64, $key, $header['alg']) !== $sign)
   return false;

  $payload = json_decode(self::urlsafeB64Decode($payload64), JSON_OBJECT_AS_ARRAY);

  $time = $_SERVER['REQUEST_TIME'];
  if (isset($payload['iat']) && $payload['iat'] > $time)
   return false;

  if (isset($payload['exp']) && $payload['exp'] < $time)
   return false;

  return $payload;
 }

 public static function urlsafeB64Decode(string $input)
 {
  $remainder = strlen($input) % 4;

  if ($remainder)
  {
   $padlen = 4 - $remainder;
   $input .= str_repeat('=', $padlen);
  }

  return base64_decode(strtr($input, '-_', '+/'));
 }
 
 
  public static function urlsafeB64Encode(string $input)
 {
  return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
 }

JWT 在使用中的注意事项

使用了 JWT 我们一般都会考虑两点:

1. 签名是否正确?

2. Token是否到期?

这两块可以通过校验几个字段来处理

1. 建立 token 吊销机制,将 token 写入数据库,

2. 无效 token 因未入数据库,所以确信传入的 token 是有效的。

3. 对有效的 token 进行签名验证,获取到 token 后重新生成签名进行校验 token 的签名部分( C 位的值)是否一致。

4. 确认是否 token 超时可以通过 exp(expire 指定token的生命周期。unix时间戳格式) 和 nbf(not before。如果当前时间在nbf里的时间之前,则Token不被接受。unix时间戳格式。) 声明,获取到 token 后,对时间进行判断。

5. 为了防止replay attack,可加上 iss(issuer 请求实体,可以是发起请求的用户的信息,也可是jwt的签发者。),jti (JWT ID。针对当前token的唯一标识) 和 iat(issued at。 token创建时间,unix时间戳格式) 声明,然后获取到 token 后,对声明信息进行匹配。

参考文章:

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

PHP 相关文章推荐
随时给自己贴的图片加文字的php水印
Mar 16 PHP
PHP批量生成缩略图的代码
Jul 19 PHP
php下将XML转换为数组
Jan 01 PHP
基于php socket(fsockopen)的应用实例分析
Jun 02 PHP
PHP多线程类及用法实例
Dec 03 PHP
PHP中substr函数字符串截取用法分析
Jan 07 PHP
Zend Framework教程之Application和Bootstrap用法详解
Mar 10 PHP
PHP并发多进程处理利器Gearman使用介绍
May 16 PHP
PHP模拟http请求的方法详解
Nov 09 PHP
老生常谈PHP位运算的用途
Mar 12 PHP
php设计模式之适配器模式原理、用法及注意事项详解
Sep 24 PHP
laravel框架使用阿里云短信发送消息操作示例
Feb 15 PHP
php进程daemon化的正确实现方法
Sep 06 #PHP
让Laravel API永远返回JSON格式响应的方法示例
Sep 05 #PHP
thinkPHP框架实现类似java过滤器的简单方法示例
Sep 05 #PHP
PHP使用pdo实现事务处理操作示例
Sep 05 #PHP
Django 标签筛选的实现代码(一对多、多对多)
Sep 05 #PHP
利用PHP扩展Xhprof分析项目性能实践教程
Sep 05 #PHP
PHP时间处理类操作示例
Sep 05 #PHP
You might like
分享下页面关键字抓取components.arrow.com站点代码
2014/01/30 PHP
php微信公众号开发之答题连闯三关
2018/10/20 PHP
JavaScript 浏览器验证代码(来自discuz)
2010/07/17 Javascript
JS+CSS实现的日本门户网站经典选项卡导航效果
2015/09/27 Javascript
基于jQuery实现以手风琴方式展开和折叠导航菜单
2016/01/28 Javascript
jQuery 判断是否包含在数组中Array[]的方法
2016/08/03 Javascript
基于JS如何实现给字符加千分符(65,541,694,158)
2016/08/03 Javascript
js中字符型和数值型数字的互相转化方法(必看)
2017/04/25 Javascript
JavaScript中双向数据绑定详解
2017/05/03 Javascript
浅谈js获取ModelAndView值的问题
2018/03/28 Javascript
JavaScript创建对象方法实例小结
2018/09/03 Javascript
怎样在vue项目下添加ESLint的方法
2019/05/16 Javascript
ES6 Class中实现私有属性的一些方法总结
2019/07/08 Javascript
vue 指令和过滤器的基本使用(品牌管理案例)
2019/11/04 Javascript
Vue文本模糊匹配功能如何实现
2020/07/30 Javascript
vue Treeselect下拉树只能选择第N级元素实现代码
2020/08/31 Javascript
Python下实现的RSA加密/解密及签名/验证功能示例
2017/07/17 Python
python write无法写入文件的解决方法
2019/01/23 Python
带你彻底搞懂python操作mysql数据库(cursor游标讲解)
2020/01/06 Python
python重要函数eval多种用法解析
2020/01/14 Python
python GUI库图形界面开发之PyQt5单行文本框控件QLineEdit详细使用方法与实例
2020/02/27 Python
Python  word实现读取及导出代码解析
2020/07/09 Python
python中的django是做什么的
2020/07/31 Python
python爬虫快速响应服务器的做法
2020/11/24 Python
详解基于Facecognition+Opencv快速搭建人脸识别及跟踪应用
2021/01/21 Python
JACK & JONES英国官方网站:欧洲领先的男装生产商
2017/09/27 全球购物
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
秋季校运动会广播稿
2014/02/23 职场文书
2014幼儿园教师个人工作总结
2014/11/08 职场文书
小爸爸观后感
2015/06/15 职场文书
刘胡兰观后感
2015/06/16 职场文书
退休欢送会主持词
2015/07/01 职场文书
岗位聘任协议书
2015/09/21 职场文书
在 Golang 中实现 Cache::remember 方法详解
2021/03/30 Python
让JavaScript代码更加精简的方法技巧
2022/06/01 Javascript
使用CSS实现按钮边缘跑马灯动画
2023/05/07 HTML / CSS