使用 Oauth2、React、Node.js 和 Passport.js 通过 Google 登录按钮对用户进行身份验证的最佳实践是什么?

IT技术 reactjs express authentication oauth-2.0 passport.js
2021-05-25 11:11:51

我想在我的网站上有一个登录按钮,这样当用户点击它时,用户就可以使用他们的 Google 凭据。我想理想地使用 Express.js 和 Passport.js 执行身份验证服务器端。

我在服务器端实现了身份验证,但问题是我无法从网站向服务器发出 AJAX 请求以启动身份验证,因为Google 或 Oauth 不支持 CORS所以我需要a href在我的网站中使用元素来调用服务器身份验证端点。但是,我无法以这种方式捕获服务器响应。

如果我在客户端执行身份验证(我正在使用 React),我可以在 Redux 中存储登录状态并允许用户访问网站的资源。但是,当用户注销时,我需要确保服务器端点停止为同一用户提供服务,这感觉就像实现了两次身份验证:客户端和服务器端。

此外,在对客户端进行身份验证时,Google 会打开一个弹出窗口供用户进行身份验证,我认为这比对服务器端进行身份验证时的重定向更糟糕。

我想知道使用 Oauth2/Google 进行身份验证的最佳实践是什么。例如,stackoverflow.com 也有 Google 按钮,但只是进行重定向,没有任何弹出窗口,所以我猜他们想出了一种执行服务器端身份验证和绕过 CORS 问题的方法。

3个回答

您的身份验证应该在服务器端完成。下面是它的工作原理。

  1. 拨打fetchaxios调用您的身份验证路由。
  2. 您的身份验证路由向 Google 的身份验证服务器发送请求。这在后端很重要,因为您需要提供您的clientSecret. 如果您将其存储在前端,那么有人会很容易找到该value并破坏您的网站。
  3. Google 对用户进行身份验证,然后向您发送一组令牌到您的回调 URL 以供该用户使用(刷新、身份验证等...)。然后,您将使用 auth 令牌进行任何额外的授权,直到它过期。
  4. 一旦过期,您将使用刷新令牌为该客户端获取新的授权令牌。不过,这是一个完全不同的过程。

以下是 Passport.js 的示例:https : //github.com/jaredhanson/passport-google-oauth2

编辑#1:

这是一个示例,其中包含与 Facebook 一起使用的流程的注释,这是相同的 OAuth 代码库:https : //github.com/passport/express-4.x-facebook-example/blob/master/server.js

我遇到了同样的问题。这篇文章是黄金链接

1.在身份验证路由文件中,我有以下代码

 const CLIENT_HOME_PAGE_URL = "http://localhost:3000";

  // GET  /auth/google
  // called to authenticate using Google-oauth2.0
  router.get('/google', passport.authenticate('google',{scope : ['email','profile']}));


  // GET  /auth/google/callback
  // Callback route (same as from google console)
   router.get(
    '/google/callback',  
    passport.authenticate("google", {
    successRedirect: CLIENT_HOME_PAGE_URL,
    failureRedirect: "/auth/login/failed"
   })); 

   // GET  /auth/google/callback
  // Rest Point for React to call for user object From google APi
   router.get('/login/success', (req,res)=>{
     if (req.user) {
         res.json({
          message : "User Authenticated",
         user : req.user
        })
     }
     else res.status(400).json({
       message : "User Not Authenticated",
      user : null
    })
  });

2.在React端当用户点击调用上面的/auth/google api的按钮后

  loginWithGoogle = (ev) => {
    ev.preventDefault();
    window.open("http://localhost:5000/auth/google", "_self");
  }

3.这将重定向到 Google 身份验证屏幕并重定向到 /auth/google/callback 再次重定向到react应用主页 CLIENT_HOME_PAGE_URL

4.在首页调用用户对象的休息端点

(async () => {
  const request = await fetch("http://localhost:5000/auth/login/success", {
   method: "GET",
   credentials: "include",
   headers: {
    Accept: "application/json",
     "Content-Type": "application/json",
    "Access-Control-Allow-Credentials": true,
  },
});

const res = await request.json();
   //In my case I stored user object in redux store
   if(request.status == 200){
     //Set User in Store
    store.dispatch({
      type: LOGIN_USER,
      payload : {
        user : res.user
     }
    });
  }

})();

5.最后在nodemodule的server.js/index.js中添加cors包和如下代码

// Cors
app.use(
  cors({
    origin: "http://localhost:3000", // allow to server to accept request from different origin
    methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
    credentials: true // allow session cookie from browser to pass through
   })
);

Redux 真的可以帮助实现这一点,这遵循与 Nick B 已经解释过的相同的逻辑......

  1. 您在服务器端设置 oauth 并提供进行该调用的端点
  2. 您在react前端上设置按钮并通过操作将其连接到您已经设置的端点
  3. 端点提供一个令牌返回,您可以通过减速器将其分派到中央 redux 存储。
  4. 该令牌现在可用于将用户设置为经过身份验证

你有它。