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

MERN栈使用Passport实现Google认证时的CORS错误求助

MERN中Passport Google登录的CORS问题解决

问题描述

在MERN应用中使用Passport实现Google登录认证时,直接在新标签页打开错误提示中的认证链接可正常完成流程,但通过Axios发起请求时触发CORS错误:从http://localhost:3000访问重定向后的Google认证地址时,因目标资源缺少Access-Control-Allow-Origin头被CORS策略拦截。

错误信息

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fgoogle%2Fcallback&scope=profile%20email&client_id=1000813228585-k44nrfc0plt3kmupqu4rqcj0qcohhm35.apps.googleusercontent.com' (redirected from 'http://localhost:8000/auth/google') from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

当前配置代码

CORS配置

app.use(cors({
  origin: ["http://localhost:3000"," https://accounts.google.com"], // 注意:第二个origin前有多余空格
        methods: "GET,POST,PUT,DELETE",
        credentials: true,
}));

Passport路由

CLIENT_URL=http://localhost:3000

router.get("/google", passport.authenticate("google", ["profile"]));
router.get("/google/callback", passport.authenticate("google", {
    successRedirect: process.env.CLIENT_URL,
    failureRedirect: "/login/failed",
}));

router.get("/login/failed", (req, res) => {
    res.status(401).json({
        error: true,
        message: "Log in failure",
    });
});

客户端Axios请求

REACT_APP_API_URL=http://localhost:8000

export const googleLoginReq = async () => {
  try {
    let res = await axios.get(`${REACT_APP_API_UR}/auth/google`, { withCredentials: true }); // 注意:REACT_APP_API_UR拼写错误
    return res.data;
  } catch (error) {
    console.log(error);
  }
};

请求头信息

General

Request URL: https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fgoogle%2Fcallback&scope=profile%20email&client_id=1000813228585-k44nrfc0plt3kmupqu4rqcj0qcohhm35.apps.googleusercontent.com
Request Method: GET
Status Code: 200 
Referrer Policy: strict-origin-when-cross-origin

响应头

alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"
cache-control: no-cache, no-store, max-age=0, must-revalidate
content-encoding: gzip
content-security-policy: require-trusted-types-for 'script';report-uri /cspreport
content-security-policy: script-src 'report-sample' 'nonce-TOmywtPu0Qo8iQCEZhMnTw' 'unsafe-inline' 'unsafe-eval';object-src 'none';base-uri 'self';report-uri /cspreport
content-type: text/html; charset=utf-8
cross-origin-opener-policy-report-only: same-origin; report-to="coop_gse_qebhlk"
date: Wed, 25 Jan 2023 10:01:03 GMT
expires: Mon, 01 Jan 1990 00:00:00 GMT
p3p: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info."
pragma: no-cache
report-to: {"group":"coop_gse_qebhlk","max_age":2592000,"endpoints":[{"url":"https://csp.withgoogle.com/csp/report-to/gse_qebhlk"}]}
server: GSE
set-cookie: __Host-GAPS=1:WBh43ekzNFz-U7PJu6wrySL4P0fJVw:-8nse8F4eB1X5yrO;Path=/;Expires=Fri, 24-Jan-2025 10:01:02 GMT;Secure;HttpOnly;Priority=HIGH
strict-transport-security: max-age=31536000; includeSubDomains
x-content-type-options: nosniff
x-frame-options: DENY
x-xss-protection: 1; mode=block

请求头

:authority: accounts.google.com
:method: GET
:path: /o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fgoogle%2Fcallback&scope=profile%20email&client_id=1000813228585-k44nrfc0plt3kmupqu4rqcj0qcohhm35.apps.googleusercontent.com
:scheme: https
accept: application/json, text/plain, */*
accept-encoding: gzip, deflate, br
accept-language: en-IN,en-US;q=0.9,en;q=0.8
cookie: __Secure-3PAPISID=0fADWvGybtHw6h4E/AuZfyvMRCsCGQG4m9; __Secure-3PSID=TAgcETHlEPmlnVokgxJP67RdvdDCwLo6zS5s8W_yA_tnNn79ks2clkRgFmsvP0yZRult_A.; __Host-3PLSID=o.chat-dl.google.com|o.chat.google.com|o.console.cloud.google.com|o.drive.google.com|o.mail.google.com|o.meet.google.com|o.myaccount.google.com|s.IN|s.youtube:TAgcET_mZKiKd0P8KBaXK00vnWmuYQPOt8sRxUc75wk7hbKaEbtuam5S-oCMNPtkvpnT_w.; NID=511=ui5rQ6D8-KrHAUOn491ZvzQP7VdaQ-r94ktEYHfqHSWwWXK9E29AWZYBZMZRE8g9Zesepsp6c6lp-VjKU1dUWus4ICU9FkArFbf7bw5E6wQFcb9mOasQA0yV1qPgVErv49i1GLrgpHc373TwTqgC1Oah1nme4oaN2VBBN-r5YyAXun1eL4P-u3Iw7W6SV7ExIqnkunp4bQoG9ThcP5DjlkyDy14sK_YuV5EZwGIm9P6a18SsDcHDE2quUps7_LdjcE_CRL_OcB8v53R-Y9msRdxrBNGhY23yvgFbVkANBh5wKElpTvfTG7vxrDxZW_8Ol3LcM_wmKdD1ePuPHQrh4v1wQ29i16Vd0Z7obEEfP2hdig; LSOLH=AH+1Ng3ry+24BKCDnw1k/j8gBn5vXNTEUY4wwBo52xPp9smoYZt/jdHVLmQLmcStBp6zxduzEbOG; 1P_JAR=2023-01-25-10; __Secure-3PSIDCC=AIKkIs3zFB8Qc0Oo3-AzH4hzyJkZFsjp0ZEMsrezMMUBxtGeayEzfxjxwSaygz9LHj3OTAhrEdFL
origin: null
referer: http://localhost:3000/
sec-ch-ua: "Not_A Brand";v="99", "Google Chrome";v="109", "Chromium";v="109"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36

Google API凭证配置

Google API凭证配置截图

解决方案

1. 核心修正:改用浏览器直接跳转而非AJAX请求

Google OAuth2授权码流程要求浏览器直接跳转到Google登录页,AJAX请求会触发跨域检查,但Google的认证接口不会返回允许localhost:3000的CORS头,必然被拦截。

替换客户端登录逻辑:

export const googleLoginReq = () => {
  // 修正拼写错误:REACT_APP_API_UR → REACT_APP_API_URL
  window.location.href = `${process.env.REACT_APP_API_URL}/auth/google`;
};

或在组件中直接使用a标签:

<a href={`${process.env.REACT_APP_API_URL}/auth/google`}>Google登录</a>

2. 修正CORS配置错误

移除origin数组中https://accounts.google.com前的多余空格,且无需将Google域名加入CORS允许列表(Google不会使用你的CORS配置):

app.use(cors({
  origin: ["http://localhost:3000"],
  methods: "GET,POST,PUT,DELETE",
  credentials: true,
}));

3. 修正客户端代码拼写错误

将REACT_APP_API_UR改为REACT_APP_API_URL,避免跳转地址错误。

4. 确认Google凭证配置

确保Google API凭证中的授权重定向URI与后端Passport配置的redirect_uri完全一致(即http://localhost:8000/auth/google/callback),从截图看当前配置正确,无需修改。


内容的提问来源于stack exchange,提问作者Deepanshu Gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 11:01:34