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

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

序文:

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

推薦する

MySQLクエリの基本的なクエリ操作の学習

序文MySQL は最も人気のあるリレーショナル データベース管理システムです。WEB アプリケーショ...

require loaderの実装原理の深い理解

序文Node は新しいプログラミング言語ではなく、JavaScript のランタイムに過ぎないとよく...

Vue.jsクラウドストレージで画像アップロード機能を実現

序文ヒント:以下はこの記事の主な内容です。以下のケースを参考にしてください。 1. オブジェクトスト...

Vue実戦記録のログインページの実装

目次1. 事前準備1.1 Node.jsをインストールする1.2 webpackをインストールする1...

MySQL データベースの基礎を始めるための一般的なコマンドの概要

この記事では、MySQL データベースの基礎を学ぶためによく使用されるコマンドを例を使って説明します...

Chromeブラウザ設定の新バージョンではクロスドメイン実装が可能

序文現在、フロントエンドは主に webpack の devServer の構成を通じてクロスドメイン...

JavaScript配列の重複排除のいくつかの方法についての詳細な説明

目次1.重複排除を設定する2. 重複を削除するには、2 回の for ループを使用します。 3. i...

Alibaba Cloud Server で MySQL デュアルマシン ホットスタンバイを手動で実装する 2 つの方法

1. コンセプト1. ホットバックアップとバックアップの違いホット バックアップは高可用性 (HA)...

Navicateを使用してAlibaba Cloud Server上のMySQLに接続する

1. まず、サーバーの mysql にアクセスして権限を変更します。 GRANT オプション付きで、...

mysql5.7.17 zip の解凍とインストールの詳細な手順

1. ダウンロードアドレスhttps://dev.mysql.com/downloads/mysql...

Centos7.X Linux システムに tomcat8 をインストールするためのグラフィック チュートリアル

1. Tomcatのインストールパスを作成する mkdir /usr/local/tomcat 2....

JS を使用して要素が配列であるかどうかを判断する例

検証できるデータの種類は次のとおりです a = [1,2,3,4,5,6]とします。 b = [とし...

選択/フォーカス時にすべてのオプションをリストする現在のより良い方法

開発中にこのような要件に遭遇したので、将来使用するために記録しました。需要背景キーボード ショートカ...

ボタンの 4 つのクリック応答方法の概要

ボタンは頻繁に使用されます。ここでは、イベント処理メソッドを整理し、実装方法が多数あることを発見しま...

MySQL の日付フォーマットと複雑な日付範囲クエリ

目次序文クエリの使用シナリオ例時間間隔クエリクエリ日付と今日の時間の比較データ一般的なサイクルタイム...