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

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

序文:

最近、ログイン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 レイアウト チュートリアル: 垂直方向の中央揃えを実現する方法

推薦する

イメージを再構築せずにDockerにポートを動的に追加する方法

操作中に Docker コンテナの公開ポートを変更または追加する必要がある場合がありますが、実行中の...

Hadoopカウンターとデータクリーニングの適用

データクリーニング (ETL)コアビジネスの MapReduce プログラムを実行する前に、まずデー...

MySQL 8.0 アトミック DDL 構文の詳細な説明

目次01 アトミックDDLの紹介02 一部のDDL操作の実行動作の変更03 DDL 操作のログを表示...

HTML テーブルに複雑なテーブル ヘッダーを実装するためのサンプル コード

複雑な表を作成するには HTML を使用します。複雑なテーブルでは通常、td の rowspan 属...

Javascriptでシンプルなナビゲーションバーを実装

この記事では、参考までに、シンプルなナビゲーションバーを実装するためのJavascriptの具体的な...

IEの送信フォームの記録履歴クリックリターン情報を実現するためのCSSスタイルコントロールはまだ残っています

これは主に CSS スタイルのコントロールと META タグです。コードをコピーコードは次のとおりで...

Nginx 転送ソケットポート設定の詳細な説明

Nginx によるソケット ポート転送の一般的なシナリオ: オンライン学習アプリケーションでは、通常...

MySQL マスタースレーブレプリケーションでエラーをスキップする方法

1. 従来のbinlogマスタースレーブレプリケーション、エラー報告をスキップする方法 mysql&...

Vue モバイル開発で better-scroll を使用するときにクリック イベントが失敗する問題の解決策

最近、モバイル プロジェクトの開発方法を学ぶために vue を使用し、スクロールには better-...

ネイティブ js で呼び出し、適用、バインドを実装する方法

1. 呼び出しを実装するステップ:関数をオブジェクトのプロパティとして設定します。これを関数に割り当...

WeChatアプレットは写真の撮影とアルバムからの写真の選択を実現します

この記事では、WeChatアプレットで写真を撮ったり、アルバムから写真を選択したりするための具体的な...

GitHub のサードパーティ認証方式を Vue で実装する例

目次OAuth アプリの作成コードを取得するaccess_tokenを取得するユーザー情報を取得する...

ネイティブ JavaScript でシンプルな Gobang ゲームを実装する

この記事では、JavaScriptで簡単なGobangゲームを実装するための具体的なコードを参考まで...

遭遇したいくつかのブラウザ互換性の問題について簡単に説明します

背景ブラウザの互換性の問題を解決するのは非常に面倒なことです。高度な技術はそれほど必要ありませんが、...