欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Json?Web?Token在前后端實(shí)踐思考分析

 更新時(shí)間:2022年11月18日 08:37:06   作者:那個(gè)曾經(jīng)的少年回  
這篇文章主要為大家介紹了Json?Web?Token在前后端實(shí)踐思考分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

1、前言

啥也不說了,直接進(jìn)入正題,來學(xué)習(xí)一下Token在前端和后端的簡單應(yīng)用分析

Token是在客戶端頻繁向服務(wù)端請(qǐng)求數(shù)據(jù),服務(wù)端頻繁的去數(shù)據(jù)庫查詢用戶名和密碼進(jìn)行對(duì)比,判斷用戶名和密碼是否正確,并作出相應(yīng)提示,在這樣的背景下,Token便應(yīng)運(yùn)而生。

Token實(shí)際上就是在第一個(gè)登錄的時(shí)候通過用戶名和密碼,在服務(wù)端驗(yàn)證OK后生成的一串字符串,也可以說是驗(yàn)證通過后服務(wù)端為其簽發(fā)一個(gè)令牌,隨后前端在訪問服務(wù)端接口時(shí),客戶端就可以攜帶這個(gè)TOken令牌訪問服務(wù)器,服務(wù)端只需要驗(yàn)證令牌的有效性即可。

下面便是請(qǐng)求接口的一個(gè)大致過程

  • 先登錄,獲取Token
  • 調(diào)用業(yè)務(wù)接口,后端要先驗(yàn)證Token
  • 驗(yàn)證OK,才繼續(xù)調(diào)用業(yè)務(wù)接口返回?cái)?shù)據(jù)
  • 驗(yàn)證失敗,則返回給前端,比如Token過期,則重新跳轉(zhuǎn)到登錄

2、后端

登錄接口,通過用戶名和密碼,或者手機(jī)號(hào)驗(yàn)證碼的方式通過驗(yàn)證

public async Task<dynamic> Login([FromServices] IAuthService authService, [FromBody] FormLoginRequest loginModel)
{
  return await authService.login(loginModel);
  // authoService.login中的邏輯
  // 判斷是否匹配,匹配成功
  // 創(chuàng)建token并寫入redis,并設(shè)置超期時(shí)間
  // 之前業(yè)務(wù)接口調(diào)用時(shí),直接從redis中獲取
  // 如果有超期,返回給前端一個(gè)標(biāo)識(shí)
}

這里有一個(gè)創(chuàng)建Token的過程,我們來看一下token的組成

我找了一個(gè)公司正在開發(fā)項(xiàng)目中的token進(jìn)行解析查看。主要結(jié)構(gòu)如上圖所示。解密以后最重要的信息便是uid,或者說是用戶在后端中的唯一的用戶id,那么通過uid便可以查詢到相關(guān)的身份認(rèn)證信息。

截圖所示便是JSON Web Token的組成結(jié)構(gòu),從截圖左側(cè)仔細(xì)可以看到,中間有兩個(gè).將JWT分成了三個(gè)部分

  • HEADER

alg屬性表示簽名的算法(algorithm),默認(rèn)是 HMAC SHA256(寫成 HS256)
typ屬性表示這個(gè)令牌(token)的類型(type)

  • PAYLOAD 中間部分存放的就是實(shí)際要傳輸?shù)臄?shù)據(jù)
  • Signature部分是對(duì)前面的兩部分的數(shù)據(jù)進(jìn)行簽名,防止數(shù)據(jù)篡改。
  • 最終生成便是

首先明確一點(diǎn),是在后端生成的Token,后端會(huì)先定義一個(gè)秘鑰,這個(gè)秘鑰只有后端服務(wù)器才知道

不能泄露給用戶,然后使用Header中指定的簽名算法(默認(rèn)情況是HMAC SHA256), 

算出簽名以后將Header、Payload、Signature三部分拼成一個(gè)字符串,每個(gè)部分用`.`分割開來,
就可以返給用戶了。

前端在登錄認(rèn)證通過獲得Token并保存到前端以后,再調(diào)用業(yè)務(wù)接口的時(shí)候每次便會(huì)攜帶Token

后端服務(wù)會(huì)通過全局注冊(cè)的環(huán)繞AOP,處理每次前端有請(qǐng)求到達(dá)后端的時(shí)候來對(duì)token校驗(yàn)

  AllowAnonymousAttribute allowAnonymousAttribute = descriptor.MethodInfo.GetCustomAttribute<AllowAnonymousAttribute>(false);
  // 判斷可不驗(yàn)證token的接口
  if (allowAnonymousAttribute != null)
  {
      await next(); 
      return;
  }
  //獲取請(qǐng)求頭中的Authorization
  string token = context.HttpContext.Request.Headers["Authorization"];
  // 相當(dāng)于對(duì)前端傳遞的token進(jìn)行轉(zhuǎn)換
  string tokenKey = "sso." + Utils.MD5(token);
  // redis獲取,看看是否有效,直接取出返回
  string loginUserJson = await RedisHelper.GetAsync(tokenKey);
  if (!loginUserJson.IsNullOrWhiteSpace()) {
    RedisSSOVerifyResult resultInfo = JsonSerializer.Deserialize<RedisSSOVerifyResult>(loginUserJson);
    if(resultInfo.ExpiresAt > DateTime.now()) {
      loginUser = resultInfo.LoginUser;
    }
    else {
      RedisHelper.RemoveAsync(tokenKey); // 無效了 從redis中移除
      throw new ValidException("Token認(rèn)證過期,請(qǐng)重新登錄", -2);  // 這里用-2跟前端做好約定
    }
  } else {
    throw new ValidException("Token認(rèn)證過期,請(qǐng)重新登錄", -2);  // 這里用-2跟前端做好約定
  }

