使用护照进行 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策略时无法将用户序列化到会话中

Facebook护照身份验证,导出passport.authenticate方法

护照 未知的身份验证策略“本地”、“脸书”、“谷歌”

模块导出,nodejs对于护照身份验证需要太长时间

无法使用 facebook 的护照成功重定向

未知的身份验证策略护照