, поэтому я создаю vue SPA-приложения и использую laravel в качестве бэкэнда с JWT для аутентификации и обработки токенов.
и я использую axios для всех моих вызовов API, а затем я использую axios.interceptors.Ответ для расчета времени между истечением срока действия токена и текущим временем, которое необходимо определить: пользователь должен выйти или обновить токен.
, но до сих пор я сталкиваюсь с 2 проблемами:
- каждый раз, когда яя открываю свои приложения, например, на следующий день или после истечения срока действия маркера истечения, он не перенаправляет меня автоматически на страницу входа, но вместо этого я должен выполнить навигацию по другим маршрутам, чтобы вызвать это.
- , когда мои приложенияв настоящее время открыт, но простаивал дольше или передал маркер истечения срока действия, тогда я не перенаправляюсь на страницу входа в систему при совершении вызовов API, но снова получаю перенаправление на вход в систему только при переходе на другой маршрут.
так что я думаю, что здесь чего-то не хватает, но не могу понять ...
вот мой файл app.js
window.axios = Axios; // handling http post
const router = new VueRouter({
base: '/admins',
mode: 'history',
routes
});
initialize(store, router);
const app = new Vue({
store,
router,
render: h => h(Admin)
}).$mount('#app');
каккод там я использую initialize(store, router);
для обработки аутентификации, токена, перехватчиков axios и маршрутизатора beforeEach
import { refreshToken } from "./auth.js";
import Token from "./token";
import { getLocalUser } from "./auth";
export function initialize(store, router) {
router.beforeEach((to, from, next) => {
window.scrollTo(0, 0);
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const currentUser = store.state.auth.currentUser;
if(requiresAuth && !currentUser) {
return next({
path:'/login',
query: {redirect: to.fullPath} // Store the full path to redirect the user to after login
});
}
if(to.path == '/login' && currentUser) {
return next('/');
}
next();
});
axios.interceptors.response.use((response) => {
if(store.state.auth.isLoggedIn){
const currentTime = new Date().getTime() / 1000;
const user = getLocalUser();
const token = Token.payload(user.token);
// console.log(currentTime, token.exp);
if(currentTime > token.exp - 600 && !store.state.auth.isLoading){
store.dispatch('auth/login');
refreshToken()
.then((res) => {
if(Token.isValid(res.access_token)){
store.dispatch('auth/loginSuccess', res);
return response;
}else{
store.dispatch('auth/loginFailed');
store.dispatch('auth/logout');
router.push({
path:'/login',
query: {redirect: to.fullPath} // Store the full path to redirect the user to after login
});
return Promise.reject(error);
}
})
.catch((error) => {
store.dispatch('auth/loginFailed');
store.dispatch('auth/logout');
router.push({
path:'/login',
query: {redirect: to.fullPath} // Store the full path to redirect the user to after login
});
return Promise.reject(error);
});
}else{
return response;
}
}else{
return response;
}
}, (error) => {
if (error.response.status == 401) {
store.dispatch('auth/logout');
router.push({
path:'/login',
query: {redirect: to.fullPath} // Store the full path to redirect the user to after 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}`
}
, в этой функции я вызываю token.js для обработки токена, полученного из бэкэнда (laravel)
class Token{
isValid(token){
const payload = this.payload(token);
if(payload){
switch( process.env.NODE_ENV){
case 'development':
return payload.iss == "https://bkcuvue.test/api/auth/login" || "https://bkcuvue.test/api/auth/refresh" ? true : false
break;
case 'production':
return payload.iss == "https://puskopditbkcukalimantan.org/api/auth/login" || "https://puskopditbkcukalimantan.org/api/auth/refresh" ? true : false
break;
}
}
return false
}
payload(token){
const payload = token.split('.')[1]
return this.decode(payload)
}
decode(payload){
if(this.isBase64(payload)){
return JSON.parse(atob(payload))
}
return false
}
isBase64(str){
try{
return btoa(atob(str)).replace(/=/g,"") == str
}
catch(err){
return false
}
}
}
export default Token = new Token()
также я использую auth.js для обработки логина, refreshtoken, получения локальных пользовательских данных из localstorage
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 or password invalid");
})
})
}
export function refreshToken(){
return new Promise((res,rej) => {
axios.post('/api/auth/refresh')
.then((response) => {
setAuthorization(response.data.access_token);
res(response.data);
})
.catch((err) => {
rej("Username or password invalid");
})
})
}
export function getLocalUser(){
const userStr = localStorage.getItem('user');
if(!userStr){
return null;
}
return JSON.parse(userStr);
}
, так как для бэкенда, который обрабатывает аутентификацию, будет очень похожетот, который был создан с использованием JWT
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')->setTTL(180)->attempt($credentials)) {
return response()->json(['error' => 'Unauthorized'], 401);
}
$id = Auth::user()->getId();
$admin = User::find($id);
if($admin->status == 0){
return response()->json(['error' => 'Maaf akun anda tidak aktif'], 401);
}
$admin->login = Date::now();
$admin->update();
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');
}
}
, так что, может быть, кто-то здесь, имеющий опыт работы с vue SPA и уже использующий таймаут и аутентификацию, может указать, где я ошибаюсь?
спасибо