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

Dal*_*eri 2 node.js cors oauth-2.0 express passport.js

我正在尝试使用 Google OAuth 身份验证设置 React/Redux - NodeJs Express 堆栈。我的问题是控制台中的 COR 错误。我发现了一些我认为正是我的问题的 Stack Overflow 问题,但解决方案没有产生任何结果。特别是这两个:CORS与谷歌的OAuthCORS / CORB问题与之反应/节点/ Express和谷歌的OAuth

因此,我尝试了各种修复方法,这些修复方法似乎都使我回到了相同的错误。这是其中最直接的:

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

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

访问 XMLHttpRequest ' 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。 .googleusercontent.com '(重定向自 ' http://localhost:5000/api/oauth/google ')来自原点 'null' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:否 '请求的资源上存在 Access-Control-Allow-Origin 标头。

因此,如果我在开发工具中查看我的网络日志,我会查看我对 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
Run Code Online (Sandbox Code Playgroud)

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

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

和回调路线:

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

最后,简化策略:

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)
}));
Run Code Online (Sandbox Code Playgroud)

我知道所有这些都不会导致任何功能,但我只是尽可能多地撕掉了绒毛,试图了解我的身份验证流程中的块在哪里。以防万一它可能有助于缩小范围,这里是 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
        })
    }
};
Run Code Online (Sandbox Code Playgroud)

这实际上从未达到返回值,并且不会记录第二个console.log记录。

Yil*_*maz 5

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

问题出在CRA 开发人员服务器express api 服务器之间。您正在从localhost:3000localhost:5000发出请求。要解决此问题,请使用代理。

在客户端目录中:

npm i http-proxy-middleware --save
Run Code Online (Sandbox Code Playgroud)

client/src 中创建setupProxy.js文件。无需在任何地方导入它。create-react-app会寻找这个目录

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

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

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

这是更多详细信息的链接:

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

默认情况下,password.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
}
Run Code Online (Sandbox Code Playgroud)

这里重要的一件事是,您应该了解为什么使用代理。据我了解,从你的代码来看,从浏览器中,你向 express 发出请求,express 将使用 password.js 处理身份验证。password.js 运行完所有认证步骤后,它会创建一个 cookie,用 id 填充它,将它交给 express,然后 express 将它发送到浏览器。这是您的应用程序结构:

 BROWSER ==> EXPRESS ==> GOOGLE-SERVER
Run Code Online (Sandbox Code Playgroud)

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

现在 react 只与 express-server 通信。

  BROWSER ==> EXPRESS
Run Code Online (Sandbox Code Playgroud)

由于 react 和 exress 不在同一个端口上,因此您会收到 cors 错误。

有2个解决方案。1 正在使用cors包。

它的设置非常简单

var express = require('express')
var cors = require('cors')
var app = express()
 
app.use(cors()) // use this before route handlers
Run Code Online (Sandbox Code Playgroud)

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

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
});
Run Code Online (Sandbox Code Playgroud)