シームレスなトークンリフレッシュを実現する方法

シームレスなトークンリフレッシュを実現する方法

序文:

最近、ログインtokenに関する要求に取り組んでいたところ、製品から次のような疑問が生じました。「 token有効期限をもっと長くできますか? 頻繁にログインする必要があります。」

フロントエンド:バックエンド、トークンの有効期限を長く設定できますか?

バックエンド:はい、ただしそうするのは安全ではないので、より良い方法を使用できます。

フロントエンド:どのような方法ですか?

バックエンド:トークンを更新するためのインターフェースを提供し、トークンを定期的に更新します

フロントエンド:わかりました。ちょっと考えさせてください。

1. 需要

token有効期限が切れたら、 tokenを更新します。フロントエンドは意味をなさずにtokenを更新する必要があります。つまり、頻繁なログインを避けるために、ユーザーはtokenを更新するときにそれを意識しないようにする必要があります。実装のアイデア

方法1

バックエンドは有効期限を返し、フロントエンドはtoken有効期限を決定し、リフレッシュtoインターフェースを呼び出す。

デメリット:バックエンドはtokenの有効期限用の追加フィールドを提供する必要があり、ローカル時間が判断に使用されます。ローカル時間が改ざんされた場合、特にローカル時間がサーバー時間よりも遅い場合は、傍受は失敗します。

方法2

tokenインターフェースを定期的に更新するタイマーを書く

デメリット:リソースの浪費、パフォーマンスの消費、推奨されません。

方法3

レスポンスインターセプターでインターセプトし、 tokenが期限切れで返されたことを判断し、リフレッシュトークンインターフェースを呼び出す

2. 実装

axiosの基本的なフレームワーク。インターセプションにはservice.interceptors.responseを使用します。

'axios' から axios をインポートします

サービスインターセプターレスポンスの使用(
  レスポンス => {
    (応答データコード === 409)の場合{
        refreshToken を返します({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { トークン } = res.data
          setToken(トークン)
          レスポンス.ヘッダー.承認 = `${トークン}`
        }).catch(エラー => {
          トークンの削除()
          router.push('/login')
          Promise.reject(err) を返します。
        })
    }
    レスポンスを返す && response.data
  },
  (エラー) => {
    メッセージ.エラー(error.response.data.msg)
    Promise.reject(error) を返します。
  })

3. 問題解決

質問1: トークンの複数回の更新を防ぐ方法

tokenステータスが更新されるかどうかを制御するには、変数isRefreshing使用します。

'axios' から axios をインポートします

サービスインターセプターレスポンスの使用(
  レスポンス => {
    (応答データコード === 409)の場合{
      if (!isRefreshing) {
        リフレッシュ = true
        refreshToken を返します({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { トークン } = res.data
          setToken(トークン)
          レスポンス.ヘッダー.承認 = `${トークン}`
        }).catch(エラー => {
          トークンの削除()
          router.push('/login')
          Promise.reject(err) を返します。
        }).finally(() => {
          リフレッシュ = false
        })
      }
    }
    レスポンスを返す && response.data
  },
  (エラー) => {
    メッセージ.エラー(error.response.data.msg)
    Promise.reject(error) を返します。
  })

質問 2: 2 つ以上のリクエストが同時に開始された場合、他のインターフェースはこの問題をどのように解決しますか?

2 番目の期限切れのリクエストが届くと、 tokenが更新されます。まず、このリクエストを配列キューに保存し、 tokenが更新されるまでこのリクエストを待機させ、その後、リクエスト キューをクリアするために 1 つずつ再試行します。では、このリクエストを待機させ続けるにはどうすればよいでしょうか?この問題を解決するには、 Promiseを使用する必要があります。リクエストをキューに格納した後、同時にPromiseが返されるため、 Promiseは常にPending状態になります (つまり、resolve は呼び出されません)。このとき、リクエストは待機し続けます。resolve resolve実行しない限り、リクエストは待機し続けます。リフレッシュ要求インターフェースが返されたら、再度解決を呼び出して、1 つずつ再試行します。

最終コード:

'axios' から axios をインポートします

