React+dj-rest-auth登录后仍可访问登录页面的问题排查
问题:登录后仍可访问/login页面
我在Django项目中使用dj-rest-auth作为认证端点,前端采用ReactJS开发。当前存在问题:用户登录后仍能访问/login页面,这不符合预期。
现有代码
LoginForm组件
import React, { useState } from 'react'; import { Form, Button, Alert, Container } from 'react-bootstrap'; import axios from 'axios'; import { useNavigate } from 'react-router-dom'; const LoginForm = () => { const navigate = useNavigate(); const [credentials, setCredentials] = useState({ username: '', password: '' }); const [error, setError] = useState(null); const handleChange = (e) => { const { name, value } = e.target; setCredentials((prevCredentials) => ({ ...prevCredentials, [name]: value })); }; const validateCredentials = () => { if (credentials.username.length < 4) { setError('Username must be longer than 4 characters.'); return false; } if (credentials.password.length < 8) { setError('Password must be at least 8 characters.'); return false; } return true; }; const handleSubmit = async (e) => { e.preventDefault(); if (!validateCredentials()) { return; } try { const response = await axios.post('http://localhost:8000/api-auth/login/', credentials); const token = response.data.token; localStorage.setItem('token', token); navigate('/rants'); } catch (error) { handleLoginError(error); } }; const handleLoginError = (error) => { console.log(error.response); if (error.response && error.response.status === 400) { const errorMessage = error.response.data.non_field_errors ? error.response.data.non_field_errors[0] : 'An error occurred while processing your request. Please try again later.'; setError(errorMessage); } else { setError('An unexpected error occurred. Please try again later.'); } }; return ( <Container className="mt-5"> <h2>Login</h2> {error && <Alert variant="danger">{error}</Alert>} <Form onSubmit={handleSubmit}> <Form.Group className="mb-3" controlId="formUsername"> <Form.Label>Username</Form.Label> <Form.Control type="text" placeholder="Enter username" name="username" value={credentials.username} onChange={handleChange} /> </Form.Group> <Form.Group className="mb-3" controlId="formPassword"> <Form.Label>Password</Form.Label> <Form.Control type="password" placeholder="Enter password" name="password" value={credentials.password} onChange={handleChange} /> </Form.Group> <Button variant="primary" type="submit"> Login </Button> </Form> </Container> ); }; export default LoginForm;
AuthContext代码
// AuthContext.js import { createContext, useContext, useState } from 'react'; const AuthContext = createContext(); export const AuthProvider = ({ children }) => { const [token, setToken] = useState(localStorage.getItem('token') || null); const login = (newToken) => { setToken(newToken); localStorage.setItem('token', newToken); }; const logout = () => { setToken(null); localStorage.removeItem('token'); }; return ( <AuthContext.Provider value={{ token, login, logout }}> {children} </AuthContext.Provider> ); }; export const useAuth = () => useContext(AuthContext);
解决方案
你需要补充登录态校验和路由权限控制的配置,具体步骤如下:
1. 给LoginForm添加登录态校验
在LoginForm组件中,通过useAuth获取当前登录状态,组件渲染时如果检测到已有token,直接跳转到主页:
// 先补充导入useEffect和useAuth import React, { useState, useEffect } from 'react'; import { useAuth } from './AuthContext'; const LoginForm = () => { const { token } = useAuth(); const navigate = useNavigate(); // 组件挂载/登录状态变化时检查 useEffect(() => { if (token) { navigate('/rants'); } }, [token, navigate]); // 原有代码保持不变... };
2. 实现路由守卫(推荐规范做法)
创建路由守卫组件,统一管理页面访问权限:
// ProtectedRoute.js import { Navigate, Outlet } from 'react-router-dom'; import { useAuth } from './AuthContext'; // 保护需要登录才能访问的页面(比如主页) export const ProtectedRoute = () => { const { token } = useAuth(); return token ? <Outlet /> : <Navigate to="/login" />; }; // 限制已登录用户访问的页面(比如登录、注册) export const RestrictedRoute = () => { const { token } = useAuth(); return token ? <Navigate to="/rants" /> : <Outlet />; };
然后在路由配置中使用这两个守卫:
// App.js或路由配置文件 import { Routes, Route } from 'react-router-dom'; import { ProtectedRoute, RestrictedRoute } from './ProtectedRoute'; import LoginForm from './LoginForm'; import RantsPage from './RantsPage'; // 你的主页组件 import { AuthProvider } from './AuthContext'; function App() { return ( <AuthProvider> <Routes> {/* 已登录用户无法进入登录页 */} <Route element={<RestrictedRoute />}> <Route path="/login" element={<LoginForm />} /> </Route> {/* 未登录用户无法进入主页 */} <Route element={<ProtectedRoute />}> <Route path="/rants" element={<RantsPage />} /> </Route> </Routes> </AuthProvider> ); }
3. 优化登录逻辑(和AuthContext联动)
将LoginForm中直接操作localStorage的逻辑,改成调用AuthContext的login方法,保持状态统一:
const { login } = useAuth(); // 导入login方法 const handleSubmit = async (e) => { e.preventDefault(); if (!validateCredentials()) return; try { const response = await axios.post('http://localhost:8000/api-auth/login/', credentials); const token = response.data.token; login(token); // 用AuthContext的方法管理token,而非直接操作localStorage navigate('/rants'); } catch (error) { handleLoginError(error); } };
内容的提问来源于stack exchange,提问作者Vicente Antonio G. Reyes
相关产品推荐
相关产品推荐

