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

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

序文:

最近、ログイン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 で charAt() を使用して、最も頻繁に出現する文字とその出現回数をカウントする方法を教えます。

前回は、JavaScript の charAt() メソッドの使い方を紹介しました。今日は、最も多く...

ラベルタグを使用してテキストをクリックしてラジオボタンを選択します

<label> タグは、入力要素のラベル (タグ) を定義します。ラベル要素はユーザーに...

Nginx での Frp による https への強制リダイレクト設定の詳細な説明

自宅のルーターが300Mの帯域幅を80Mに強制的に減らしたため、3205Uソフトルーターを購入しまし...

Reactフックの長所と短所

目次序文アドバンテージ:欠点: 1. レスポンシブな使用効果2. ステータスが同期されていないRea...

MySQL で datetime 型のデフォルト値を設定する方法

Navicat クライアントを通じてデフォルトの日時値を変更する際に問題が発生しました。データベース...

JavaScript の navigator.userAgent がブラウザ情報を取得するケースの説明

ブラウザはおそらく私たちにとって最も馴染みのあるツールです。 Firefox、Opera、Safar...

CSS 3D からソースコードによる空間座標軸へ

かつて、サイコロを振るゲームについて話しました。その時は、steps 属性 + スプライト画像を使用...

Docker プライベートリポジトリの管理とローカルリポジトリ内のイメージの削除

1: Dockerプライベートウェアハウスのインストール1. イメージリポジトリからイメージをダウン...

Linuxでブーストライブラリをインストールするための完全な手順

序文Boost ライブラリは、標準ライブラリのバックアップとして機能し、C++ 標準化プロセスの開発...

ローカルでビルドした Docker イメージを Dockerhub に公開する方法

今日は、ローカルの Docker プロジェクト イメージを dockerhub に公開する方法を紹介...

Vue elementUI はツリー構造テーブルと遅延読み込みを実装します

目次1. 成果を達成する2. バックエンドの実装2.1 エンティティクラス2.2 データベース内のデ...

MySQL に IP アドレスを効果的に保存する方法と、文字列 IP と数値を変換する方法の詳細な説明

High Performance MySQL バージョン 3 (セクション 4.1.7) を見ると、...

バックエンド管理システムを構築するためのvue-element-adminの実装手順

最近、カンファレンスの健康申告システムに取り組んでいたとき、バックエンドを構築する必要があり、vue...

jQuery の CSS スタイル属性 css() と width() の完全ガイド

目次1. css() の基本的な使用法: 1.1 CSSプロパティを取得する1.2 CSSプロパティ...

MySQL バックアップ スクリプトの書き方

序文:データベースのバックアップの重要性は、特にデータの損失が深刻な結果を招く可能性がある実稼働環境...