前提・実現したいこと
フロントにNextjs,バックエンドにExpressという構成でwebアプリケーションを作成しています。
Nextjsのグローバルステート管理にはRecoilを使用しています。
jwtを使用したログイン判定をSWRを使って実装しようと思ったのですがどうにもうまくいきません
ここが原因ではないかと思いましたらコメントしていただけると嬉しいです。
発生している問題・エラーメッセージ
本来ならuserデータかisErrorデータのどちらかがすぐに返ってくるはずなのですが常にLoading状態になってしまいます。
コードはSWR公式ドキュメントから殆どコピペしてきたので原因箇所の見当がつきません
const { user, isLoading, isError } = useCheckUserRole("admin"); if (isError) return <div>failed to load</div> if (isLoading) return <div>loading...</div> if (user) return <div>get userdata</div>
該当のソースコード
Next.js
useCheckUserRole
1import useSWR from 'swr' 2import useAxios from './useAxios' 3 4const useCheckUserRole = (role: string) => { 5 const axios = useAxios(); //カスタマイズした設定のaxiosインスタンスを取得 6 7 const fetcher = (url: string) => { 8 axios.get(url).then((res => { 9 console.log(res.data) //画像のブラウザコンソールに出力されているものです。ここの出力からリクエストは成功していることが確認できます 10 res.data 11 })) 12 } 13 14 const { data, error } = useSWR(`auth/currentuser/${role}`, fetcher, { revalidateIfStale: true }) //テスト用にキャッシュをオフにしています 15 return { 16 user: data, 17 isLoading: !error && !data, 18 isError: error 19 } 20} 21 22export default useCheckUserRole;
SignUpPage
1import Layout from '../../components/Layout'; 2import useAxios from '../../hooks/useAxios'; 3import useCheckUserRole from '../../hooks/useCheckUserRole' 4 5const SignUpPage = () => { 6 const axios = useAxios(); 7 const { user, isLoading, isError } = useCheckUserRole("admin"); 8 9 if (isError) return <div>failed to load</div> 10 if (isLoading) return <div>loading...</div> 11 if (user) return <div>get userdata</div> 12 return ( 13 <Layout title="タイトル"> 14 <h1>サインアップ</h1> 15 </Layout> 16 ) 17} 18 19export default SignUpPage
useAxios
1import { useRecoilState } from "recoil"; 2import { accessTokenState } from "../components/atoms"; 3import { useRouter } from 'next/router' 4import Cookies from 'js-cookie' 5import axios from 'axios' 6 7//ここはあまり関係ないと思いますが一応載せておきます 8 9 10const useAxios = () => { 11 const router = useRouter(); 12 const [accessToken, setAccessToken] = useRecoilState(accessTokenState); 13 const refreshToken = Cookies.get("refreshToken") 14 15//リクエスト時にaccessTokenをAuthorizationヘッダーにセット 16 const api = axios.create({ 17 baseURL: process.env.NEXT_PUBLIC_API_HOST, 18 timeout: 1000, 19 withCredentials: true 20 }); 21 api.interceptors.request.use( 22 (config: any) => { 23 config.headers.common['Authorization'] = 'Bearer ' + accessToken; 24 return config; 25 } 26 ); 27 28//レスポンス時にAccessTokenが期限切れになっていた場合自動でrefreshTokenを使用してAccessTokenを更新した後リクエストをリトライする 29 api.interceptors.response.use((response) => { 30 return response; 31 }, async (error) => { 32 if (error.config && error.response && error.response.data.message === "jwt expired") { 33 try { 34 const result: any = await axios.post(`${process.env.NEXT_PUBLIC_API_HOST}auth/refresh`, { refreshToken: refreshToken }) 35 setAccessToken(result.data.accessToken) 36 const config = error.config; 37 config.headers['Authorization'] = 'Bearer ' + result.data.accessToken; 38 return axios.request(error.config); 39 } catch (err) { 40 router.push("/auth/login") 41 } 42 } 43 return Promise.reject(error); 44 }) 45 return api; 46} 47 48export default useAxios;
Express
authRouter
1import express from 'express'; 2import { currentUser } from '../../controllers/authController' 3const router = express.Router(); 4 5router.get("/currentuser/:role", currentUser) 6 7export default router; 8
authController
1import express from 'express'; 2import jwt from 'jsonwebtoken'; 3import HttpException from '../exceptions/HttpException'; 4 5//トークンを検証してログインしているかどうか、またURLのクエリで受け取ったroleと一致しているか判定するAPIです。 6export const currentUser = (req: express.Request, res: express.Response, next: express.NextFunction) => { 7 const accessTokenSecret: jwt.Secret = process.env.ACCESS_TOKEN_SECRET ?? "defaultaccesssecret" 8 const authHeader = req.headers["authorization"]; 9 const accessToken = authHeader && authHeader.split(" ")[1]; 10 if (accessToken == null) return next(new HttpException(403, "AccessToken is null")) 11 jwt.verify(accessToken, accessTokenSecret, (err: any, user: any) => { 12 if (err) return next(err) 13 if (req.params.role !== user.role) return next(new HttpException(402, "Permission error")) 14 return res.json(user); 15 }); 16}
### コンソールの出力
ExpressAPIへのリクエスト自体は成功しており、200statusとjsonデータが返ってきています。
問題はReact側、useSWRの方にあると推測しております。
補足情報(FW/ツールのバージョンなど)
node --version
v16.9.1
npm list --depth 0
├── @material-ui/core@4.12.3
├── @material-ui/icons@4.11.2
├── @types/js-cookie@3.0.0
├── @types/node@12.20.33
├── @types/react-dom@17.0.9
├── @types/react@17.0.30
├── axios@0.23.0
├── js-cookie@3.0.1
├── next@11.1.2
├── node-fetch@3.0.0
├── react-dom@17.0.2
├── react-hook-form@7.17.4
├── react@17.0.2
├── recoil-persist@3.0.0
├── recoil@0.4.1
├── swr@1.0.1
└── typescript@4.0.8
回答1件
あなたの回答
tips
プレビュー