vue+axios+koa 前端後端實現登錄攔截--http攔截

一、前言

要想統一處理所有http請求和響應,就得用上 axios 的攔截器。通過配置http response inteceptor,當後端接口返回401 Unauthorized(未授權),讓用戶重新登錄。

 

二、具體實現

當前端使用localStorage存儲登陸信息,但是這個時候,後端一般在登陸的成功的時候,使用JWT(json web token)會生成token,這個token包含了失效時間和祕鑰,以及用戶的信息。比如:

1、登陸時候後端生成失效時間的JWT

const jwt = require("jsonwebtoken");

const token = jwt.sign(userToken, secret, {expiresIn: '7d'});

這個userToken可以是,比如是登陸進來的user的id和name。

const userToken = {
     name: name,
     id: res[0]["id"]
};

secret是自己定義的salt,確保這個jwt生成的字符串的隨機性和不易破解性。比如項目英文名稱

const secret = 'happy-chat-sec'

 

2、前端的http請求的封裝

http請求都是需要需要經過axios的,通過axios的create的方法可以添加http的前綴和超時時間。比如這個實例:

const service = axios.create({
  baseURL: '/',
  // baseURL: '/',
  timeout: 10000
})

通過interceptors.request.use方法對所有的http請求,進行封裝,比如對於已經登陸的,localstorage裏有這個字段HappyChatUserToken,說明需要在http報文頭部加上Authorization這個字段用來校驗前端是否登陸,後端會從http報文頭部中取到這個值,並進行校驗,是否是正確的。

service.interceptors.request.use(config => {
  const token = localStorage.getItem('HappyChatUserToken');
  if (token) {
    /*Bearer是JWT的認證頭部信息*/
    config.headers.common['Authorization'] = 'Bearer ' + token;
  }
  return config;
},error => {
  return Promise.reject(error);
});

 

3、前端的http返回的攔截

前端是本地緩存,但是後端纔是最根本來控制登陸的,如果失效時間到了,jwt的token就會失效,但是前端還是拿着這個失效的token去請求後端接口,那肯定是拿不到數據的,這時候後端返回401,未授權。

此時後端代碼遇到失效或者錯誤的JWT的返回

/*處理驗證是否登陸*/
const jwt = require("jsonwebtoken");
const secret = require("../config").secret;

module.exports = async (ctx, next) => {
    /*同步 校驗token*/
    const auth = ctx.get("Authorization");
    const token = auth.split(' ')[1];
    try {
        const userToken = jwt.verify(token, secret)
        ctx.user_id = userToken.id;
        ctx.name = userToken.name;
        await next()
    } catch (err){
        ctx.throw(401, err)
    }
}

這時候前端對返回的http請求做攔截,並跳轉到登陸頁面

service.interceptors.response.use(
  response => {
    let data = response.data;
    if (!data.data) {
      //   登陸成功的回調地址
      return data;
    } else {
      return data;
    }
  },
  error => {
    if(error.response) {
      switch (error.response.status){
        case 401:
          /*返回401,清空token信息,關閉socketio,並跳轉到登陸頁*/
          let userInfo = JSON.parse(localStorage.getItem("HappyChatUserInfo"));
          socketWeb.emit('logout', userInfo.user_id)
          localStorage.removeItem("HappyChatUserToken");
          localStorage.removeItem("HappyChatUserInfo");
          setTimeout(function() {
            router.push({
              path: "/login",
              query: {redirect: router.currentRoute.fullPath}
            });
          }, 500);
      }
    }
    return Promise.reject(error.response)   // 返回接口返回的錯誤信息
  }
);

跳轉到登陸,同時使用setimeout定時器,作爲延遲跳轉,使用router.push({path:'/login',query: {redirect: router.currentRoute.fullPath}}),這裏使用query的redirect的方式,用來解決:登錄失效後跳轉到去登錄頁面。登錄後打開的是你最後登錄的頁面。

這時候,登陸成功跳轉頁面時不能寫死寫成首頁。

  let redirect = decodeURIComponent(this.$route.query.redirect || '/robot');
  this.$router.push({ path: redirect });

上面代碼是在登陸成功之後,先去$route.query.redirect中找是否有值,沒有值,那就正常跳轉到/robot路由上。

注意:decodeURIComponent函數編碼的 URI 進行解碼

 

三、總結

使用router.push({path:'/login',query: {redirect: router.currentRoute.fullPath}})用來登錄失效後跳轉到去登錄頁面。登錄後打開的是你最後登錄的頁面。修改登陸頁面的跳轉let redirect = decodeURIComponent(this.$route.query.redirect || '/robot');

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章