laravel - Laravel-vue jwt 令牌刷新
问题描述
我正在使用Tymon 的jwtAuth
包来处理从我的 laravel 后端到vue
spa 前端的 Auth,我正在创建 AuthController,我从文档中获取了几乎所有内容,并对其进行了一些调整以满足我的需求。从登录到注销以及令牌到期时,一切正常。
问题是我确实看到该控制器上有一个令牌刷新功能,如果我的猜测是正确的,它就是刷新客户端已经拥有的当前令牌。但是怎么做呢?如何在前端处理该刷新令牌?因为每 60 分钟(默认情况下令牌生命周期)非常烦人,所以它会抛出 401。
我想要的可能是每次用户向后端发出请求时,它都会刷新令牌或增加令牌的生命周期。因此,仅当用户空闲整整 60 分钟时,令牌才会过期。
我们可以这样做吗?这是最佳做法吗?我对整个jwt
和令牌的事情都很陌生,在过去,我只依赖 laravel 令牌过期,因为我不使用 spa,而是刀片前端,所以大多数情况下不需要弄乱 laravel 的方式验证用户。
对于此处添加的信息,我认为每个文件都与整个身份验证有关。
这是我的授权控制器
<?php
namespace App\Http\Controllers;
use DB;
use Hash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Input;
use App\Http\Controllers\Controller;
use App\User;
use Response;
class Authcontroller extends Controller
{
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login']]);
}
/**
* Get a JWT via given credentials.
*
* @return \Illuminate\Http\JsonResponse
*/
public function login()
{
$credentials = request(['username', 'password']);
if (! $token = auth('api')->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
/**
* Get the authenticated User.
*
* @return \Illuminate\Http\JsonResponse
*/
public function me()
{
return response()->json(auth('api')->user());
}
/**
* Log the user out (Invalidate the token).
*
* @return \Illuminate\Http\JsonResponse
*/
public function logout()
{
auth('api')->logout();
return response()->json(['message' => 'Successfully logged out']);
}
/**
* Refresh a token.
*
* @return \Illuminate\Http\JsonResponse
*/
public function refresh()
{
return $this->respondWithToken(auth('api')->refresh());
}
/**
* Get the token array structure.
*
* @param string $token
*
* @return \Illuminate\Http\JsonResponse
*/
protected function respondWithToken($token)
{
$id = auth('api')->user()->getId();
$kelas = User::with('pus','cu')->findOrFail($id);
return response()->json([
'access_token' => $token,
'user' => $kelas,
'token_type' => 'bearer',
'expires_in' => auth('api')->factory()->getTTL() * 60
]);
}
public function guard()
{
return Auth::Guard('api');
}
}
这是我的 API 路线
Route::group(['prefix' => 'auth'],function($router){
Route::post('/login', 'AuthController@login');
Route::post('/logout', 'AuthController@logout');
Route::post('/refresh', 'AuthController@refresh');
Route::get('/me', 'AuthController@me');
});
这是我vue general.js
处理路由的文件,并将标头提供给 Axios
export function initialize(store, router) {
router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const currentUser = store.state.auth.currentUser;
if(requiresAuth && !currentUser) {
next('/login');
} else if(to.path == '/login' && currentUser) {
next('/');
} else {
next();
}
});
axios.interceptors.response.use(null, (error) => {
if (error.response.status == 401) {
store.dispatch('auth/logout');
router.push('/login');
}
return Promise.reject(error);
});
if (store.state.auth.currentUser) {
setAuthorization(store.state.auth.currentUser.token);
}
}
export function setAuthorization(token) {
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`
}
这是auth.js
处理登录
import { setAuthorization } from "./general";
export function login(credentials){
return new Promise((res,rej) => {
axios.post('/api/auth/login', credentials)
.then((response) => {
setAuthorization(response.data.access_token);
res(response.data);
})
.catch((err) => {
rej("Username atau password salah");
})
})
}
解决方案
您可以调整令牌到期时间(从.env
as JWT_TTL
)和刷新时间 ( JWT_REFRESH_TTL
) 以满足您的需要。并检查令牌是否有效和/或是否需要在中间件中刷新,以便在需要时尽快刷新令牌。
至于这是否是一个好的做法,请参阅JWT_REFRESH_TTL
您的 Laravel 项目中的config/jwt.php
.
对我来说效果很好的解决方案是使用扩展的自定义中间件Tymon\JWTAuth\Http\Middleware\BaseMiddleware
。样板文件看起来像这样:
Class TryTokenRefresh extends BaseMiddleware
{
public function handle($request, Closure $next)
{
$newToken = $this->tryRefresh($request);
if ($newToken) {
// in case there's anything further to be done with the token
// we want that code to have a valid one
$request->headers->set('Authorization', 'Bearer ' . $newToken);
}
...
...
$response = $next($request);
...
...
if ($newToken) {
// send new token back to frontend
$response->headers->set('Authorization', $newToken);
}
return $response;
}
// Refresh the token
protected function tryRefresh()
{
try {
$token = $this->auth->parseToken()->refresh();
return $token;
} catch (JWTException $e) {
// token expired? force logout on frontend
throw new AuthenticationException();
}
return null;
}
在前端,它就像Authorization
在响应中查找标头一样简单:
// check for the `Authorization` header in each response - refresh on frontend if found
axios.interceptors.response.use((response) => {
let headers = response.headers
// your 401 check here
// token refresh - update client session
if (headers.authorization !== undefined) {
setAuthorization(headers.authorization);
}
return response
})
希望这可以帮助。
推荐阅读
- matlab - 二维向量的叉积
- javascript - 必需的属性在选择中不起作用
- android - 导入项目时 build.gradle 错误
- c# - 将 Web API 投影请求的结果绑定到 DataGrid 或 ListView 等 WPF 控件
- qt - 带有模板的 QList 通用 join() 函数
- python - Division of multiple dimension data in pandas using groupby
- sqlite - 如何限制 session.query 中每个对象的结果
- reactjs - 如何使用 React Native 和 Redux 制作搜索栏
- python - for 循环仅使用 dict 中的第一个键
- c++ - 如何在 C++ 中删除二维数组中的列