Node +中的CORS错误使用护照对facebook身份验证做出反应

时间:2018-03-12 19:07:44

标签: node.js reactjs passport.js facebook-oauth passport-facebook

我正在使用节点开发简单的webapp并使用facebook身份验证做出反应。我还关注了这个主题的一些教程,但在这些实现中,客户端和后端位于同一台服务器上。在这里,我的后端服务器可以在localhost:5000上工作,并在localhost:3000上做出反应。在react package.json中有后端代理,因此客户端知道如何调用api。

当我点击“使用Facebook登录”按钮时,我将重定向到Facebook页面,在那里我授权应用程序并接收到我的客户端应用程序个人资料ID和其他请求的用户iformation。 Hovewer,当我将用户信息发送到我的后端服务器时,我可以在控制台中看到这个错误:

  

阻止跨源请求:同源策略禁止在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应用设置:

  1. enter image description here
  2. enter image description here
  3. enter image description here
  4. 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;
    

    护照Facebook的:

    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错误?任何帮助或建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

首先,我从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
});