Django/React JWT认证问题:仅指定页面需未登录跳转登录页
问题:Django/React JWT认证应用中,未登录用户访问所有路由都跳转到登录页,需仅指定页面跳转
当前开发基于JWT认证的Django/React应用,遇到的问题是:未认证用户访问任意路由URL时,都会自动跳转到登录页,但需求是仅特定页面(比如/authorform)才触发该跳转,而非全部页面。
现有代码如下:
AuthContext.js
import React, { createContext, useState, useEffect } from 'react' import jwt_decode from "jwt-decode"; import { useNavigate } from 'react-router-dom' const AuthContext = createContext() export default AuthContext; export const AuthProvider = ({children}) => { let [authTokens, setAuthTokens] = useState(()=> localStorage.getItem('authTokens') ? JSON.parse(localStorage.getItem('authTokens')) : null) let [user, setUser] = useState(()=> localStorage.getItem('authTokens') ? jwt_decode(localStorage.getItem('authTokens')) : null) let [loading, setLoading] = useState(true) const history = useNavigate() let loginUser = async (e )=> { e.preventDefault() let response = await fetch('/token/', { method:'POST', headers:{ 'Content-Type':'application/json' }, body:JSON.stringify({'username':e.target.username.value, 'password':e.target.password.value}) }) let data = await response.json() if(response.status === 200){ setAuthTokens(data) setUser(jwt_decode(data.access)) localStorage.setItem('authTokens', JSON.stringify(data)) history('/') }else{ alert('Something went wrong!') } } let logoutUser = () => { setAuthTokens(null) setUser(null) localStorage.removeItem('authTokens') history('/login') } let updateToken = async ()=> { let response = await fetch('/token/refresh/', { method:'POST', headers:{ 'Content-Type':'application/json' }, body:JSON.stringify({'refresh':authTokens?.refresh}) }) let data = await response.json() if (response.status === 200){ setAuthTokens(data) setUser(jwt_decode(data.access)) localStorage.setItem('authTokens', JSON.stringify(data)) }else{ logoutUser() } if(loading){ setLoading(false) } } let contextData = { user:user, authTokens:authTokens, loginUser:loginUser, logoutUser:logoutUser, } useEffect(()=> { if(loading){ updateToken() } let fourMinutes = 1000 * 60 * 4 let interval = setInterval(()=> { if(authTokens){ updateToken() } }, fourMinutes) return ()=> clearInterval(interval) }, [authTokens, loading]) return( <AuthContext.Provider value={contextData} > {loading ? null : children} </AuthContext.Provider> ) }
App.js
import React, { Component } from "react"; import { render } from "react-dom"; import HomePage from "./HomePage"; import '../../static/css/index.css'; import { BrowserRouter as Router, Route, Routes, } from "react-router-dom"; import { AuthProvider } from "../authentication/AuthContext"; export default class App extends Component { constructor(props) { super(props); } render() { return ( <div> <Router> <AuthProvider> <React.StrictMode> <div> <HomePage /> </div> </React.StrictMode> </AuthProvider> </Router> </div> ); } } const appDiv = document.getElementById("app"); render(<App />, appDiv);
HomePage.js
import React, { Component } from "react"; import { useState, useEffect } from "react"; import { useContext } from "react"; import LandingPage from "./LandingPage"; import LoginPage from "../authentication/LoginPage"; import AuthorForm from "../forms/submitforms/AuthorForm"; import { AuthProvider } from "../authentication/AuthContext"; export default function HomePage() { let {user, logoutUser} = React.useContext(AuthContext) function authenticationButtons (){ if (user){ return( <p className="brand-name" onClick={logoutUser}>logout</p> ) } else{ return( <div> <Link to="/login"className='brand-name' > Login.</Link> <a href="/register" className="brand-name"> <span> Register </span> </a> </div> ) } } return ( <div className="container"> <div>{authenticationButtons()}</div> <Routes> <Route exact path='/' element={<LandingPage/>}/> <Route exact element={ <LoginPage /> } path="/login"/> <Route path="authorform" element={<AuthorForm />}/> </Routes> </div > ); }
解决方案
核心思路是创建路由保护组件,仅给需要登录才能访问的页面添加保护逻辑,公开页面直接放行。
步骤1:创建路由保护组件(ProtectedRoute.js)
在认证模块下新建ProtectedRoute.js,用于判断用户登录状态:
import React, { useContext } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; import AuthContext from './AuthContext'; export default function ProtectedRoute() { const { user } = useContext(AuthContext); // 未登录则跳转到登录页,已登录则渲染目标页面 return user ? <Outlet /> : <Navigate to="/login" replace />; }
步骤2:修改HomePage.js,配置受保护路由
修改HomePage.js,将需要登录的路由嵌套进ProtectedRoute,公开路由直接保留:
import React from "react"; import { Link, Routes, Route } from "react-router-dom"; import { useContext } from "react"; import LandingPage from "./LandingPage"; import LoginPage from "../authentication/LoginPage"; import AuthorForm from "../forms/submitforms/AuthorForm"; import AuthContext from "../authentication/AuthContext"; import ProtectedRoute from "../authentication/ProtectedRoute"; export default function HomePage() { const { user, logoutUser } = useContext(AuthContext); function authenticationButtons() { if (user) { return ( <p className="brand-name" onClick={logoutUser}>logout</p> ); } else { return ( <div> <Link to="/login" className='brand-name'> Login.</Link> <Link to="/register" className="brand-name"> <span>Register</span> </Link> </div> ); } } return ( <div className="container"> <div>{authenticationButtons()}</div> <Routes> {/* 公开路由:无需登录即可访问 */} <Route exact path='/' element={<LandingPage />} /> <Route path="/login" element={<LoginPage />} /> {/* 受保护路由:未登录自动跳转到登录页 */} <Route element={<ProtectedRoute />}> <Route path="authorform" element={<AuthorForm />} /> {/* 可在此添加更多需要保护的路由 */} </Route> </Routes> </div> ); }
步骤3:验证效果
- 未登录状态下访问
/:正常显示LandingPage,无跳转 - 未登录状态下访问
/authorform:自动跳转到/login - 登录后访问
/authorform:正常显示AuthorForm - 点击logout:跳转到
/login,符合预期
内容的提问来源于stack exchange,提问作者Mostafa Mohamed
相关产品推荐
相关产品推荐

