使用护照进行 Facebook 身份验证的 Node+react 应用程序中的 CORS 错误
Posted
技术标签:
【中文标题】使用护照进行 Facebook 身份验证的 Node+react 应用程序中的 CORS 错误【英文标题】:CORS error in Node+react app with facebook authentication using passport 【发布时间】:2018-08-20 22:04:12 【问题描述】:我正在使用 node 开发简单的 webapp,并使用 facebook 身份验证做出反应。我也关注了一些关于这个主题的教程,但在这些实现中,客户端和后端位于同一台服务器上。在这里,我的后端服务器在 localhost:5000 上工作,并在 localhost:3000 上响应应用程序。在 react package.json 中有后端代理,所以客户端知道如何调用 api。
当我单击“使用 facebook 登录”按钮时,我会重定向到 facebook 页面,在该页面我授权应用程序并接收到我的客户端应用程序配置文件 ID 和其他请求的用户信息。然而,当我将用户信息发送到我的后端服务器时,我可以在控制台中看到这个错误:
跨域请求被阻止:同源策略不允许读取位于https://www.facebook.com/dialog/oauth?response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2Fapi%2Fauth%2Ffacebook%2Fcallback&client_id=1617633901657669 的远程资源。 (原因:缺少 CORS 标头“Access-Control-Allow-Origin”)。
你可以在下面看到:
TypeError:尝试获取资源时出现 NetworkError。 [了解更多]
Facebook 应用设置:
OAuth 路由器:
const router = require('express').Router();
const passport = require('../config/facebook-passport');
router.get('/facebook', passport.authenticate('facebook'));
router.get('/facebook/callback',
passport.authenticate('facebook', failureRedirect: '/login' ),
function(req, res)
console.log('Successful authentication, redirect home');
res.redirect('/');
);
module.exports = router;
护照脸书:
const passport = require('passport');
const FacebookStrategy = require('passport-facebook').Strategy;
passport.use(new FacebookStrategy(
clientID: process.env.CLIENTID,
clientSecret: process.env.CLIENTSECRET,
callbackURL: "/api/auth/facebook/callback"
,
function(accessToken, refreshToken, profile, done)
console.log(accessToken, refreshToken, profile)
));
module.exports = passport;
app.js:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded( extended: false ));
app.use(cookieParser());
app.use(session(
secret: '3cr3ts#tr',
resave: true,
saveUninitialized: true
));
app.use(passport.initialize());
app.use(passport.session());
app.use('/api/users', users);
app.use('/api/oauth', oauth);
app.get('/api/hello', ensureAuthenticated, function(req, res, next)
res.send(express: 'Hello there')
);
app.listen(5000);
function ensureAuthenticated(req, res, next)
if (req.isAuthenticated())
return next();
res.status(401);
res.send(express: "you need to authenticate")
登录反应组件:
import FacebookLogin from 'react-facebook-login';
class Login extends Component
sendFacebookResponse(response)
fetch(`/api/oauth/facebook?$Object.keys(response).map(k => k+'='+response[k]).join('&')`)
render()
return (
<FacebookLogin
appId="1617633901657669"
autoLoad=true
fields="name,email,picture"
callback=this.sendFacebookResponse />
);
我的应用配置正确吗?如何摆脱 CORS 错误?任何帮助或建议将不胜感激。
【问题讨论】:
看看***.com/questions/49058042/… 推荐的插件不起作用,此外,我正在寻找解决方案,而不是 hack ;) 完全理解。这就是为什么它是评论而不是答案。 【参考方案1】:首先,我从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);
));
然后我添加了用于用户身份验证的端点。 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 */, )
)
);
现在用户应该经过身份验证,换句话说,应该在上面的端点生成一个 jwt 令牌。下一个请求中的客户端应用程序应该添加之前提到的授权标头。
可以通过护照库提供的中间件函数保护端点,在这种情况下,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
);
【讨论】:
以上是关于使用护照进行 Facebook 身份验证的 Node+react 应用程序中的 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章
使用带护照本地的护照Facebook策略时无法将用户序列化到会话中