如何实现Next.js前端到Node.js后端的Google用户认证
独立Node.js后端(Passport.js)+ Next.js前端 Google 认证实现方案
核心思路
不能直接在Next.js前端调用Google认证的回调URL,因为回调URL是后端Passport.js用来接收Google返回的授权码、完成用户信息校验与存储的专属接口。前端的核心作用是引导用户跳转到后端的Google认证发起接口,后续流程由后端与Google交互完成,最后再回调到前端并处理登录状态。
具体实现步骤
1. 后端配置确认
确保你的Node.js后端已配置好Passport.js的Google策略,且存在两个关键接口:
- 发起认证接口(如
/auth/google):用于重定向用户到Google授权页面 - 回调处理接口(如
/auth/google/callback):接收Google返回的授权码,完成用户信息验证、存入MySQL,最后生成会话或JWT并跳转到前端指定页面
示例后端Express路由:
// 发起Google认证 app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] })); // 回调处理逻辑 app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: 'http://localhost:3000/login' }), (req, res) => { // 生成JWT(若用会话则无需此步骤,直接依赖express-session) const token = jwt.sign({ userId: req.user.id }, 'your-secret-key'); // 跳转到前端登录成功页并携带token res.redirect(`http://localhost:3000/login-success?token=${token}`); } );
2. Next.js前端登录页实现
在Next.js中创建登录页面(如pages/login.js),添加Google登录按钮,点击后直接跳转到后端的认证发起接口:
export default function LoginPage() { const handleGoogleLogin = () => { window.location.href = 'http://localhost:3001/auth/google'; }; return ( <div className="login-container"> <h1>账号登录</h1> <button onClick={handleGoogleLogin} className="google-login-btn"> 用Google账号登录 </button> </div> ); }
3. 前端处理登录回调
当后端完成Google认证后,会跳转到前端指定页面(如pages/login-success.js),这里需要获取后端传递的token,存储到本地并完成页面跳转:
import { useEffect } from 'react'; import { useRouter } from 'next/router'; export default function LoginSuccessPage() { const router = useRouter(); useEffect(() => { const token = router.query.token; if (token) { // 将token存入localStorage,供后续接口请求使用 localStorage.setItem('authToken', token); // 跳转到主页 router.push('/'); } else { // 无有效token,返回登录页 router.push('/login'); } }, [router]); return <div>登录成功,正在跳转...</div>; }
4. 前端接口请求的身份校验
后续前端调用后端API时,需在请求头中携带token,示例用axios实现:
import axios from 'axios'; const api = axios.create({ baseURL: 'http://localhost:3001/api', }); // 请求拦截器,自动携带token api.interceptors.request.use((config) => { const token = localStorage.getItem('authToken'); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }); // 示例:调用需认证的用户信息接口 export const fetchUserProfile = async () => { const response = await api.get('/profile'); return response.data; };
5. 后端身份校验中间件
后端需添加中间件验证前端传递的token有效性,确保接口仅对已认证用户开放:
const jwt = require('jsonwebtoken'); const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; if (!token) return res.sendStatus(401); jwt.verify(token, 'your-secret-key', (err, user) => { if (err) return res.sendStatus(403); req.user = user; next(); }); }; // 示例:需认证的用户信息接口 app.get('/api/profile', authenticateToken, (req, res) => { db.query('SELECT * FROM users WHERE id = ?', [req.user.userId], (err, results) => { if (err) throw err; res.json(results[0]); }); });
关键注意事项
- 跨域配置:后端需使用
cors中间件允许前端域名请求,示例:const cors = require('cors'); app.use(cors({ origin: 'http://localhost:3000', credentials: true })); - Google开发者控制台:确保回调URL设置为后端的回调接口(如
http://localhost:3001/auth/google/callback),并添加前端、后端地址到授权来源列表。 - 会话与JWT选择:若用会话,需配置
express-session结合MySQL存储会话;JWT更适合前后端分离场景,无需会话存储。
内容的提问来源于stack exchange,提问作者Sajib Hossain
相关产品推荐
相关产品推荐

