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

Json?Web?Token在前后端實踐思考分析

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

1、前言

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

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

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

下面便是請求接口的一個大致過程

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

2、后端

登錄接口,通過用戶名和密碼,或者手機號驗證碼的方式通過驗證

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

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

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

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

  • HEADER

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

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

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

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

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

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

后端服務(wù)會通過全局注冊的環(huán)繞AOP,處理每次前端有請求到達(dá)后端的時候來對token校驗

  AllowAnonymousAttribute allowAnonymousAttribute = descriptor.MethodInfo.GetCustomAttribute<AllowAnonymousAttribute>(false);
  // 判斷可不驗證token的接口
  if (allowAnonymousAttribute != null)
  {
      await next(); 
      return;
  }
  //獲取請求頭中的Authorization
  string token = context.HttpContext.Request.Headers["Authorization"];
  // 相當(dāng)于對前端傳遞的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)證過期,請重新登錄", -2);  // 這里用-2跟前端做好約定
    }
  } else {
    throw new ValidException("Token認(rèn)證過期,請重新登錄", -2);  // 這里用-2跟前端做好約定
  }

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

3、前端

通過登錄頁面,輸入登錄名和密碼,或者手機號和驗證碼,獲取到token,現(xiàn)將token存儲到localStorage中,再通過token獲取其他業(yè)務(wù)接口的數(shù)據(jù)。 通常可能首先通過token獲取個人信息或者一些權(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)前登錄用戶的個人信息以及后臺勾選的菜單權(quán)限,后端分別通過兩個接口進(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針對每次的請求添加請求頭的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)
);

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

instance.interceptors.response.use(
  (response) => {
    // token
    if (response.data.code === -2) {   
      // token失效
      ElMessage({
        message: "身份認(rèn)證無效,請重新登錄",
        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路由中會進(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é)

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

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

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

相關(guān)文章

  • bootstrap手風(fēng)琴制作方法詳解

    bootstrap手風(fēng)琴制作方法詳解

    這篇文章主要為大家詳細(xì)介紹了bootstrap手風(fēng)琴的制作方法,制作聲明式觸發(fā)手風(fēng)琴,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-01-01
  • echarts環(huán)形圖內(nèi)部圓、外部圓形及陰影設(shè)置方法

    echarts環(huán)形圖內(nèi)部圓、外部圓形及陰影設(shè)置方法

    近期要做圖表,我選擇了ECharts做可視化圖表,圖表的樣式有陰影,這篇文章主要給大家介紹了關(guān)于echarts環(huán)形圖內(nèi)部圓、外部圓形及陰影設(shè)置的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-11-11
  • 表單提交(插入效果)javascript

    表單提交(插入效果)javascript

    表單提交(插入效果)javascript...
    2006-08-08
  • js判斷鼠標(biāo)左、中、右鍵哪個被點擊的方法

    js判斷鼠標(biāo)左、中、右鍵哪個被點擊的方法

    這篇文章主要介紹了js判斷鼠標(biāo)左、中、右鍵哪個被點擊的方法,主要通過event.button事件來判斷鼠標(biāo)點擊的類型,需要的朋友可以參考下
    2015-01-01
  • 相關(guān)JavaScript在覽器中實現(xiàn)可視化的四種方式

    相關(guān)JavaScript在覽器中實現(xiàn)可視化的四種方式

    這篇文章主要介紹了相關(guān)JavaScript在覽器中實現(xiàn)可視化的四種方式,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,感興趣的小伙伴可以參考一下
    2022-09-09
  • 點擊顯示指定元素隱藏其他同輩元素的方法

    點擊顯示指定元素隱藏其他同輩元素的方法

    點擊顯示指定元素并隱藏其他同輩元素,下面有個不錯的方法,需要的朋友可以參考下
    2014-02-02
  • 基于javascript實現(xiàn)圖片預(yù)加載

    基于javascript實現(xiàn)圖片預(yù)加載

    這篇文章主要介紹了javascript圖片預(yù)加載的方法,實例分析了javascript實現(xiàn)圖片預(yù)加載的思路,具有一定參考借鑒價值,需要的朋友可以參考下
    2016-01-01
  • 微信JSSDK上傳圖片

    微信JSSDK上傳圖片

    做過微信開發(fā)的都知道,在部分android機型里微信不支持網(wǎng)頁上傳圖片的,這是由于這些機型的文件上傳存在內(nèi)存泄漏,會導(dǎo)致微信閃退,所以微信內(nèi)置瀏覽器將文件上傳屏蔽,本篇文章給大家介紹使用微信jssdk如何上傳圖片,需要的朋友可以關(guān)注下
    2015-08-08
  • 純js實現(xiàn)瀑布流展現(xiàn)照片(自動適應(yīng)窗口大小)

    純js實現(xiàn)瀑布流展現(xiàn)照片(自動適應(yīng)窗口大小)

    用瀑布流來展現(xiàn)照片再好不過了,我的思路大概是一張一張的圖片插入,當(dāng)這一行的圖片保持長寬比例不變并且高度低于250時就完成一個了循環(huán),即這一行插入進(jìn)去了
    2013-04-04
  • 用Webpack構(gòu)建Vue項目的實踐

    用Webpack構(gòu)建Vue項目的實踐

    這篇文章主要介紹了用Webpack構(gòu)建Vue項目的實踐,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11

最新評論