You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 08:24:56