CORs 错误:Google Oauth 从 React 到 Express (PassportJs 验证)



我正在尝试使用Google OAuth身份验证设置一个React/Redux - NodeJs Express堆栈。我的问题是控制台中出现 COR 错误。我发现了一些我认为完全是我的问题的堆栈溢出问题,但解决方案没有产生任何结果。具体来说,这两个:带有google oauth的CORS和React/Node/Express和google OAuth的CORS/CORB问题。

所以我尝试了各种修复程序,这些修复程序似乎都会导致我回到相同的错误。这是其中最直接的:

const corsOptions = {
origin: 'http://localhost:3000',
optionsSuccessStatus: 200,
credentials: true
}
app.use(cors(corsOptions));

这是我API.js文件的根目录。我收到的控制台错误状态:

CORS 策略已阻止从源"null"访问位于"https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fapi%2Foauth%2Fgoogle%2Freturn&scope=profile&client_id=PRIVATE_CLIENT_ID.apps.googleusercontent.com"处的 XMLHttpRequest(从"http://localhost:5000/api/oauth/google"重定向(:对预检请求的响应未通过访问控制检查:无"访问控制-允许源"标头存在于请求的资源上。

因此,如果我在开发工具中查看我的网络日志,我会查看我对 API 路径的请求,并查看我希望看到的内容:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: content-type
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: http://localhost:3000

所以在我看来,我的问题不在我前后的沟通范围内。这让我相信这可能是护照令牌验证的问题。以下是我的简化路线:

router.post('/oauth/google', passport.authenticate('googleVerification', {
scope: ['profile']
}), (req, res) => {
console.log('Passport has verified the oauth token...');
res.status(200)
});

和回调路由:

router.get('/oauth/google/return', (req, res) => {
console.log('google oauth return has been reached...')
res.status(200)
});

最后,简化策略:

passport.use('googleVerification', new GoogleStrategy({
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_SECRET,
callbackURL: 'http://localhost:5000/api/oauth/google/return'
}, (accessToken, refreshToken, profile, cb) => {
console.log('Passport OAuth Strategy reached');
cb(null, profile)
}));

我知道所有这些都不会导致任何功能,但我只是尽可能多地撕掉了绒毛,试图掌握身份验证流中的块在哪里。以防万一可能有助于缩小范围,这里是 Redux 中的操作创建器,它在错误开始出现之前记录流程的最后一步("redux 接受令牌并传递给 API:",令牌(:

export const signIn = (token) => {
console.log('redux accepting token and passing to API:', token)
return async dispatch => {
const res = await Axios({
method: 'post',
url: `${API_ROOT}/api/oauth/google`,
withCredentials: true,
data: {
access_token: token
}
})
console.log('API has returned a response to redux:', res)
dispatch({
type: SIGN_IN,
payload: res
})
}
};

这实际上永远不会到达返回值,也不会记录记录的第二个console.log

CORS与向Google发出请求无关,因为当您在console.developers.google.com中注册应用程序时,它已经由Google处理。

问题出在CRA 开发人员服务器和快速 API 服务器之间。您正在从本地主机:3000 向本地主机:5000发出请求。要解决此问题,请使用代理。

在客户端目录中:

npm i http-proxy-middleware --save

客户端/src中创建setupProxy.js文件。无需将其导入任何地方。创建反应应用程序将查找此目录

将您的代理添加到此文件:

module.exports = function(app) {
app.use(proxy("/auth/google", { target: "http://localhost:5000" }));
app.use(proxy("/api/**", { target: "http://localhost:5000" }));
};

我们说做一个代理,如果有人试图在我们的反应服务器上访问路由/api 或/auth/google,会自动将请求转发到localhost:5000

以下是更多详细信息的链接:

https://create-react-app.dev/docs/proxying-api-requests-in-development/

默认情况下密码.js不允许代理请求。

passport.use('googleVerification', new GoogleStrategy({
clientID: process.env.OAUTH_CLIENT_ID,
clientSecret: process.env.OAUTH_SECRET,
callbackURL: 'http://localhost:5000/api/oauth/google/return',
proxy:true
}

这里很重要的一件事是,您应该了解为什么使用代理。据我从您的代码,从浏览器中了解到,您向表达式发出请求,Express 将使用密码处理身份验证.js。password.js运行完所有认证步骤后,它会创建一个cookie,塞上id,给快递,快递就会发送到浏览器。这是您的应用结构:

BROWSER ==> EXPRESS ==> GOOGLE-SERVER

浏览器会自动将 cookie 附加到发出 cookie 的服务器的请求。因此,浏览器知道哪个cookie属于哪个服务器,因此当他们向该服务器发出新请求时,他们会附加它。但是在你的应用程序结构中,浏览器没有与谷歌服务器通信。如果您没有使用代理,您将通过 express 从 GOOGLE-SERVER 获取 cookie,但由于您没有向 GOOGLE-SERVER 发出请求,因此不会使用 cookie,它不会自动附加。这就是使用 cookie 的重点,浏览器会自动附加 cookie。通过设置代理,现在浏览器不知道谷歌服务器。据它所知,它正在向快递服务器发出请求。因此,每次浏览器请求使用相同的端口表达时,它都会附加cookie。我希望这部分是清楚的。

现在 react 只与快递服务器通信。

BROWSER ==> EXPRESS

由于 React 和 ExreS 不在同一端口上,因此会出现 CORS 错误。

有 2 种解决方案。 1 是使用 CORS 包。

它的设置非常简单

var express = require('express')
var cors = require('cors')
var app = express()

app.use(cors()) // use this before route handlers

第二种解决方案是在路由处理程序之前手动设置中间件

app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE"
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next(); // dont forget this
});

最新更新