Table of Contents
Environment Description" >Environment Description
Overall description of authority authentication" >Overall description of authority authentication
Design table structure" >Design table structure
2. Front-end request class" >2. Front-end request class
3. JS encapsulation related to authority authentication" >3. JS encapsulation related to authority authentication
4. laravel auth middleware" >4. laravel auth middleware
6. Painless refresh of access_token idea" >6. Painless refresh of access_token idea
Home Web Front-end uni-app uni-app applet Laravel+jwt authority authentication series

uni-app applet Laravel+jwt authority authentication series

Nov 27, 2020 pm 05:15 PM
uni-app Applets Authority authentication

uni-app Development Tutorial column introduces a series of permission authentication methods.

uni-app applet Laravel+jwt authority authentication series

Recommended: ##uni-app development tutorial

uni-app
laravel 5.7 jwt- auth 1.0.0

    Design table structure
  1. Front-end request class
  2. The js package related to permission authentication contains a non-aware refresh token
  3. laravel auth middleware contains a non-aware refresh token
  4. Get the mobile phone number to log in
  5. Painless refresh access_token idea
  6. How to determine the login status of the mini program
There is no difference from the general design table. If it is a multi-platform mini program , associate the federated table through 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;
Copy after login
A relatively good request class

luch-request supports dynamic modification of configuration and interceptors , can be found in the uni-app plug-in market.
uni-app applet Laravel+jwt authority authentication seriesrequest.js does not need to be changed. Custom logic is in 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}
Copy after login

Global mount

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()
Copy after login

authorize.js

Due to space reasons, the complete code is not posted and the others are not used. For example, uni.checkSession(), because jwt is used to take over the login state of the applet, this method is not currently used.

// #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}
Copy after login

jwt.js

Specializes in managing access_token, not much code, and also puts userinfo management in it.

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}
Copy after login

auth.js

Only handles login, why put it in a separate file, nothing else, because it is used everywhere

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}
Copy after login
Here is a little bit about jwt-auth. 1. When a token expires and the token is refreshed, the original token will be listed in the "blacklist" and become invalid. In fact, jwt-auth also maintains a file to store the blacklist, and invalid tokens will be cleared only when the refresh time limit is reached. For example, the expiration time is 10 minutes, and the refresh limit is one month. During this period, a large number of blacklists will be generated, which will affect performance, so try to adjust as much as possible. For example, the expiration time is 60 minutes, the refresh limit is two weeks, or the expiration time is one week, and the refresh limit is No problem for a month. 2. Regarding the painless refresh solution, when the token expires, the front end I use makes two requests to complete the refresh, of which the user is unaware. There is a solution on the Internet that directly requests automatic refresh and login, but I did not use it. As for why, I don’t know. I can't understand anything else. However, I have compiled various jwt exceptions, and students can customize them if needed. TokenExpiredException expires, TokenInvalidException cannot parse the token, UnauthorizedHttpException does not carry the token, JWTException the token is invalid or the refresh limit is reached or jwt internal error.

<?phpnamespace  App\Http\Middleware;use App\Library\Y;use Closure;use Exception;use Tymon\JWTAuth\Exceptions\JWTException;use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;use Tymon\JWTAuth\Exceptions\TokenExpiredException;class ApiAuth extends BaseMiddleware{

    public function handle($request, Closure $next, $guard = &#39;api&#39;)
    {
        // 在排除名单中 比如登录
        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',
    ];}
Copy after login
The author thinks that this kind of refresh is very difficult to maintain. It is better to use a one-time token directly. It is better to log in again after expiration. It depends on whether the mini program or website requires strong security. Generally, high security is not required. It is better to use a one-time token for https request. The middleware here only needs auth()->check(), true means logged in status, false means not logged in.

5. Get the mobile phone number to log in
<template>
    <view>
        <button>获取手机号</button>
        <button>获取用户数据</button>
        <button>清除用户数据</button>
    </view></template><script>
    import auth from &#39;@/utils/auth/auth.js&#39;;
    import jwt from &#39;@/utils/auth/jwt.js&#39;;
    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(&#39;/v1/auth/me&#39;,{custom: {auth: true}}).then(res=>{
                    console.log(res,&#39;success&#39;)
                }).catch(err=>{
                    console.log(err,&#39;error60&#39;)
                })
            },
            clear: function(){
                jwt.clearAccessToken();
                jwt.clearUser();
                uni.showToast({
                    icon: &#39;success&#39;,
                    title: &#39;清除成功&#39;,
                    duration:2000,
                });
            }
        },
        components: {}
    }</script><style></style>
Copy after login

Backend

// 登陆
    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];
    }
Copy after login

Mobile phone number decryption

<?phpnamespace  App\Library;use App\Library\Y;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  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;
    }}
