CORS 问题从 React 应用程序 > 节点服务器 > 重定向到 Google OAuth2 身份验证发出 AJAX 请求

IT技术 node.js ajax reactjs authentication oauth-2.0
2021-05-16 01:11:29

大家好,过去 2 天我一直在努力研究这个,但没有运气。

这是我尝试从我的 React 应用程序 @localhost:3000 使用 Google Oauth2 Passport 策略进行身份验证时遇到的错误。我正在 localhost:3001 上运行一个带有节点/快速服务器的单独应用程序。

XMLHttpRequest 无法加载 http:localhost:3001/api/auth/google/login。从“http:localhost:3001/api/auth/google/login”重定向到“https:accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A3001%2Fapi %2Fauth%2Fgoogle%2Fcallback&scope=https%3A%2F%2Fmail.google.com&client_id=***.apps.googleusercontent.com”已被 CORS 策略阻止:没有“Access-Control-Allow-Origin”标头存在于请求的资源。因此不允许访问源 'http:localhost:3000'。

createError.js:16 

Uncaught (in promise) Error: Network Error at createError (createError.js:16) at XMLHttpRequest.handleError (xhr.js:87)

这是我在客户端中使用的代码,用于尝试从我的组件之一登录:

// 按钮

<div>
   <button className="btn btn-danger" onClick={props.googleAuth}>
      Login With Google
   </button>
</div>

// 有状态的组件方法

googleAuth() {
    axios.get("http:localhost:3001/api/auth/google/login").then(res => {
      console.log("GOOGLE OAUTH 2 RES", res);
    });
  }

// 控制器

passport.use(
  new GoogleStrategy(
    {
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: "/api/auth/google/callback",
      accessType: "offline"
    },
    (accessToken, refreshToken, profile, done) => {
      const info = {
        googleUsername: profile.displayName,
        googleAccessToken: accessToken,
        googleRefreshToken: refreshToken,
        googleEmail: profile.emails[0].value
      };

      User.findOrCreate({
        where: {
          googleId: profile.id
        },
        defaults: info
      })
        .spread(user => {
          if (user) return done(null, user.toAuthJSON); 
          // this is method that returns a signed JWT off user DB instance. 
          return done(null, false);
        })
        .catch(done);
    }
  )
);

// GOOGLE LOGIN

router.get(
  "/login",
  passport.authenticate("google", {
    scope: [
      "https://mail.google.com/",
      "https://www.google.com/m8/feeds/",
      "email",
      "profile"
    ]
  })
);

// GOOGLE CALLBACK
router.get(
  "/callback",
  passport.authenticate("google", {
    session: false,
  }), (req, res) => {
    res.json(req.user.token)
  }
);

我已经尝试解决的步骤:

  • 我在浏览器上禁用了 CORS
  • 我在服务器端的路由/api 上尝试了 cors npm module似乎没有任何效果。
  • 还有很多其他的修补和绝望......

  • 基于错误,谷歌阻止我从我的服务器发出下游请求并抛出错误(我认为)......

我的目标是:

  • 我希望谷歌返回一个用户对象,然后我将其存储在我的数据库中(已经为此编码逻辑)
  • 我不想让服务器 res.redirect() 我想要 res.json() 一个签名的 JWT(我已经正确连接了)。
  • 我不想在我的服务器上使用基于会话的身份验证并保持干净和无状态。

这甚至可能吗?还应该注意,我有一个开发环境设置:

服务器同时启动(同时启动客户端和 nodemon 服务器 - client@localhost:3000 向 server@localhost:3001 发出代理请求) - 不确定这是否会导致任何问题?

任何帮助将不胜感激!

1个回答

所以我能够解决这个问题。问题是您正在使用passport.js社交身份验证,而您可以简单地使用类似的东西

https://www.npmjs.com/package/react-social-login

但无论如何我都会告诉你如何让你当前的项目工作。

https://github.com/j-mcfarlane/Reactjs-SocialAuth-RESTAPI

您需要重定向到 UI 而不是 api。所以你的配置会像下面一样改变

googleCallbackURL: 'http://localhost:3000/api/auth/google/callback'

接下来在您的回调中,您将返回如下所示的重定向,而不是返回数据

jwt.sign(payload, secret, { expiresIn: 220000 }, (err, token) => {
    if (err) return console.log(err)

    res.redirect("http://localhost:3000/login?token=" + token);
})

我已经硬编码到,localhost:3000但您应该获取hostfrom 请求然后使用它。

接下来,您将更新您的App.js以添加另一个路由/login,这将调用一个组件SocialLogin

import React, { Component, Fragment } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

import PrivateRoute from '../util/PrivateRoute'

// Components
import Navbar from './layout/Navbar'

import Landing from './Landing'
import SocialLogin from './SocialLogin'
import Dashboard from './Dashboard'

class App extends Component {
    render() {
        return (
            <Router>
                <Fragment>
                    <Navbar /><br />

                    <Route exact path="/" component={Landing} />
                    <Route exact path="/login" component={SocialLogin} />

                    <Switch>
                        <PrivateRoute path="/dashboard" component={Dashboard} />
                    </Switch>
                </Fragment>
            </Router>

        )
    }
}

export default App

SocialLogin我写的最简单的如下

import React from 'react'
import qs from 'query-string'

const SocialLogin = (props) => {
    console.log(props.location.search)
    let params = qs.parse(props.location.search)
    window.localStorage.setItem('token', params['token'])
    return (<div>Landing Page - {params.token} </div>)
}

export default SocialLogin

在这里,您拥有令牌,您可以按照自己喜欢的方式继续流程。也在Google.js我下面改了

<button onClick={this.googleAuth}>Signin With Google</button>

回到你的评论

<a href="/api/auth/google">Log in with google</a>

你需要重定向才能工作,你不应该 AJAX 你的 google auth 调用,否则如何使用选择一个帐户?

现在在所有这些修复之后,我能够获得如下所示的令牌

UI 上的令牌