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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 09:49:58