基于Google Identity Sign-In的React+Node.js登录重定向与身份认证问题
Hey there! Let's sort out your React Router v6 redirect and route protection problems—since the old Redirect component is gone, we’ve got modern tools to handle this cleanly with your tech stack (Google Identity, React, Node.js, JWT in sessionStorage).
1. Redirecting to Dashboard After Successful Login
In React Router v6, programmatic redirects are handled with the useNavigate hook instead of the deprecated Redirect component. Here’s how to integrate it into your Google Sign-In flow:
First, import the hook and use it after validating the user’s JWT and storing it in sessionStorage:
import { useNavigate } from 'react-router-dom'; function Login() { const navigate = useNavigate(); const handleGoogleLoginSuccess = async (credentialResponse) => { // Send Google's ID token to your Node.js backend for verification const response = await fetch('/api/verify-google-token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ idToken: credentialResponse.credential }) }); if (response.ok) { const { jwt } = await response.json(); // Store the validated JWT in sessionStorage sessionStorage.setItem('jwt', jwt); // Redirect to dashboard immediately navigate('/dashboard', { replace: true }); } else { console.error('Login failed: Invalid token or server error'); } }; return ( <> {/* Google Sign-In button setup */} <div id="g_id_onload" data-client_id="YOUR_GOOGLE_CLIENT_ID" data-callback={handleGoogleLoginSuccess} data-auto_prompt="false" ></div> <div className="g_id_signin" data-type="standard" data-size="large" data-theme="outline" data-text="sign_in_with" data-shape="rectangular" data-logo_alignment="left" ></div> </> ); }
The replace: true option ensures the login page is removed from the browser’s history stack, so users can’t click back to it after logging in.
2. Blocking Unauthorized Access to Dashboard
To protect your dashboard route, create a custom ProtectedRoute component that checks for a valid JWT in sessionStorage. If the user isn’t authenticated, it redirects them to the login page. This is the official recommended pattern for route protection in React Router v6.
Step 1: Create the ProtectedRoute Component
import { Navigate, Outlet } from 'react-router-dom'; export function ProtectedRoute() { // Check if JWT exists in sessionStorage const isAuthenticated = sessionStorage.getItem('jwt') !== null; // Optional: Add backend validation to confirm JWT is still valid // (Prevents users from tampering with sessionStorage values) // const [isTokenValid, setIsTokenValid] = useState(false); // useEffect(() => { // const validateToken = async () => { // const response = await fetch('/api/validate-jwt', { // headers: { 'Authorization': `Bearer ${sessionStorage.getItem('jwt')}` } // }); // setIsTokenValid(response.ok); // }; // if (isAuthenticated) validateToken(); // }, [isAuthenticated]); // Render protected content if authenticated, else redirect to login return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />; }
Step 2: Update Your Route Configuration
Wrap your dashboard route with the ProtectedRoute in your main router setup:
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import Login from './Login'; import Dashboard from './Dashboard'; import { ProtectedRoute } from './ProtectedRoute'; function App() { return ( <Router> <Routes> {/* Public login route */} <Route path="/login" element={<Login />} /> {/* Protected dashboard route */} <Route path="/dashboard" element={<ProtectedRoute />}> <Route index element={<Dashboard />} /> {/* Add dashboard sub-routes here (e.g., /dashboard/profile) */} </Route> {/* Default route: Redirect unrecognized paths to login */} <Route path="*" element={<Navigate to="/login" replace />} /> </Routes> </Router> ); }
Critical Notes
- Backend Validation is Mandatory: Frontend route protection is convenient but can be bypassed. Always validate the JWT on your Node.js server using Google’s official verification function for every API request to protected endpoints.
- Handle JWT Expiry: Add logic to detect expired tokens (either decode the JWT client-side or hit a backend validation endpoint) and clear
sessionStoragebefore redirecting to login. - Clean Up on Logout: When users sign out, clear the JWT from
sessionStorageand redirect to the login page withnavigate('/login', { replace: true }).
内容的提问来源于stack exchange,提问作者Mayank Yadav

