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

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

序文:

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

推薦する

この記事では、Viteがブラウザのリクエストに対して何を行うかを説明します。

目次動作原理:ブラウザは何をするのですか?ホストファイル index.htmlメイン.jsその他のベ...

Vueでブラウザタイトルを動的に設定する方法の詳細な説明

目次ナンセンス文章最初ルーター/index.js 2番目1. プラグインをインストールする2.mai...

js でクラスセレクターと名前属性セレクターを実装する手順の例

jQuery の登場により、DOM の操作効率が大幅に向上し、開発がより高いレベルに引き上げられまし...

Nginx ソースコード調査における nginx 電流制限モジュールの詳細な説明

目次1. 電流制限アルゴリズム2. nginxの基礎知識4. 実戦要約する高並行性システムには、キャ...

ウェブサイトのコードブロックのpreタグにコピーコードボタンコードを追加します

他のよりプロフェッショナルなブログ システムを参照すると、コード ブロックにコードのコピー ボタンが...

MySQL マスタースレーブ同期における server-id の例の詳細な説明

序文MySQL クラスターを構築する場合、当然のことながら、データの一貫性を確保するために、データベ...

WeChat ミニプログラム 宝くじ番号ジェネレーター

この記事では、WeChatアプレットの宝くじ番号ジェネレータの具体的なコードを参考までに紹介します。...

Linux カーネル デバイス ドライバー システム コールに関する注意事項

/**************************** * システムコール**********...

MySQL マルチテーブル共同クエリ操作例の分析

この記事では、MySQL のマルチテーブル共同クエリ操作について説明します。ご参考までに、詳細は以下...

Docker コンテナの uid と gid の詳細な理解

デフォルトでは、コンテナ内のプロセスは root ユーザー権限で実行され、この root ユーザーは...

Linuxで$を#に変更する方法

このシステムでは、# 記号は root ユーザーを表し、$ 記号は通常のユーザーを表します。では、ど...

Linux システムでのユーザー管理の概要

目次1. ユーザーとユーザーグループの重要性1) ユーザーの存在意義2) ユーザーグループの重要性2...

JavaScript 基礎シリーズ: 関数とメソッド

目次1. 関数とメソッドの違い2. 良い関数の書き方2.1 正確な命名2.1.1 関数の命名2.1....

ウェブアニメーションのフレームレートFPSを計算する方法

目次スムーズなアニメーションの基準方法1: Chromeデベロッパーツールを使用する方法 2: フレ...

CSS3を使用してトランジションとアニメーション効果を実現する

JS アニメーションの代わりに CSS アニメーションを使用する必要があるのはなぜですか? Java...