Oauth2 Google身份验证流-Next.JS/Express

Oauth2 Google身份验证流-Next.JS/Express,express,oauth-2.0,next.js,google-authentication,Express,Oauth 2.0,Next.js,Google Authentication,我正在使用React/Next.Js前端,并试图用Google的Oauth2策略实现身份验证 我对这个过程感到非常困惑 目前在客户端上,我有一个Google登录组件,其中包含一个客户端ID,可以检索访问令牌 <GoogleLogin clientId="myclientid" buttonText="Login" onSuccess={userLogin} onFailure={us

我正在使用React/Next.Js前端,并试图用Google的Oauth2策略实现身份验证

我对这个过程感到非常困惑

目前在客户端上,我有一个Google登录组件,其中包含一个客户端ID,可以检索访问令牌

      <GoogleLogin
            clientId="myclientid"
            buttonText="Login"
            onSuccess={userLogin}
            onFailure={userLogin}
            cookiePolicy={'single_host_origin'}
  />
在后端,我使用passport,路径如下所示:

import express from 'express';
import passport from 'passport';
import Logger from '../logger/index';

const router = express.Router();

export function isAuthenticated(req:express.Request, res:express.Response, next : any) {
    return req.isAuthenticated() ?
        next() :
        res.sendStatus(401);
 }  

  router.get('/fail', (_req:express.Request, res:express.Response) => {
    res.json({ loginFailed: true });
  });

  router.post('/google', passport.authenticate('google', { scope: ['profile']}), (_req:express.Request, _res:express.Response) => {
    Logger.info("GET Request at Google Authentication endpoint received.");
  });

  router.get(
    '/google/callback',
    passport.authenticate('google', { failureRedirect: '/login' }),
    (_req:express.Request, res:express.Response) => {
      res.redirect('/graphql');
    }
  );

export default router;
module.exports = function(passport : any, GoogleStrategy : any){
  passport.use(new GoogleStrategy({
    clientID: config.google.client_id,
    clientSecret: config.google.client_secret,
    callbackURL: config.google.redirect_url
  },
  function(accessToken : string, profile : Profile, refreshToken : string, cb : any) {
    return cb(null, {
      id: profile.googleId,
      username: profile.email,
      image: profile.imageUrl,
      firstName: profile.givenName,
      surname: profile.familyName,
      accessToken: accessToken,
      refreshToken: refreshToken
    })
  }
  ));
}
我的passport模块如下所示:

import express from 'express';
import passport from 'passport';
import Logger from '../logger/index';

const router = express.Router();

export function isAuthenticated(req:express.Request, res:express.Response, next : any) {
    return req.isAuthenticated() ?
        next() :
        res.sendStatus(401);
 }  

  router.get('/fail', (_req:express.Request, res:express.Response) => {
    res.json({ loginFailed: true });
  });

  router.post('/google', passport.authenticate('google', { scope: ['profile']}), (_req:express.Request, _res:express.Response) => {
    Logger.info("GET Request at Google Authentication endpoint received.");
  });

  router.get(
    '/google/callback',
    passport.authenticate('google', { failureRedirect: '/login' }),
    (_req:express.Request, res:express.Response) => {
      res.redirect('/graphql');
    }
  );

export default router;
module.exports = function(passport : any, GoogleStrategy : any){
  passport.use(new GoogleStrategy({
    clientID: config.google.client_id,
    clientSecret: config.google.client_secret,
    callbackURL: config.google.redirect_url
  },
  function(accessToken : string, profile : Profile, refreshToken : string, cb : any) {
    return cb(null, {
      id: profile.googleId,
      username: profile.email,
      image: profile.imageUrl,
      firstName: profile.givenName,
      surname: profile.familyName,
      accessToken: accessToken,
      refreshToken: refreshToken
    })
  }
  ));
}
由于Next.js是服务器端渲染的,因此我无法使用save令牌。我知道我得用饼干。但是这是如何工作的呢?我无法从express后端重定向客户端浏览器

目前我只看到以下两个错误:

OPTIONS https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2localhost:3000%2Fdashboard&scope=profile&client_id=687602672235-l0uocpfchbjp34j1jjlv8tqv7jadb8og.apps.googleusercontent.com 405

Access to XMLHttpRequest at 'https://accounts.google.com/o/oauth2/v2/auth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A4000%2Fbackoffice.dev.myos.co%2Fdashboard&scope=profile&client_id=687602672235-l0uocpfchbjp34j1jjlv8tqv7jadb8og.apps.googleusercontent.com' (redirected from 'http://localhost:4000/auth/google') from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

首先,我认为google auth无法在本地主机上工作。
如果我在服务器端逻辑中理解正确,您可以轻松地将令牌保存为cookie,然后在客户端中读取它们

passport不确定,但您可以执行类似操作:
(我的应用程序正在使用此代码的实现)

前端:

  <GoogleLogin
        clientId="myclientid"
        buttonText="Login"
        onSuccess={userLogin}
        onFailure={userLogin}
        cookiePolicy={'single_host_origin'}
/>
然后在后端,您可以使用
谷歌认证库
登录或注册。
server.js

const {OAuth2Client} = require('google-auth-library');
const GOOGLEID = "mygoogleid.apps.googleusercontent.com"
const client = new OAuth2Client(GOOGLEID);
var cookieParser = require('cookie-parser')

async function verify(userToken) {
    const ticket = await client.verifyIdToken({
    idToken: userToken,
    audience: "clientid.apps.googleusercontent.com",  // Specify the CLIENT_ID of the app that accesses the backend
   // Or, if multiple clients access the backend:
   //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  return payload
  // If request specified a G Suite domain:
  //const domain = payload['hd'];
}
server.js中
类似于以下内容的路由:

   server.get('/google-login/:token',(req,res) => {
    const userToken =  req.params.token
    var  result =  verify(userToken).then(function(result){
      var userName = result.given_name
      var userSurname = result.family_name
      var userEmail = result.email
      /*
        Now user is authenticated i can send to the frontend
        user info or user token o save the token to session
      */
    }).catch(function(err){
      // error handling
    })
  })
你可以用它来处理这件事。
为了测试localhost,您应该使用它向web公开您的localhost服务器,并在google platform中配置给定的url

以澄清,在前端,我调用google服务,并返回一个包含访问令牌的对象。我从我的前端发布到后端,它通过调用GoogleAPI来验证这个访问令牌。成功后,我应该将某些内容发送回前端,这是一个cookie?这取决于您需要什么,您可以在后端设置cookie,或者您可以只发送回令牌(在验证后)并从前端设置cookie。