http://www.thinkphp.cn/topic/67206.html
这3-4个月接触微信公众号开发比较多,偶尔需要做一些接口【内部使用】,我的上一篇文章写了:ssl协议,白名单\[ip,域名,url\],黑名单\[ip,域名,url\],请求频率\[eg:每10秒,最大请求数\],设备【电脑,手机】,终端浏览器\[微信,qq,...\],设置请求方式并禁用curl获取数据\[保证用户只能在页面使用ajax请求\];差了一个签名验证的方式,本来想做一微信的JS-SDK签名方式类似的东西;js-sdk:通过服务端生成签名,然后js前端将签名值和参与签名的参数 传递 给接口,接口进行验证 返回数据。如果模仿微信的做法,那么我好像还需要做一个获取token 和 ticket的接口,感觉使用起来挺麻烦的,而且还需要创建表格记录token,ticket. 总觉得 使用起来太耗性能了, 最近刚好看到了jwt【json web token】,于是百度了解了一下,觉得挺不错的.就在github上面搜索jwt 发现了lcobucci/jwt,然后就是composer,看了一下源码,以及简单的使用【readme.txt】,然后整理了一下。**JWT适合一次性的命令认证,颁发一个有效期极短的JWT,即使暴露了危险也很小,由于每次操作都会生成新的JWT,实现无状态**。`
1. <?php
3. namespace app\common\library;
5. useLcobucci\JWT\Builder;
6. useLcobucci\JWT\Signer\Key;
7. useLcobucci\JWT\ValidationData;
8. useLcobucci\JWT\Parser;
9. use think\Exception;
12. class JWT
13. {
14. /**
15. * 现在的4.x是发行版 测试版
16. * 使用3.3.1 稳定版本
17. * composer require lcobucci/jwt 3.3.1
18. */
19. /**
20. * 使用的加密类名称
21. * alg:
22. * 使用公钥私钥 加密对 请使用下面的类
23. * ['Lcobucci\JWT\Signer\Rsa\Sha256','Lcobucci\JWT\Signer\Rsa\Sha384','Lcobucci\JWT\Signer\Rsa\Sha512']
24. *
25. * 使用字符串密钥类【单向不可逆加密算法】 请使用下面的类
26. * ['Lcobucci\JWT\Signer\Hmac\Sha256','Lcobucci\JWT\Signer\Hmac\Sha384','Lcobucci\JWT\Signer\Hmac\Sha512']
27. *
28. * Ecdsa类 --- 在github上找了一个 BitcoinPHP/BitcoinECDSA.php[这个已经很完整了,可以单独使用] 所以不加进来
29. */
30. private $alg ='Lcobucci\JWT\Signer\Hmac\Sha256';
32. /**
33. * 用户 aud
34. */
35. private $audience;
37. /**
38. * 身份id jti
39. */
40. private $id;
42. /**
43. * 发布时间 iat
44. */
45. private $issuedAt;
47. /**
48. * 发行人 iss
49. */
50. private $issuer;
52. /**
53. * 主题 sub
54. */
55. private $subject;
57. /**
58. * 到期时间 exp
59. */
60. private $expiration;
62. /**
63. * 在此之前不可用 nbf
64. */
65. private $notBefore;
67. /**
68. * 其他私有参数设置 比如uid
69. */
70. private $claims =[];
72. /**
73. * 加密私钥 用于加密 使用[file://]+[文件路径] 比如根目录下的prikey.txt文件 eg:file://prikey.txt
74. */
75. private $privateKey =null;
77. /**
78. * 解密公钥 如果 不使用 非对称加密类进行签名 那么公钥值等于私钥值
79. * 使用[file://]+[文件路径] 比如根目录下的pubkey.txt文件 eg:file://pubkey.txt
80. */
81. private $publicKey =null;
84. publicfunction __construct($config =[])
85. {
86. if(!is_array($config)){
87. thrownewException('构造参数必须是数组');
88. }
89. $time = time();
90. $this->alg = isset($config['alg'])&&!empty($config['alg'])? $config['alg']: $this->alg;
91. $this->audience = isset($config['aud'])&&!empty($config['aud'])? $config['aud']: get_ip();
92. $this->id = isset($config['jti'])&&!empty($config['jti'])? $config['jti']: $this->getNoncestr(20);
93. $this->issuedAt = isset($config['iat'])&&!empty($config['iat'])? $config['iat']: $time;
94. $this->issuer = isset($config['iss'])&&!empty($config['iss'])? $config['iss']: $_SERVER['SERVER_NAME'];
95. $this->subject = isset($config['sub'])&&!empty($config['sub'])? $config['sub']:'无主题';
96. $this->expiration = isset($config['exp'])&&!empty($config['exp'])? $time + $config['exp']: $time +3600;
97. $this->notBefore = isset($config['nbf'])&&!empty($config['nbf'])? $config['nbf']: $time;
98. $this->privateKey = isset($config['privateKey'])&&!empty($config['privateKey'])? $config['privateKey']:null;
99. $this->publicKey = isset($config['publicKey'])&&!empty($config['publicKey'])? $config['publicKey']:null;
100. $this->claims = isset($config['claims'])&& is_array($config['claims'])? $config['claims']: $this->claims;
101. }
103. /**
104. * 使用私钥加密token
105. */
106. publicfunction getToken()
107. {
108. $token =(newBuilder())
109. ->issuedBy($this->issuer)
110. ->permittedFor($this->audience)
111. ->identifiedBy($this->id,true)
112. ->issuedAt($this->issuedAt)
113. ->relatedTo($this->subject)
114. ->canOnlyBeUsedAfter($this->notBefore)
115. ->expiresAt($this->expiration);
117. if(count($this->claims)>0){
119. for($i =0; $i < count($this->claims);++$i){
120. $token->withClaim($this->claims[$i][0], $this->claims[$i][1]);
121. }
122. }
124. if(is_null($this->privateKey)){
125. return $token->getToken();
126. }
128. $signer =new $this->alg;
129. $privateKey =newKey($this->privateKey);
131. return $token->getToken($signer, $privateKey);
132. }
134. 1. /\*\*
2. \* 验证 token 的有效性
3. \*/
4. publicfunction verify($token)
5. {
6. if(is\_null($this\->publicKey)){
7. return\['result'\=>false,'errorMsg'\=>'解密密钥不能为空'\];
8. }
9. $signer \=new $this\->alg;
10. $signer\_key \= $this\->publicKey;
11. $token \=(newParser())->parse((string) $token);
12. $data \=newValidationData();
13. // $data->setIssuer($token->getClaim('iss'));
14. // $data->setAudience($token->getClaim('aud'));
15. // $data->setId($token->getHeader('jti'));
16. // $data->setSubject($token->getClaim('sub'));
17. $data\->setIssuer($this\->issuer);
18. $data\->setAudience($this\->audience);
19. $data\->setId($this\->id);
20. $data\->setSubject($this\->subject);
21. //如果没有使用加密,那么就只验证数据
22. if($token\->getHeader('alg')!=='none'){
23. //验证密钥是否匹配【公钥私钥】
24. if(!$token\->verify($signer, $signer\_key)){
25. return\['result'\=>false,'errorMsg'\=>'密钥不对'\];
26. }
27. }
28. //验证token是否有效 数据比对不成功
29. if(!$token\->validate($data)){
30. return\['result'\=>false,'errorMsg'\=>'签名错误'\];
31. }
32. return\['result'\=>true,'msg'\=>'验证通过'\];
33. }
174. /**
175. * 生成非对称密钥对
176. * 目的:方便自己生成密钥对,可以用于测试
177. */
178. publicfunction createRsaKey($alg ="sha256", $byte =1024, $type = OPENSSL_KEYTYPE_RSA)
179. {
180. $config = array(
181. "digest_alg"=> $alg,
182. "private_key_bits"=> $byte,//512 1024 2048 4096
183. "private_key_type"=> $type,
184. );
186. // 创建公钥和私钥 密钥对
187. $res = openssl_pkey_new($config);
189. //从新建的密钥对立面获取私钥
190. openssl_pkey_export($res, $privKey);
192. //从新建的密钥对立面获取公钥
193. $pubKey = openssl_pkey_get_details($res);
194. $pubKey = $pubKey["key"];
196. return['result'=>true,'msg'=>'非对称密钥对生成成功','publicKey'=> $pubKey,'privateKey'=> $privKey];
197. }
199. /**
200. * 生成随机的字符作为本次请求的jti 识别id【标识】
201. * @param $length int
202. * 生成随机字符串
203. * 大于10位,将(当前时间戳+7200 ---- 作为有效时间)隔个字符插入
204. */
205. privatefunction getNoncestr($length =20)
206. {
207. if($length >10){
208. $strs ="QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
209. $str = substr(str_shuffle($strs), mt_rand(0, strlen($strs)- $length -1-10), $length -10);
210. $strArr = str_split($str,1);
211. $timeArr = str_split(time()+3600,1);
212. $string ="";
213. if(count($strArr)< count($timeArr)){
215. for($i =0; $i < count($timeArr);++$i){
217. if(isset($strArr[$i])){
218. $string .= $strArr[$i]. $timeArr[$i];
219. }else{
220. $string .= $timeArr[$i];
221. }
222. }
223. }else{
225. for($i =0; $i < count($strArr);++$i){
227. if(isset($timeArr[$i])){
228. $string .= $strArr[$i]. $timeArr[$i];
229. }else{
230. $string .= $strArr[$i];
231. }
232. }
233. }
234. }else{
235. $strs ="QWERTYUIOPASDFGHJKLZXCVBNM1234567890qwertyuiopasdfghjklzxcvbnm";
236. $string = substr(str_shuffle($strs), mt_rand(0, strlen($strs)- $length -1), $length);
237. }
239. return $string;
240. }
242. /**
243. * 设置属性
244. */
245. publicfunction __set($name, $val)
246. {
247. return $this->$name = $val;
248. }
250. /**
251. * 获取属性
252. */
253. publicfunction __get($name)
254. {
255. return $this->$name;
256. }
257. }
复制代码
`使用方式:`
1. //一般作为签名:那么就是分两步,一是生成令牌token,然后在前端使用,可以放到header或者作为参数[eg:$_GET] 二获取并验证token
3. //方式一 使用私钥 获取token Rsa 类
6. echo '<pre>';
8. $conf =[
9. 'privateKey'=>'file://private.txt',
10. 'alg'=>'Lcobucci\JWT\Signer\Rsa\Sha256',
11. 'exp'=>30,
12. 'sub'=>'ahai'
13. ];
15. $list =new JWT($conf);
17. /**
18. * echo $token;
19. * example:
20. * eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImp0aSI6IjgxczV2Nzc3aDJnNTM5SzBONUM5In0.eyJpc3MiOiJ0ZXN0LmNtcy5uZXQiLCJhdWQiOiIxMC4wLjAuMTU1IiwianRpIjoiODFzNXY3NzdoMmc1MzlLME41QzkiLCJpYXQiOjE1NzcyNTU0NTksInN1YiI6ImFoYWkiLCJuYmYiOjE1NzcyNTU0NTksImV4cCI6MTU3NzI1OTA1OX0.dO0SiS6-85WSnz4SiBvb-BFR3oEVarwq6gWUvlZpMoId6w8WQ3Wx6WLlOSC8MWyn1ziapnhWP9usRfS5_3XicvzKI8fIilbFgHAhAJekxGXIOYw9TB66ggTuEQH4otLJH81hBwmfM4bJkd_N67kvh1HnpMMK3rdXIaiVWP9rKog
21. */
22. $token = $list->getToken();
23. echo $token;
26. //方式一 使用公钥 解密token Rsa 类
27. echo '<pre>';
28. $conf =[
29. 'publicKey'=>'file://public.txt',
30. 'alg'=>'Lcobucci\JWT\Signer\Rsa\Sha256'
31. ];
33. $lists =new JWT($conf);
35. var_dump($lists->verify($token));
39. //方式二 使用相同的密钥作为公私钥 Hmac 类
41. $conf =[
42. 'privateKey'=>'公钥与私钥一样',
43. 'alg'=>'Lcobucci\JWT\Signer\Hmac\Sha256',
44. 'exp'=>3600
45. ];
47. $list =new JWT($conf);
49. $token = $list->getToken();
50. echo $token;
52. //方式二 使用相同的密钥作为公私钥 Hmac 类
53. $conf =[
54. 'publicKey'=>'公钥与私钥一样',
55. 'alg'=>'Lcobucci\JWT\Signer\Hmac\Sha256'
56. ];
58. $lists =new JWT($conf);
59. echo '<pre>';
60. var_dump($lists->verify($token));
63. //token是有headers + payload + signature 中间使用"."做为连接符号
64. //验证token
65. var_dump($lists->verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiIsImp0aSI6IngxeTU2N3M3STJUNWI5QzdTNU40In0.eyJpc3MiOiJ0ZXN0LmNtcy5uZXQiLCJhdWQiOiIxMC4wLjAuMTU1IiwianRpIjoieDF5NTY3czdJMlQ1YjlDN1M1TjQiLCJpYXQiOjE1NzcyNTYxNTQsInN1YiI6Ilx1NjVlMFx1NGUzYlx1OTg5OCIsIm5iZiI6MTU3NzI1NjE1NCwiZXhwIjoxNTc3MjU2MjE0fQ.-EhLYg0KlSyEMUdNJTAhk4-kcYvKr7G1_fwBWcuuEfs"));
复制代码
`ok,记录到这里。
- 空白目录1
- RBAC
- RBAC权限模型[完整]
- 你知道权限管理的RBAC模型吗?
- rbac 一个用户对应多个账号_如何设计一个强大的权限系统
- Postman 快速使用(设置环境变量)
- postman的使用方法详解!最全面的教程
- Postman常用的几个功能
- ThinkPHP项目总结
- thinkphp5 递归查询所有子代,查询上级,并且获取层级
- PHP原生项目之留言板
- 智慧校园
- PHP如何实现订单的延时处理详解
- VUE
- const {data:res} = await login(this.loginForm)
- Vue中的async和await的使用
- PHP实现消息推送(定时轮询)
- tp5 计算两个日期之间相差的天数
- 使用jquery的ajax方法获取下拉列表值
- jQuery实现select下拉框选中数据触发事件
- SetFocus 方法
- 快来了解下TP6中的超级函数app()!
- PHP socket 服务器框架 workerman
- 程序员如何才能成为独立开发者?
- PHP 错误处理
- php面向对象类中的$this,static,final,const,self及双冒号 :: 这几个关键字使用方法。
- 小白教你玩转php的闭包
- 关于TP6项目搭建的坑(多应用模式)
- ThinkPHP6.0 与5.0的差别及坑点
- axios在vue项目中的使用实例详解
- php中的类、对象、方法是指什么
- 聊一聊PHP的依赖注入(DI) 和 控制反转(IoC)
- 深入理解控制反转(IoC)和依赖注入(DI)
- Private,Public,Protected
- ThinkPHP5(目录,路径,模式设置,命名空间)
- 在 ThinkPHP6 中使用 Workerman
- 介绍thinkphp lock锁的使用和例子
- php中_initialize()函数与 __construct()函数的区别说明
- api接口数据-验证-整理
- api接口数据-验证-整理【续】
- TP6容易踩得坑【原创】
- TP6的日志怎么能记录详细的日志?
- 是否需要模型分层
- PHP面试题 全网最硬核面试题来了 2021年学习面试跳槽必备(一)
- MySQL单表数据量过千万,采坑优化记录,完美解决方案
- MySql表分区(根据时间timestamp)
- MySQL大表优化方案
- 闲言碎语
- 数据库外键的使用
- 深入理解thinkphp、laravel等框架中容器概念
- vue做前端,thinkphp6做后台,项目部署
- 简单MVC架构的PHP留言本
- TP5里面extend和vendor的区别
- 在mysql数据库中制作千万级测试表
- MySQL千万级的大表要怎么优化
- ThinkPHP关联模型操作实例分析
- lcobucci/jwt —— 一个轻松生成jwt token的插件
- RESTful API 设计指南
- MySQL如何为表字段添加索引
- ThinkPHP6.0快速开发手册(案例版)
- tp5 静态方法和普通方法的区别
- 数据字典功能
- mysql中的数据库ID主键的设置问题
- 基于角色的权限控制(django内置auth体系)
- RBAC系统经典五张表
- 什么是接口文档,如何写接口,有什么规范?
- thinkphp5.0自定义验证器