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

时间:2017-08-24 20:38:55

标签: node.js ajax reactjs authentication oauth-2.0

大家好,我过去2天一直在研究这个问题而没有运气。

这是我尝试使用我的React app @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 =代码&安培; REDIRECT_URI = HTTP%3A%2F%2Flocalhost%3A3001%2Fapi%2Fauth%2Fgoogle%2Fcallback&安培;范围= HTTPS%3A% 2F%2Fmail.google.com&安培; CLIENT_ID = *** apps.googleusercontent.com&#39。   被CORS政策阻止:No' Access-Control-Allow-Origin'   标头出现在请求的资源上。起源   ' HTTP:本地主机:3000'因此不允许访问。

createError.js:16 

未捕获(承诺)错误:网络错误         at createError(createError.js:16)         在XMLHttpRequest.handleError(xhr.js:87)

这是我在客户端尝试从我的某个组件登录的代码:

// BUTTON

<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);
    });
  }

// CONTROLLER

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
  • 我在服务器端的routes / api上尝试了cors npm模块 似乎没什么用。
  • 还有很多其他的修补和绝望......

  • 根据错误,Google阻止我从我的服务器发出下游请求并抛出错误(我认为)......

我的目标是什么:

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

这是否可能?还应该注意我有一个开发环境设置:

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

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:2)

所以我能够解决这个问题。问题是你使用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,但您应该从请求中获取host然后再使用它。

接下来,您将更新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认证调用,否则将如何使用选择帐户?

现在经过所有这些修复后,我可以获得如下所示的令牌

Token on UI