gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区

站長資訊網
最全最豐富的資訊網站

uni-app 小程序 Laravel+jwt 權限認證系列

uni-app開發教程欄目介紹系列權限認證的方法。

uni-app 小程序 Laravel+jwt 權限認證系列

推薦:uni-app開發教程

環境說明

uni-app
laravel 5.7 + jwt-auth 1.0.0

權限認證整體說明

  1. 設計表結構
  2. 前端 request 類
  3. 有關權限認證的 js 封裝 包含無感知刷新 token
  4. laravel auth 中間件 包含無感知刷新 token
  5. 獲取手機號登陸
  6. 無痛刷新 access_token 思路
  7. 小程序如何判斷登陸狀態

設計表結構

和一般設計表沒有什么區別,如果是多平臺小程序,通過 account_id 關聯聯合表。

CREATE TABLE `users` (   `u_id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '賬號id',   `u_username` varchar(15) NOT NULL DEFAULT '' COMMENT '手機號隱藏 ',   `u_nickname` varchar(15) NOT NULL COMMENT '分配用戶名',   `u_headimg` varchar(200) DEFAULT NULL COMMENT '頭像',   `u_province` varchar(50) DEFAULT NULL,   `u_city` varchar(50) DEFAULT NULL,   `u_platform` varchar(30) NOT NULL COMMENT '平臺:小程序wx,bd等',   `u_mobile` char(11) NOT NULL COMMENT '手機號必須授權',   `u_openid` varchar(100) DEFAULT NULL COMMENT 'openid',   `u_regtime` timestamp NULL DEFAULT NULL COMMENT '注冊時間',   `u_login_time` timestamp NULL DEFAULT NULL COMMENT '最后登陸時間',   `u_status` tinyint(3) unsigned NOT NULL DEFAULT '1' COMMENT '0禁用1正常',   `account_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '平臺聯合id',   PRIMARY KEY (`u_id`),   KEY `platform` (`u_platform`,`u_mobile`) USING BTREE) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

2. 前端 request 類

一個較不錯的 request 類 luch-request ,支持動態修改配置、攔截器,在 uni-app 插件市場可以找到。
uni-app 小程序 Laravel+jwt 權限認證系列
其中 request.js 不需要更改。自定義邏輯在 index.js。
index.js

import Request from './request';import jwt from '@/utils/auth/jwt.js'; // jwt 管理 見下文const http = new Request();const baseUrl = 'http://xxx'; // api 地址var platform = ''; // 登陸時需知道來自哪個平臺的小程序用戶// #ifdef MP-BAIDUplatform = 'MP-BAIDU';// #endif/* 設置全局配置 */http.setConfig((config) => {    config.baseUrl = baseUrl; //設置 api 地址   config.header = {     ...config.header  }   return config})/* 請求之前攔截器 */http.interceptor.request((config, cancel) => {     if (!platform) {cancel('缺少平臺參數');}     config.header = {         ...config.header,         platform:platform    }    if (config.custom.auth) {       // 需要權限認證的路由 需攜帶自定義參數 {custom: {auth: true}}     config.header.Authorization = jwt.getAccessToken();   }   return config})http.interceptor.response(async (response) => { /* 請求之后攔截器 */     console.log(response);     // 如果是需要權限認證的路由     if(response.config.custom.auth){              if(response.data.code == 4011){                 // 刷新 token                 jwt.setAccessToken(response.data.data.access_token);                 // 攜帶新 token 重新請求                 let repeatRes = await http.request(response.config);                 if ( repeatRes ) {                     response = repeatRes;                 }             }      }     return response}, (response) => { // 請求錯誤做點什么     if(response.statusCode == 401){         getApp().globalData.isLogin = false;         uni.showToast({icon:'none',duration:2000,title: "請登錄"})     }else if(response.statusCode == 403){         uni.showToast({             title: "您沒有權限進行此項操作,請聯系客服。",             icon: "none"         });     }   return response})export {   http}

