Использование перехватчиков axios для тайм-аута приложения в Vue Spa - PullRequest
1 голос
/ 25 сентября 2019

, поэтому я создаю vue SPA-приложения и использую laravel в качестве бэкэнда с JWT для аутентификации и обработки токенов.

и я использую axios для всех моих вызовов API, а затем я использую axios.interceptors.Ответ для расчета времени между истечением срока действия токена и текущим временем, которое необходимо определить: пользователь должен выйти или обновить токен.

, но до сих пор я сталкиваюсь с 2 проблемами:

  1. каждый раз, когда яя открываю свои приложения, например, на следующий день или после истечения срока действия маркера истечения, он не перенаправляет меня автоматически на страницу входа, но вместо этого я должен выполнить навигацию по другим маршрутам, чтобы вызвать это.
  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 и уже использующий таймаут и аутентификацию, может указать, где я ошибаюсь?

спасибо

...