大致的一個(gè)token認(rèn)證過程是這樣的,實(shí)際項(xiàng)目中相對(duì)來說還是比較復(fù)雜的,這是我從公司項(xiàng)目中扣取出來的。還有很多代碼沒有列出來,要不然會(huì)顯得比較臃腫,而且主要邏輯不容易查看。

3、前端

通過登錄頁面,輸入登錄名和密碼,或者手機(jī)號(hào)和驗(yàn)證碼,獲取到token,現(xiàn)將token存儲(chǔ)到localStorage中,再通過token獲取其他業(yè)務(wù)接口的數(shù)據(jù)。 通??赡苁紫韧ㄟ^token獲取個(gè)人信息或者一些權(quán)限數(shù)據(jù)(這里只是提一下)。

  const adminLogin = async () => {
      //   state.loading = true
      const res = await loginByMobile({
        mobile: state.loginForm.phone,
        captchaValue: state.loginForm.verificationCode,
      });
      state.loading = false;
      if (res?.code === 200) {
        localStorage.setItem(
          "token",
          JSON.stringify({
            ...res.data,
            account: state.loginForm.phone,
          })
        );
        store.dispatch("fetchMenu");
      }
    };

我這里登錄完,直接通過token來獲取當(dāng)前登錄用戶的個(gè)人信息以及后臺(tái)勾選的菜單權(quán)限,后端分別通過兩個(gè)接口進(jìn)行的數(shù)據(jù)返回。

    async fetchMenu({ commit }) {
      try {
        const information = await getMyInformation()
        if (information?.code === 200) {
          console.log(information, 'information')
          commit("setMyInformation" , information.data)
          const res = await getMyMenu()
          if(res?.code === 200) {
            commit("changeMenuList",res.data)
            window.location.href = "/"
          }
        }
      } catch (error) {
      }
    },

這里是axios針對(duì)每次的請(qǐng)求添加請(qǐng)求頭的Authorization

instance.interceptors.request.use(
  (request) => {
    const token = localStorage.token
      ? JSON.parse(localStorage.token)
      : {};
    request.headers = {
      "Authorization": token.authorization || '',
      "Content-Type": "application/x-www-form-urlencoded",
      "Content-Type": "application/json",
    };
    return request;
  },
  (error) => Promise.reject(error)
);

這里是針對(duì)后端接口返回?cái)?shù)據(jù)的判斷處理,其中有一個(gè)-2的特殊判斷,這里是跟后端返回一起約定的code

instance.interceptors.response.use(
  (response) => {
    // token
    if (response.data.code === -2) {   
      // token失效
      ElMessage({
        message: "身份認(rèn)證無效,請(qǐng)重新登錄",
        type: "warning",
      });
      // localStorage.clear();
      clear()
      window.location.href = "/";
      return false;
    }
    if (response.data.code !== 200) {
      return Promise.reject(new Error(response.data.message));
    }
    /// ..... 其他的邏輯判斷
    return response.data;
  },
}

上面通過 code為-2 進(jìn)行判斷 ,然后清除掉緩存數(shù)據(jù),那么在vue-router路由中會(huì)進(jìn)行判斷處理

router.beforeEach((to, _from, next) => {
  NProgress.start()
  if (to.path === '/login' || to.path === '/init-password' ||  to.path === '/login-cellphone') {
    next()
    return false;
  }
  if (!localStorage.getItem('token')) {
    next('/login')
    return false
  }
  if (to.name) {
    next()
    return false
  }
  if (childrenPath.some((item) => to.path.includes(item))) {
    next()
    console.log('child');
    return false
  }
  // 如果找不到路由跳轉(zhuǎn)到404
  next("/404")
  return false
})

總結(jié)

前端和后端大致的一個(gè)過程就在這里簡單說完了,梳理完了以后,發(fā)現(xiàn)自己更清楚了,其實(shí)還有很多的問題要去處理,比如

  • 請(qǐng)求業(yè)務(wù)接口Token超期失效了該怎么辦? 可以通過每次調(diào)用業(yè)務(wù)接口的前,只要驗(yàn)證Token成功,就延遲Token的超期時(shí)間,但是這種方式每次都要去處理Token的時(shí)間,相對(duì)來說就比較麻煩,而且對(duì)服務(wù)器有一定的損耗。
  • 那還有更好的辦法嗎? 當(dāng)然也是有的。比如通過雙Token進(jìn)行無痛刷新,就是當(dāng)一個(gè)token失效或者超期后,通過另外一個(gè)refresh_token來重新獲取token的處理,獲取成功后,再重新調(diào)用期間異常的業(yè)務(wù)接口
  • 當(dāng)然肯定還有其他的方式吧,暫時(shí)能想到的就這么多了。

以上就是Json Web Token在前后端實(shí)踐思考分析的詳細(xì)內(nèi)容,更多關(guān)于Json Web Token前后端的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論