全局掛載

import Vue from 'vue'import App from './App'import { http } from '@/utils/luch/index.js' //這里Vue.prototype.$http = http  Vue.config.productionTip = falseApp.mpType = 'app'const app = new Vue({     ...App})app.$mount()

3.有關權限認證的 js 封裝

authorize.js

篇幅原因,沒有貼完整的代碼,其他并沒有使用到。比如 uni.checkSession(),由于使用 jwt 接管了小程序的登陸態,所以目前沒有用到這個方法。

// #ifndef H5const loginCode = provider => {     return new Promise((resolve, reject) => {         uni.login({             provider: provider,             success: function(loginRes) {                 if (loginRes && loginRes.code) { resolve(loginRes.code) } else { reject("獲取code失敗") }             },             fail:function(){ reject("獲取code失敗")}         });     })}// #endifexport {     loginCode //登錄獲取code}

jwt.js

專門管理 access_token 的,代碼不多,同時將 userinfo 的管理也放在里面。

const tokenKey = 'accessToken';//鍵值const userKey    = 'user'; // 用戶信息// tokenconst getAccessToken = function(){     let token='';     try {token = 'Bearer '+ uni.getStorageSync(tokenKey);} catch (e) {}     return token;}const setAccessToken = (access_token) => {     try {uni.setStorageSync(tokenKey, access_token);return true;} catch (e) {return false;}}const clearAccessToken = function(){     try {uni.removeStorageSync(tokenKey);} catch (e) {}}// userinfoconst setUser = (user)=>{     try {uni.setStorageSync(userKey, user);return true;} catch (e) {return false;}}const getUser = function(){     try {return uni.getStorageSync(userKey)} catch (e) {return false;}}const clearUser = function(){     try {uni.removeStorageSync(userKey)} catch (e) {}}export default {   getAccessToken,setAccessToken,clearAccessToken,getUser,setUser,clearUser}

auth.js

只處理 login ,為什么單獨放在一個文件,沒別的,因為到處都用到

import {loginCode} from '@/utils/auth/authorize.js';import jwt from '@/utils/auth/jwt.js';import {http} from '@/utils/luch/index.js';const login=function(detail){     return new Promise((resolve, reject) => {         loginCode().then(code=>{             detail.code = code;             return http.post('/v1/auth/login',detail);         })         .then(res=>{             jwt.setAccessToken(res.data.data.access_token);             jwt.setUser(res.data.data.user);             getApp().globalData.isLogin = true;             resolve(res.data.data.user);         })         .catch(err=>{             reject('登陸失敗')         })     })}export default {login}

4. laravel auth 中間件

這里叨叨一點 jwt-auth 方面的。1,當一個token過期并進行了刷新token,那么原token會被列在“黑名單”,即失效了。實際上 jwt-auth 也維護了一個文件來儲存黑名單,而達到刷新時間上限才會清理失效的token。例如過期時間為10分鐘,刷新上限為一個月,這期間會產生大量的黑名單,影響性能,所以盡量的調整,比如過期時間為60分鐘,刷新上限為兩周,或者過期時間一周,刷新上限一個月都沒有問題的。2,關于無痛刷新方案,當token過期時,我采用的前端兩次請求完成刷新,其中用戶是無感知的,網上有直接一次請求自動刷新并登陸的方案,我沒有采用,至于為什么,沒別的,看不懂。不過我整理了各種 jwt 各種 exception ,需要的同學可以自定義。TokenExpiredException 過期、TokenInvalidException 無法解析令牌、UnauthorizedHttpException 未攜帶令牌、JWTException 令牌失效或者達到刷新上限或jwt內部錯誤。

