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自定義驗證器