Copy after login
First of all, the method I use is that after the backend determines that the token has expired, it automatically tries to refresh it, and the refresh returns successfully. For the new token, the front-end captures the agreed code of the back-end response in the response interceptor, stores the new token, and then makes a second request. In the end, it is perceived as a normal request.

Another way of thinking is that after the backend attempts to refresh successfully, it will automatically log in for the current user and return the new token in the header. The frontend is only responsible for storage.

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 一定是未登陆
        }
    })}
Copy after login

笔者最终放弃上面的这种检查登录的方式,直接检验storage中有user和token即视为登录状态。以被动的验证代替主动去验证,就是说用户执行一个请求,返回401,那么就改变登录状态。以后再补充。

前端

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

                                                       

The above is the detailed content of uni-app applet Laravel+jwt authority authentication series. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

AI Hentai Generator

AI Hentai Generator

Generate AI Hentai for free.

Hot Article

R.E.P.O. Energy Crystals Explained and What They Do (Yellow Crystal)
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Best Graphic Settings
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. How to Fix Audio if You Can't Hear Anyone
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Develop WeChat applet using Python Develop WeChat applet using Python Jun 17, 2023 pm 06:34 PM

With the popularity of mobile Internet technology and smartphones, WeChat has become an indispensable application in people's lives. WeChat mini programs allow people to directly use mini programs to solve some simple needs without downloading and installing applications. This article will introduce how to use Python to develop WeChat applet. 1. Preparation Before using Python to develop WeChat applet, you need to install the relevant Python library. It is recommended to use the two libraries wxpy and itchat here. wxpy is a WeChat machine

Can small programs use react? Can small programs use react? Dec 29, 2022 am 11:06 AM

Mini programs can use react. How to use it: 1. Implement a renderer based on "react-reconciler" and generate a DSL; 2. Create a mini program component to parse and render DSL; 3. Install npm and execute the developer Build npm in the tool; 4. Introduce the package into your own page, and then use the API to complete the development.

How to develop uni-app in VSCode? (Tutorial sharing) How to develop uni-app in VSCode? (Tutorial sharing) May 13, 2022 pm 08:11 PM

How to develop uni-app in VSCode? The following article will share with you a tutorial on developing uni-app in VSCode. This may be the best and most detailed tutorial. Come and take a look!

Implement card flipping effects in WeChat mini programs Implement card flipping effects in WeChat mini programs Nov 21, 2023 am 10:55 AM

Implementing card flipping effects in WeChat mini programs In WeChat mini programs, implementing card flipping effects is a common animation effect that can improve user experience and the attractiveness of interface interactions. The following will introduce in detail how to implement the special effect of card flipping in the WeChat applet and provide relevant code examples. First, you need to define two card elements in the page layout file of the mini program, one for displaying the front content and one for displaying the back content. The specific sample code is as follows: &lt;!--index.wxml--&gt;&l

Alipay launched the 'Chinese Character Picking-Rare Characters' mini program to collect and supplement the rare character library Alipay launched the 'Chinese Character Picking-Rare Characters' mini program to collect and supplement the rare character library Oct 31, 2023 pm 09:25 PM

According to news from this site on October 31, on May 27 this year, Ant Group announced the launch of the "Chinese Character Picking Project", and recently ushered in new progress: Alipay launched the "Chinese Character Picking-Uncommon Characters" mini program to collect collections from the society Rare characters supplement the rare character library and provide different input experiences for rare characters to help improve the rare character input method in Alipay. Currently, users can enter the "Uncommon Characters" applet by searching for keywords such as "Chinese character pick-up" and "rare characters". In the mini program, users can submit pictures of rare characters that have not been recognized and entered by the system. After confirmation, Alipay engineers will make additional entries into the font library. This website noticed that users can also experience the latest word-splitting input method in the mini program. This input method is designed for rare words with unclear pronunciation. User dismantling

Use uniapp to develop a simple map navigation Use uniapp to develop a simple map navigation Jun 09, 2022 pm 07:46 PM

How to use uniapp to develop a simple map navigation? This article will provide you with an idea for making a simple map. I hope it will be helpful to you!

How uniapp achieves rapid conversion between mini programs and H5 How uniapp achieves rapid conversion between mini programs and H5 Oct 20, 2023 pm 02:12 PM

How uniapp can achieve rapid conversion between mini programs and H5 requires specific code examples. In recent years, with the development of the mobile Internet and the popularity of smartphones, mini programs and H5 have become indispensable application forms. As a cross-platform development framework, uniapp can quickly realize the conversion between small programs and H5 based on a set of codes, greatly improving development efficiency. This article will introduce how uniapp can achieve rapid conversion between mini programs and H5, and give specific code examples. 1. Introduction to uniapp unia

Let's talk about how to use uniapp to develop a snake game! Let's talk about how to use uniapp to develop a snake game! May 20, 2022 pm 07:56 PM

How to use uniapp to develop a snake game? The following article will take you step by step to implement the Snake game in uniapp. I hope it will be helpful to you!

See all articles