<?phpnamespace AppHttpMiddleware;use AppLibraryY;use Closure;use Exception;use TymonJWTAuthExceptionsJWTException;use TymonJWTAuthHttpMiddlewareBaseMiddleware;use TymonJWTAuthExceptionsTokenExpiredException;class ApiAuth extends BaseMiddleware{      public function handle($request, Closure $next, $guard = 'api')     {         // 在排除名單中 比如登錄         if($request->is(...$this->except)){             return $next($request);         }          try {             $this->checkForToken($request);// 是否攜帶令牌             if ( $this->auth->parseToken()->authenticate() ) {                 return $next($request); //驗證通過             }         }catch(Exception $e){             // 如果token 過期             if ($e instanceof TokenExpiredException) {                 try{                     // 嘗試刷新 如果成功 返給前端 關于前端如何處理的 看前邊 index.js                     $token = $this->auth->refresh();                     return Y::json(4011, $e->getMessage(),['access_token'=>$token]);                 }catch(JWTException $e){                     // 達到刷新時間上限                     return Y::json(401, $e->getMessage());                 }             }else{                 // 其他各種 直接返回 401 狀態碼 不再細分                 return Y::json(401, $e->getMessage());             }         }     }      protected $except = [         'v1/auth/login',     ];}

筆者認為這種刷新很不好維護,直接使用一次性token,過期直接重新登錄比較好,視小程序或網站是否要求極強的安全性而定,一般不需求很高的安全性,https請求下一次性token更好,這里的中間件只需要 auth()->check(),true 即登錄狀態,false 即未登錄。

5. 獲取手機號登陸

<template>     <view>         <button type="default" open-type="getPhoneNumber" @getphonenumber="decryptPhoneNumber">獲取手機號</button>         <button @tap="me">獲取用戶數據</button>         <button @tap="clear">清除用戶數據</button>     </view></template><script>     import auth from '@/utils/auth/auth.js';     import jwt from '@/utils/auth/jwt.js';     var _self;     export default{         data() {return {}},         onLoad(option) {},         onShow(){},         methods: {             decryptPhoneNumber: function(e){                 // console.log(e.detail);                 if( e.detail.errMsg == "getPhoneNumber:ok" ){ //成功                     auth.login(e.detail);                 }             },             me: function(){                 this.$http.get('/v1/auth/me',{custom: {auth: true}}).then(res=>{                     console.log(res,'success')                 }).catch(err=>{                     console.log(err,'error60')                 })             },             clear: function(){                 jwt.clearAccessToken();                 jwt.clearUser();                 uni.showToast({                     icon: 'success',                     title: '清除成功',                     duration:2000,                 });             }         },         components: {}     }</script><style></style>

后端

// 登陸     public function login(Request $request)     {         $platform = $request->header('platform');         if(!$platform || !in_array($platform,User::$platforms)){             return Y::json(1001, '不支持的平臺類型');         }         $post = $request->only(['encryptedData', 'iv', 'code']);         $validator = Validator::make($post, [             'encryptedData' => 'required',             'iv'            => 'required',             'code'          => 'required'         ]);         if ($validator->fails()) {return Y::json(1002,'非法請求');}         switch ($platform) {             case 'MP-BAIDU':                 $decryption = (new BdDataDecrypt())->decrypt($post['encryptedData'],$post['iv'],$post['code']);                 break;             default:                 $decryption = false;                 break;         }         // var_dump($decryption);         if($decryption !== false){             $user = User::where('u_platform',$platform)->where('u_mobile',$decryption['mobile'])->first();             if($user){                 $user->u_login_time = date('Y-m-d H:i:s',time());                 $user->save();             }else{                 $user = User::create([                     'u_username'=> substr_replace($decryption['mobile'],'******',3,6),                     'u_nickname'=> User::crateNickName(),                     'u_platform'=> $platform,                     'u_mobile'   => $decryption['mobile'],                     'u_openid'  => $decryption['openid'],                     'u_regtime' => date('Y-m-d H:i:s',time())                 ]);             }              $token = auth()->login($user);             return Y::json(                 array_merge(                     $this->respondWithToken($token),                     ['user'=>['nickName'=>$user->u_nickname]]                 )             );         }         return Y::json(1003,'登錄失敗');      }     // 返回 token     protected function respondWithToken($token)     {         return ['access_token' => $token];     }

手機號碼解密

<?phpnamespace AppLibrary;use AppLibraryY;class BdDataDecrypt{      private $_appid;     private $_app_key;     private $_secret;     private $_session_key;      public function __construct()     {         $this->_appid       = env('BD_APPID');         $this->_app_key     = env('BAIDU_KEY');         $this->_secret      = env('BD_SECRET');     }      public function decrypt($encryptedData, $iv, $code){         $res = $this->getSessionKey($code);         if($res === false){return false;}         $data['openid'] = $res['openid'];         $res = $this->handle($encryptedData,$iv,$this->_app_key,$res['session_key']);         if($res === false){return false;}         $res = json_decode($res,true);         $data['mobile'] = $res['mobile'];         return $data;      }      public function getSessionKey($code)     {         $params['code']         = $code;         $params['client_id']     = $this->_app_key;         $params['sk']             = $this->_secret;         $res = Y::curl("https://spapi.baidu.com/oauth/jscode2sessionkey",$params,0,1);         // var_dump($res);         /**          * 錯誤返回          * array(3) {             ["errno"]=>             int(1104)             ["error"]=>             string(33) "invalid code , expired or revoked"             ["error_description"]=>             string(33) "invalid code , expired or revoked"             }             成功返回:             array(2) {                 ["openid"]=>                 string(26) "z45QjEfvkUJFwYlVcpjwST5G8w"                 ["session_key"]=>                 string(32) "51b9297ababbcf43c1a099256bf82d75"             }          */         if( isset($res['error']) ){             return false;         }         return $res;     }      /**      * 官方 demo      * return string(24) "{"mobile":"18288881111"}" or false      */     private function handle($ciphertext, $iv, $app_key, $session_key)     {         $session_key = base64_decode($session_key);         $iv = base64_decode($iv);         $ciphertext = base64_decode($ciphertext);          $plaintext = false;         if (function_exists("openssl_decrypt")) {             $plaintext = openssl_decrypt($ciphertext, "AES-192-CBC", $session_key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv);         } else {             $td = mcrypt_module_open(MCRYPT_RIJNDAEL_128, null, MCRYPT_MODE_CBC, null);             mcrypt_generic_init($td, $session_key, $iv);             $plaintext = mdecrypt_generic($td, $ciphertext);             mcrypt_generic_deinit($td);             mcrypt_module_close($td);         }         if ($plaintext == false) {             return false;         }         // trim pkcs#7 padding         $pad = ord(substr($plaintext, -1));         $pad = ($pad < 1 || $pad > 32) ? 0 : $pad;         $plaintext = substr($plaintext, 0, strlen($plaintext) - $pad);         $plaintext = substr($plaintext, 16);         $unpack = unpack("Nlen/", substr($plaintext, 0, 4));         $content = substr($plaintext, 4, $unpack['len']);         $app_key_decode = substr($plaintext, $unpack['len'] + 4);         return $app_key == $app_key_decode ? $content : false;     }}

6. 無痛刷新 access_token 思路

先說我使用的方法是,后端判斷 token 過期后,自動嘗試刷新,刷新成功返回新的 token,前端在響應攔截器里,捕獲到后端響應的約定 code,把新的 token 存儲,并且緊接著二次請求,最終感知上是一次正常的請求。
另外一種思路,后端嘗試刷新成功后,自動為當前用戶登陸,并在 header 中返回新 token,前端只負責存儲。

7. 小程序如何判斷登陸狀態

其實思路也很簡單,非前后端分離怎么做的,前后端分離就怎么做,原理一樣。非前后端分離,在每次請求時都會讀取 session ,那么前后端分離,更好一些,有些公開請求不走中間件,也就無需判斷登陸態,只有在需要權限認證的頁面,在頁面初始化時發出一次請求走中間件,以此判斷登陸狀態。
定義全局登陸檢查函數

import jwt from '@/utils/auth/jwt.js';Vue.prototype.checkLogin = function(){     var TOKEN  = jwt.getAccessToken();     return new Promise((resolve, reject) => {         if(TOKEN){             http.get('/v1/auth/check',{custom: {auth: true}}).then(res=>{                 // 通過中間件 一定是登陸態                 resolve(true);             }).catch(err=>{                 resolve(false);                 console.log(err) // 這里是401 403 后端500錯誤或者網絡不好             })         }else{             resolve(false) //沒有token 一定是未登陸         }     })}

筆者最終放棄上面的這種檢查登錄的方式,直接檢驗storage中有user和token即視為登錄狀態。以被動的驗證代替主動去驗證,就是說用戶執行一個請求,返回401,那么就改變登錄狀態。以后再補充。

前端

<script>     export default {         data() {             return {                 isLogin:null             }         },         onLoad() {             this.checkLogin().then(loginStatus=>{                 this.isLogin = loginStatus;             });         },         methods: {         },         components: {}     }</script>

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
gmnon.cn-疯狂蹂躏欧美一区二区精品,欧美精品久久久久a,高清在线视频日韩欧美,日韩免费av一区二区
成年人在线看片| 国产精品久久久久久9999| 中文字幕国产高清| 91精品无人成人www| 亚洲中文字幕无码不卡电影| 丝袜人妻一区二区三区| 色婷婷777777仙踪林| 一级做a爱视频| 日韩第一页在线观看| 三级一区二区三区| 日本精品www| caoporn超碰97| 蜜臀视频一区二区三区| 91极品尤物在线播放国产| av网址在线观看免费| 不卡av免费在线| 色一情一区二区| 亚洲天堂伊人网| 欧美精品一区二区性色a+v| 9999在线观看| 无码人妻aⅴ一区二区三区日本| 欧美一级特黄aaa| 欧美性猛交内射兽交老熟妇| 成人午夜精品久久久久久久蜜臀| 国产午夜大地久久| 精品久久久久久久无码| 婷婷激情5月天| 免费看欧美黑人毛片| 美女av免费在线观看| 久久久久久久片| 麻豆映画在线观看| 少妇高潮喷水久久久久久久久久| 自拍偷拍21p| 真人做人试看60分钟免费| 97在线播放视频| 日韩一级理论片| 五月花丁香婷婷| 青草网在线观看| 欧美视频亚洲图片| 手机在线免费毛片| 激情成人在线观看| 黄色一级片网址| 中文字幕综合在线观看| 亚洲欧美日本一区二区三区| 在线黄色免费看| 欧美一级黄色影院| 男人日女人的bb| 久草精品在线播放| 精品无码av无码免费专区| 色诱视频在线观看| 国产情侣第一页| 天美一区二区三区| 美女黄色片视频| 国产 日韩 欧美在线| 欧美国产日韩另类 | av亚洲天堂网| 日韩av资源在线| 麻豆tv在线播放| 成人高清dvd| 欧美少妇在线观看| 男同互操gay射视频在线看| 国产精品一区二区小说| 亚欧在线免费观看| 激情内射人妻1区2区3区 | 精品少妇人妻av免费久久洗澡| 在线播放 亚洲| 欧美午夜精品理论片| 男女视频在线看| 国产精品v日韩精品v在线观看| 成年人黄色片视频| 亚洲中文字幕无码不卡电影| 日本免费黄色小视频| 久国产精品视频| 国产极品在线视频| 亚洲理论电影在线观看| 亚洲高潮无码久久| 免费在线看黄色片| 男人c女人视频| 亚洲精品mv在线观看| 另类小说第一页| 日韩免费高清在线| 中国丰满人妻videoshd| 免费人成自慰网站| 香蕉精品视频在线| 男女h黄动漫啪啪无遮挡软件| 爱情岛论坛亚洲首页入口章节| 91制片厂免费观看| 欧美亚洲日本在线观看| 中国一级大黄大黄大色毛片| 已婚少妇美妙人妻系列| 奇米影视亚洲色图| 中文字幕日本最新乱码视频| 国产精品无码av在线播放| 人妻激情另类乱人伦人妻| 无码少妇一区二区三区芒果| 欧美日韩激情视频在线观看| 日韩av综合在线观看| 国产av国片精品| 国产精品无码一区二区在线| 亚洲啊啊啊啊啊| 一区二区三区四区久久| 亚洲三级视频网站| 图片区乱熟图片区亚洲| 91看片淫黄大片91| 成熟丰满熟妇高潮xxxxx视频| 国内精品视频一区二区三区| aaaaaa亚洲| 污视频网址在线观看| 久久久久久久免费视频| 日韩高清在线一区二区| 中文字幕日本最新乱码视频| 一区二区三区免费播放| 女同性恋一区二区| 欧美日韩在线不卡视频| 中文字幕视频三区| 国产精品自拍合集| 91 在线视频观看| 交换做爰国语对白| 亚洲三级视频网站| 亚洲国产一二三精品无码 | 亚洲美女性囗交| 国产又粗又猛又爽又黄的网站| 无码aⅴ精品一区二区三区浪潮 | 四虎免费在线观看视频| 欧美 日本 亚洲| 91免费视频黄| 亚洲第一区第二区第三区| 日韩一级片播放| 韩国无码av片在线观看网站| 无码内射中文字幕岛国片| 国产尤物av一区二区三区| 亚洲久久中文字幕| 男人亚洲天堂网| www.国产二区| 男女污污视频网站| 欧美啪啪免费视频| 国产精品专区在线| 国产一二三区在线播放| 亚洲成人动漫在线| 精品国产一区二区三区在线| 国产精品亚洲a| 青青在线视频免费观看| 日韩人妻无码精品久久久不卡| 蜜臀av无码一区二区三区| 亚洲国产精品久久久久婷蜜芽| 五月天婷婷激情视频| 国内自拍在线观看| 欧美在线观看黄| 中文字幕免费高清在线| 精产国品一二三区| 2021狠狠干| 福利视频免费在线观看| 欧美国产日韩在线播放| 极品美女扒开粉嫩小泬| 日韩欧美猛交xxxxx无码| 毛葺葺老太做受视频| 国产精品-区区久久久狼| 日本毛片在线免费观看| 日批视频在线免费看| 999香蕉视频| 日韩av片在线看| 日本美女高潮视频| 午夜剧场在线免费观看| www.五月天色| 国产91在线亚洲| 亚洲天堂2018av| 黄色手机在线视频| 四虎1515hh.com| 大荫蒂性生交片| 欧美视频在线播放一区| 国产激情在线观看视频| 午夜剧场高清版免费观看 | 日本中文字幕亚洲| av黄色在线网站| 日本不卡一区二区在线观看| 超碰中文字幕在线观看| 粉嫩虎白女毛片人体| 爆乳熟妇一区二区三区霸乳| 中文av字幕在线观看| 激情五月婷婷六月| 亚洲中文字幕久久精品无码喷水| 五月天婷婷影视| 精品久久久久久久久久中文字幕| 国产无限制自拍| 狠狠操狠狠干视频| av在线免费观看国产| 欧美日韩在线中文| 日韩欧美猛交xxxxx无码| 青青在线免费观看视频| 成人性做爰片免费视频| 日av中文字幕| 日本中文字幕一级片| 999精彩视频| 成熟丰满熟妇高潮xxxxx视频| 国产一级不卡毛片| 国产午夜伦鲁鲁| 日韩一二区视频| 国产成人美女视频| 日韩国产欧美亚洲| 小泽玛利亚av在线|