//リフレッシュ中かどうか let isRefreshing = false
// キューを再試行する let requests = []
サービスインターセプターレスポンスの使用(
  レスポンス => {
  //合意コード 409 トークンの有効期限が切れました if (response.data.code === 409) {
      if (!isRefreshing) {
        リフレッシュ = true
        //リフレッシュトークンインターフェースを呼び出す return refreshToken({ refreshToken: localStorage.getItem('refreshToken'), token: getToken() }).then(res => {
          const { トークン } = res.data
          // トークンを置き換える
          setToken(トークン)
          レスポンス.ヘッダー.承認 = `${トークン}`
           // トークンが更新されたら、配列メソッドrequests.forEach((cb) => cb(token))を再実行します。
          リクエスト = [] // 再リクエストしてクリアするサービス(response.config)
        }).catch(エラー => {
        //ログインページにジャンプするremoveToken()
          router.push('/login')
          Promise.reject(err) を返します。
        }).finally(() => {
          リフレッシュ = false
        })
      } それ以外 {
        // 解決されていない Promise を返します
        新しいPromiseを返します(resolve => {
          // 関数形式で解決を保存し、requests.push(token => {を実行する前に更新を待機します。
            レスポンス.ヘッダー.承認 = `${トークン}`
            解決(サービス(response.config))
          })
        })
      }
    }
    レスポンスを返す && response.data
  },
  (エラー) => {
    メッセージ.エラー(error.response.data.msg)
    Promise.reject(error) を返します。
  }
)

シームレストークンリフレッシュの実装方法については以上です。シームレストークンリフレッシュの実装方法の詳細については、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • SpringBoot JWTはトークンログインリフレッシュ機能を実装します
  • トークンの有効期限が切れたときにページを更新するときに繰り返しプロンプトが表示されないようにする Vue について
  • uniappの無痛トークンリフレッシュ方法の詳細な説明
  • ASP.NET Core Web API における JWT リフレッシュ トークンの詳細な説明
  • リクエスト中にトークンの有効期限が切れた場合、トークン操作を自動的に更新する
  • SpringSecurity Jwt トークン自動更新の実装
  • springboot+jwt に基づくリフレッシュトークンプロセス分析
  • Vue での Axios インターセプター トークン更新メカニズムのサンプル コード
  • Laravel (Lumen) は JWT-Auth リフレッシュトークンの問題を解決します

<<:  Dockerfileを使用してDockerイメージを構築する

>>:  CSS レイアウト チュートリアル: 垂直方向の中央揃えを実現する方法

推薦する

格納可能なセカンダリメニューを実装するための JavaScript

JavaScriptで格納可能なセカンダリメニューを実装するための具体的なコードは参考までに。具体...

ホバードロップダウンメニューを実装するためのネイティブJS

JS はホバー ドロップダウン メニューを実装します。これは、フロントエンドの面接で遭遇するシナリ...

Reactスロットの使い方

目次必要コアアイデアReactでスロットを実装する2つの方法必要コンポーネントを自分で書きました。コ...

React forwardRefの使い方と注意点

これまで react.forwardRef は react の高階コンポーネントには適用できませんで...

JavaScript の便利な配列トリック 12 選

目次アレイ重複排除1. from() を新しい Set() メソッドに重ねる2. スプレッド演算子 ...

ネイティブ js カプセル化シームレスカルーセル機能

ネイティブjsカプセル化シームレスカルーセルプラグイン、参考までに、具体的な内容は次のとおりです。例...

Ubuntu 18.04 サーバーのパスワードを忘れたり改ざんされた場合にパスワードをリセットする方法

最近、サーバー上のアカウントが2つハッキングされ、パスワードが改ざんされました。幸い、まだ使えるアカ...

CentOS7 で docker を使用して Apollo 構成センターをデプロイする実装

Apollo オープンソース アドレス: https://github.com/ctripcorp/...

MySQL データベースのアップグレードにおけるいくつかの「落とし穴」

商用データベースの場合、データベースのアップグレードは優先度が高く、バージョンアップのロードマップ、...

CSS3 における構造擬似クラスセレクターと擬似要素セレクターの使い方の詳細な説明

構造擬似クラスセレクタの紹介構造擬似クラスセレクターは、いくつかの特殊効果を処理するために使用されま...

Nginx ログ出力のリクエスト後パラメータを設定する方法

【序文】当プロジェクトの SMS 機能は、第三者に接続することです。第三者からの元の受信確認要求は ...

Vueは商品詳細ページの商品タブ機能を実装します

この記事の例では、商品詳細ページ機能を実現するためのVueの商品タブの具体的なコードを参考までに共有...

ベスト HTML/CSS デザインおよび開発フレームワーク 15 選を紹介します

プロフェッショナルな Web デザインは複雑で時間がかかります。 HTML と CSS フレームワー...

Alibaba Cloud centos7にmysql8.0.22をインストールする詳細なチュートリアル

1. MySQLインストールパッケージをダウンロードするまず、https://dev.mysql.c...

MySQL がタイムスタンプを使用するときにタイムゾーンの問題を無視できるのはなぜですか?

私はいつも、なぜMySQLデータベースのtimestampタイムゾーンの問題を無視できるのか疑問に思...