saw*_*wim 5 node.js facebook-oauth reactjs passport-facebook passport.js
我正在使用 Node 开发简单的 Web 应用程序,并使用 Facebook 身份验证进行反应。我还遵循了一些有关该主题的教程,但在这些实现中,客户端和后端位于同一服务器上。在这里,我的后端服务器在 localhost:5000 上运行,并在 localhost:3000 上运行应用程序。在react package.json中有到后端的代理,因此客户端知道如何调用api。
\n\n当我单击“使用 Facebook 登录”按钮时,我将重定向到 Facebook 页面,在其中我授权应用程序并接收我的客户端应用程序配置文件 ID 和其他请求的用户信息。然而,当我将用户信息发送到后端服务器时,我可以在控制台中看到以下错误:
\n\n\n\n\n跨源请求被阻止:同源策略不允许读取远程资源https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fapi%2Fauth%2Ffacebook% 2Fcallback&client_id=1617633901657669。(原因:CORS 标头 \xe2\x80\x98Access-Control-Allow-Origin\xe2\x80\x99 丢失)。
\n
下面你可以看到:
\n\n\n\n\n类型错误:尝试获取资源时出现网络错误。\n [了解更多]
\n
Facebook 应用程序设置:
\n\n\n\nOAuth 路由器:
\n\nconst router = require(\'express\').Router();\nconst passport = require(\'../config/facebook-passport\');\n\nrouter.get(\'/facebook\', passport.authenticate(\'facebook\'));\n\nrouter.get(\'/facebook/callback\',\n passport.authenticate(\'facebook\', { failureRedirect: \'/login\' }),\n function(req, res) {\n console.log(\'Successful authentication, redirect home\');\n res.redirect(\'/\');\n });\n\nmodule.exports = router;\nRun Code Online (Sandbox Code Playgroud)\n\n护照脸书:
\n\nconst passport = require(\'passport\');\nconst FacebookStrategy = require(\'passport-facebook\').Strategy;\n\npassport.use(new FacebookStrategy({\n clientID: process.env.CLIENTID,\n clientSecret: process.env.CLIENTSECRET,\n callbackURL: "/api/auth/facebook/callback"\n},\nfunction(accessToken, refreshToken, profile, done) {\n console.log(accessToken, refreshToken, profile)\n}\n));\nmodule.exports = passport;\nRun Code Online (Sandbox Code Playgroud)\n\n应用程序.js:
\n\napp.use(bodyParser.json());\napp.use(bodyParser.urlencoded({ extended: false }));\napp.use(cookieParser());\napp.use(session({\n secret: \'3cr3ts#tr\',\n resave: true,\n saveUninitialized: true\n}));\napp.use(passport.initialize());\napp.use(passport.session());\n\napp.use(\'/api/users\', users);\napp.use(\'/api/oauth\', oauth);\napp.get(\'/api/hello\', ensureAuthenticated, function(req, res, next) {\n res.send({express: \'Hello there\'})\n});\n\napp.listen(5000);\n\nfunction ensureAuthenticated(req, res, next) {\n if (req.isAuthenticated()) {\n return next();\n }\n res.status(401);\n res.send({express: "you need to authenticate"})\n}\nRun Code Online (Sandbox Code Playgroud)\n\n登录反应组件:
\n\nimport FacebookLogin from \'react-facebook-login\';\n\nclass Login extends Component {\n sendFacebookResponse(response) {\n fetch(`/api/oauth/facebook?${Object.keys(response).map(k => k+\'=\'+response[k]).join(\'&\')}`)\n }\n\nrender() {\n return (\n <FacebookLogin\n appId="1617633901657669"\n autoLoad={true}\n fields="name,email,picture"\n callback={this.sendFacebookResponse} />\n );\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n我的应用程序配置正确吗?如何消除 CORS 错误?任何帮助或建议将不胜感激。
\n首先,我从Passport-facebook切换到Passport-facebook-token。
然后我添加了2个护照策略。Facebook 用作身份验证提供者,jwt 则用于授权请求。
const FacebookStrategy = require('passport-facebook-token');
const passportJWT = require('passport-jwt');
passport.use(new FacebookStrategy({
clientID: <FB CLIENT ID>,
clientSecret: <FB CLIENT SECRET>
},
(token, refreshToken, profile, done) => {
// here there should be code responsible for fetching user from database based on facebook profile, saving user if it doesn't exist yet etc.
done(null, user);
}
));
// this will parse jwtPayload (sent as header; "Authorization: Bearer <JWT TOKEN>") into user object, which will be added to request objects in express router endpoints handlers
passport.use('jwt', new passportJWT.Strategy({
jwtFromRequest: passportJWT.ExtractJWT.fromAuthHeaderAsBearerToken(),
secretOrKey: "secret salt"
}, (jwtPayload, done) => {
done(null, jwtPayload);
}));
Run Code Online (Sandbox Code Playgroud)
然后我添加了用于用户身份验证的端点。Passport-facebook-token库期望获取从客户端应用程序发送的 facebook 访问令牌作为查询参数 access_token=FACEBOOK_ACCESS_TOKEN。通过fb成功授权后,可以生成jwt令牌,发送到客户端应用程序并用于请求授权。
const { sign } = require('jsonwebtoken');
router.get(
'/facebook-token',
passport.authenticate('facebook-token', {session: false}),
(req, res, next) => {
res
.send({
token: sign(req.user, "secret salt" /* the same value that was used to configure jwt passport above */, {})
})
});
Run Code Online (Sandbox Code Playgroud)
现在用户应该经过身份验证,换句话说,应该在上面的端点中生成一个 jwt 令牌。下一个请求中的客户端应用程序应该添加授权标头,这在前面已经提到过。
端点可以通过 Passport 库提供的中间件函数来保护,在这种情况下,passport.authenticate('jwt', {session: false}) 返回一个使用 jwt 策略的函数。
router.get('/secured-endpoint', passport.authenticate('jwt', {session: false}), (req, res, next) => {
res.send("hello world")
// there is req.user object that can be used for user specific actions
});
Run Code Online (Sandbox Code Playgroud)