Jwt-Auth + Vue smoothly refresh Token in Laravel front-end and back-end separation project

Jwt-Auth and Token

Token is used as the security mechanism of the interface. The APP or WEB (built with VUE, REACTJS, etc.) uses the token to interact with the back-end interface to achieve security.

jwt-auth has two important parameters, which can be set in .env

How many minutes will the token generated by JWT_TTL expire? The default is 60 minutes
. The token generated by JWT_REFRESH_TTL specifies the number of minutes within which a new token can be refreshed. The default is 20160 minutes and 14 days.
Here you need to understand the JWT expiration and refresh mechanism. Expiration is easy to understand. After this time, the token is invalid. The refresh time is generally longer than the expiration time. As long as this refresh time, even if the token expires, you can still exchange for a new token, which has achieved the long-term availability of the application and does not need to log in again.

RefreshToken middleware

php artisan make:middleware RefreshToken
<?php

namespace App\Http\Middleware;

use Auth;
use Closure;
use Tymon\JWTAuth\JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Http\Middleware\BaseMiddleware;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class RefreshToken extends BaseMiddleware
{
    
    
    function handle($request, Closure $next)
    {
    
    
        // 检查此次请求中是否带有 token,如果没有则抛出异常。
        $this->checkForToken($request);

        // 使用 try 包裹,以捕捉 token 过期所抛出的 TokenExpiredException  异常
        try {
    
    
            // 检测用户的登录状态,如果正常则通过
            if ($this->auth->parseToken()->authenticate()) {
    
    
                return $next($request);
            }
            throw new UnauthorizedHttpException('jwt-auth', '未登录');
        } catch (TokenExpiredException $exception) {
    
    
            // 此处捕获到了 token 过期所抛出的 TokenExpiredException 异常,我们在这里需要做的是刷新该用户的 token 并将它添加到响应头中
            try {
    
    
                // 刷新用户的 token
                $newToken = $this->auth->refresh();
                $request->headers->set('Authorization','Bearer '.$newToken);
            } catch (JWTException $exception) {
    
    
                // 如果捕获到此异常,即代表 refresh 也过期了,用户无法刷新令牌,需要重新登录。
                throw new UnauthorizedHttpException('jwt-auth', $exception->getMessage());
            }
        }
        // 在响应头中返回新的 token
        return $this->setAuthenticationHeader($next($request), $newToken);
    }

    public function handle2($request,Closure $next)
    {
    
    

    }
}

Update the Handler for exception handling

Since we are building an api service, we need to update the render
method in app/Exceptions/Handler.php to customize some exceptions.

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;

class Handler extends ExceptionHandler
{
    
    
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Report or log an exception.
     *
     * @param  \Exception  $exception
     * @return void
     */
    public function report(Exception $exception)
    {
    
    
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Exception  $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
    
    
        // 用户认证的异常,我们需要返回 401 的 http code 和错误信息
        if ($exception instanceof UnauthorizedHttpException) {
    
    
            return response($exception->getMessage(), 401);
        }

        if ($this->isHttpException($exception)) {
    
    
			//if (view()->exists('errors.' . $exception->getStatusCode())) {
    
    
			//API服务器不需要返回视图
			//return response()->view('errors.' . $exception->getStatusCode(), [], $exception->getStatusCode());
//}
            //404已交给Vue处理,这里返回视图即可;
            if($exception->getStatusCode()==404){
    
    
                return response()->view('app');
            }
            return response()->json(['message' => '出错了'], $exception->getStatusCode());

        }
        return parent::render($request, $exception);
    }
}

Set up Axios interceptor

Add Axios response interceptor in resources/js/app.js

//设置 Axios 拦截器
axios.interceptors.response.use((response) => {
    
    
	//获取响应头中的 authorization 
    var token = response.headers.authorization;
    //如果存在 authorization 说明服务器端判定 token 过期了并返回了新的 token
    if (token) {
    
    
    	//Vue 需要做的就是把新的token更新保存到cookie中,调用 Vuex users.js 模块中的 refreshToken 方法
        store.dispatch('refreshToken',{
    
    
            token:token
        });
    }
    return response;
});

Vuex store update token

/*
|-------------------------------------------------------------------------------
| VUEX modules/users.js
|-------------------------------------------------------------------------------
| The Vuex data store for the Users
*/

import UserAPI from '../api/users';

/**
    status = 0 -> 数据尚未加载
    status = 1 -> 数据开始加载
    status = 2 -> 数据加载成功
    status = 3 -> 数据加载失败
*/

export const users = {
    
    
	state: {
    
    
			// 存储token
        	Authorization: localStorage.getItem('Authorization') ? localStorage.getItem('Authorization') : '',
	},
	actions: {
    
    
			refreshToken({
    
    commit},data){
    
    
	            commit('setLoginToken', data.token);
			}
	},
    mutations: {
    
    
        	// 修改token,并将token存入cookie:localStorage
            setLoginToken (state, access_token) {
    
    
                state.Authorization = access_token;
                localStorage.setItem('Authorization', access_token);
            },
    },
};

Reference: Use Jwt-Auth to implement API user authentication and refresh the access token painlessly

Guess you like

Origin blog.csdn.net/geeksoarsky/article/details/103841201