以下是我为此构建解决方案/策略所依据的所有资源:
https://medium.com/free-code-camp/how-to-set-up-twitter-oauth-using-passport-js-and-reactjs-9ffa6f49ef0 https://medium.com/@techsuneel99/jwt-authentication-in-nodejs-refresh-jwt-with-cookie-based-token-37348ff685bf 将社交登录(使用 Google 登录)添加到现有电子邮件/密码应用程序和数据库的最佳方式是什么? 使用 Oauth2、React、Node.js 和 Passport.js 通过 Google 登录按钮对用户进行身份验证的最佳实践是什么?
====================================
我有一个 FE React 应用程序在 localhost:3000 中运行,我的后端在 Node Express 中运行在 localhost:5000
我正在尝试使用护照库实现Google登录。只需简单的谷歌登录就可以了。然而我对下一步做什么有点困惑。因为我也有一个使用电子邮件/密码的登录/注册,如果用户使用谷歌登录,我想看看我的数据库中是否已经有一个使用该电子邮件的用户。如果是这样,我就会与该用户建立关联,并从我的数据库获取他们的数据,而不是使用他们的谷歌个人资料。我想我还想生成自己的 JWT 令牌来处理我的系统中的身份验证。然后我会将该令牌返回给我的 FE,以将其用作承载令牌进行身份验证。 如果没有用户,FE 会将用户重定向到注册页面
所以,这是我想到的流程以及我如何实现它:
React FE (localhost:3000) 在 localhost:5000/auth/google 上调用 BE 我在 FE 中的 GoogleLoginButton 组件:
import type React from 'react'
export const GoogleLoginButton: React.FC = () => {
const handleGoogleLogin = (ev) => {
ev.preventDefault()
window.open('http://localhost:5000/auth/google', '_self')
}
return (
<a href="#" onClick={handleGoogleLogin}>
Login with Google
</a>
)
}
以及BE中的路由定义:
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
BE 调用谷歌服务,用户登录,我获得用户谷歌个人资料、访问令牌和刷新令牌(不确定我如何处理这些令牌,因为我将生成自己的 jwt - 我猜什么也没有?)
以下是带护照的Google策略的相关实现:
passport.use(
new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID || 'fakeId',
clientSecret: process.env.GOOGLE_CLIENT_SECRET || 'fakeSecret',
callbackURL: '/auth/google/callback',
passReqToCallback: true
},
async (_req, _accessToken, _refreshToken, profile, done) => {
let existingUser = await oauthTokenService.findUserByEmail(profile.emails[0].value, 'mybrand');
if (!existingUser) {
console.log("We will send nothing for now as user will have to register on FE")
return done(null, undefined);
}
return done(null, existingUser);
},
),
);
在这里,我在数据库中查找具有该电子邮件帐户的现有用户,以防该用户已经使用密码/用户名流程注册(这已经在系统中完成)
这里我有使用护照的 jwt 策略:
passport.use(
"jwt_strategy",
new JwtStrategy(
{
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: 'myFakeSecretKey',
},
async (payload, done) => {
const user = await User.findByPk(payload.id)
if (user) {
return done(null, user);
} else {
return done(null, false);
}
}
)
);
我的想法是,我想将该令牌返回到我的前端,并用它来检查用户是否登录。
最后这是我的 /auth/google/callback 处理程序:
app.get('/auth/google/callback',
passport.authenticate("google", {
failureRedirect: "/failedLogin",
session:false
}),
function (req, res) {
const token = jwt.sign({user:{"email":req.user.email},id: req.user.id, clientId:'myFakeClientId'}, 'fakeSecretKey');
res.send( {token })
}
);
以及仅当我在授权标头中传递有效的承载令牌时才返回我的用户数据的端点:
app.get('/getDetails', passport.authenticate('jwt_strategy', { session: false }), (req, res)=>{
console.log("Request on getDetails:")
console.log(req.user);
return res.status(200).json({
message: 'User authenticated',
user: req.user,
});
});
如果我像上面那样做,我会成功获得令牌,并且我可以在 Insomnia/Postman 上测试对我的用户详细信息的请求是否正常工作。问题是,在我的 FE 中,在整个流程之后,我被发送到 localhost:5000/auth/google/callback,这当然只是显示带有我的令牌的 json 对象。
我尝试添加 successRedirect 所以它现在保持这样:
app.get('/auth/google/callback',
passport.authenticate("google", {
failureRedirect: "/failedLogin",
successRedirect: "http://localhost:3000",
session:false
}),
function (req, res) {
const token = jwt.sign({user:{"email":req.user.email},id: req.user.id, clientId:'myFakeClientId'}, 'fakeSecretKey');
console.log("Token? ")
console.log(token)
res.send( {token })
}
);
它确实将我带到了 localhost:3000 但随后我没有生成令牌,因为我认为该函数不会执行,因为此时已经发生了重定向。
我需要能够将令牌返回给我的 FE,但我当然不希望浏览器转到 localhost:5000/auth/google/callback。我想留在原地。我怎样才能做到这一点?另外,由于这对我来说有点新鲜,如果有更好的流程,请随时提出建议
我现在也有同样的问题,请问你找到解决办法了吗,请告诉我方法