Reactを使ってブログサイトを作る 04 - トークン管理

https://github.com/KyleAndKelly/ArticleHub-React

## Reduxを使ったトークン管理

### 背景  
- Token（トークン）はユーザーのデータ識別子として、APIの権限管理において重要な役割を果たします。つまり、バックエンドでは多くのAPIが、現在のリクエストヘッダーにトークンデータが含まれているかどうかを確認し、正常にデータを返すかどうかを判断します。  
- Tokenはユーザーの識別データとして、多くのモジュールで共有する必要があります。Reduxを使用することで、状態の共有問題を簡単に解決できます。  

---

### 実装方法  
1. Redux内で、トークンを取得する非同期処理と、トークンを変更する同期処理を実装します。  
2. Loginコンポーネントがactionを送信し、フォームデータを渡す役割を担います。  

---

### code
- strore/modules/user.js

```jsx
import { request } from '@/utils';
import {createSlice} from '@reduxjs/toolkit'
const userStore = createSlice({
name:'user',
initialState:{
token :''
    },
reducers:{  
setToken(state, action) {
state.token = action.payload
        }
    },
});
const  fetchLogin = (loginForm) =>{
return async (dispatch)=>{
const res = await request.post('/v1_0/authorizations',loginForm)
dispatch(setToken(res.data.token))
    }
}
const { setToken } = userStore.actions
const userReducer = userStore.reducer
export {setToken, fetchLogin}
export default userReducer;

```
- store/index.js

```jsx
import { configureStore } from '@reduxjs/toolkit'
import userReducer from './modules/user'
export default configureStore({
reducer: {
user: userReducer
  }
})

```
- index.js
```jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.scss';
import App from './App';
import { RouterProvider } from 'react-router-dom'
import router from './router'
import {Provider} from 'react-redux'
import store from './store'
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<Provider store = {store}>
<RouterProvider router={router} />
</Provider>
</React.StrictMode>
);

```

- pages/Login/index.js
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/b2f74c73-7b8d-c78e-9ca2-d0cf17f9a5a7.png)


以下是翻译成日文的内容：

---

## トークンの永続化

### 課題  
- Reduxにトークンを保存した後、ブラウザをリロードするとトークンが失われます。（永続化とは、リロード時にトークンが失われないようにすることです）  
- Reduxはブラウザのメモリを利用したストレージ方式であるため、リロードすると状態が初期値に戻ります。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/e353cc30-f44e-36ef-86a3-e5270c5ea548.png)

---

### 解決策  
1. トークンを取得した後、ReduxとlocalStorageの両方に保存します。  
2. トークンを初期化する際、まずlocalStorageにトークンが存在するか確認し、存在する場合はlocalStorageに保存されているトークンを使用して値を設定します。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/1fabc770-9ca2-a801-c71f-405018cb5563.png)  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/0f7e21f9-a0de-1716-a93d-2ee26f11b21d.png)  

---

### APIのモジュール化  
- トークンに関する各種操作は、プロジェクトの複数のモジュールで使用されるため、ツール関数としてカプセル化することで共有・再利用が可能です。

--- 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/b44ca628-220c-ab5b-0e51-840b5da8eae7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/95979f0f-5242-1d08-9aba-569e02d489f8.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/48a9ee68-0eb4-dee0-64c1-e4b06c528b9a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/1816584e-a28f-1bb5-3727-2138c38d3c37.png)



## リクエストインターセプターによるトークンの注入

## ルート認証
### 実装の考え方  
- ローカルにトークンがあるか確認し、ある場合は子コンポーネントを返し、なければログインページ（Login）にリダイレクトします。

### 実装手順  
- `components` ディレクトリに `AuthRoute/index.jsx` ファイルを作成します。  
- ログインしている場合、対応するページコンポーネントをレンダリングします。  
- ログインしていない場合、ログインページにリダイレクトします。  
- 認証が必要なページのルート設定を、`AuthRoute` コンポーネントを使ってレンダリングするように変更します。

--- 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/35dfe665-636e-6d2f-98da-a2e6942967c9.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3916068/3271bc02-0a31-d885-7024-40384607a603.png)