【问题标题】:Can I have multiple facebook strategies for passport?我可以为护照设置多个 Facebook 策略吗?
【发布时间】:2015-11-14 12:05:29
【问题描述】:

我想以不同的方式处理以下与护照相关的操作。

  1. 在 Facebook 上注册
  2. 使用 Facebook 登录
  3. 将现有帐户连接到 Facebook

对于“注册”,我想做/检查:

  • 如果用户已经存在(基于 facebook oauth id),重定向到登录。
  • 如果用户已经存在(基于 facebook 个人资料中的电子邮件地址),提示用户使用电子邮件登录,然后连接他们的 facebook 帐户。
  • 创建一个新用户并登录。

对于“登录”和“连接帐户”,我想执行一系列其他检查/操作。

我查看了 passport documentation for facebookpassport-facebook module 以及一堆相关的 Stack Overflow 问题,但我仍在努力解决如何实现这一点。

如何使用不同的回调 URL 和选项实现不同的 Facebook 策略(通过护照)?

【问题讨论】:

    标签: javascript node.js facebook passport.js passport-facebook


    【解决方案1】:

    经过大量挖掘,这就是我最终要做的:


    创建 3 个单独的护照策略。

    每个都有不同的名称(facebookSignUp vs facebookLogIn vs facebookConnect)和不同的回调 URL 路径(.../sign-up/clbk vs .../log-in/clbk vs .../connect/clbk)。

    // facebook strategy 1 (sign-up with facebook)
    passport.use('facebookSignUp', new FacebookStrategy({
            clientID: FACEBOOOK_APP_ID,
            clientSecret: FACEBOOK_APP_SECRET,
            callbackURL: 'http://website/auth/facebook/sign-up/clbk'
        },
        function(accessToken, refreshToken, profile, clbk) {
            return clbk(profile);
        }
    ));
    
    // facebook strategy 2 (log-in with facebook)
    ...
    
    // facebook strategy 3 (connect facebook to existing account) 
    ...
    

    为每个策略创建路线。

    facebook认证后的初始请求路由和回调路由。所以每个策略有 2 条路线。

    var member = require('../member');              // member module controller
    
    // sign-up with facebook
    app.route('/auth/facebook/sign-up')
        .get(member.facebookSignUp);                // passport redirect to facebook for authentication
    
    // sign-up with facebook callback
    app.route('/auth/facebook/sign-up/clbk')
        .get(
        member.facebookSignUpClbk,                  // parse facebook profile to create new user & check for existing account -> redirect to log-in route
        member.checkEmail,                          // check if email is already used -> throw error 'please log in with email, then connect facebook in settings'
        member.checkUrl,                            // get unique url
        member.signUp,                              // create new user & sign-in
        member.email.welcome,                       // send welcome email
        member.facebookRedirectDashboard            // redirect to member dashboard
    );
    
    // log-in with facebook
    app.route('/auth/facebook/log-in')
        .get(member.facebookLogIn);                 // passport redirect to facebook for authentication
    
    // log-in with facebook callback
    app.route('/auth/facebook/log-in/clbk')
        .get(
        member.facebookLogInClbk,                   // authenticate user and log-in & check if user exists (fb oauth id or email address) -> throw error 'please sign up with facebook or log in with email'
        member.lastLogin,                           // update user's last login field
        member.facebookRedirectDashboard            // redirect to dashboard
    );
    
    // connect facebook profile to existing account
    ...
    
    // connect facebook profile to existing account clbk
    ...
    

    在以下文件/函数中执行实际的护照身份验证。

    member.facebookSignUp 只是调用 passport.authenticate(),它会重定向到 facebook。

    // member.facebookSignUp
    exports.facebookSignUp = function(req, res, next) {
        passport.authenticate('facebookSignUp', {          // use the 'facebookSignUp' strategy
            display: null,                                 // null = let facebook decide (or 'page' (default), 'popup', 'touch', etc)
            scope: [
                'public_profile',                          // profile returned by default, but specified here anywhere
                'email',                                   // ask for email address
                'user_location'                            // ask for location
            ]
        })(req, res);
    };
    

    member.facebookSignUpClbk 在 facebook 授权用户并重定向到回调路由后执行。这是其他一切发生的地方。

    // member.facebookSignUpClbk
    exports.facebookSignUpClbk = function(req, res, next) {
    
        // parse profile & plug into req.body for new user creation in later fxn
        function parseProfile(profile) {
            // user doc
            req.body = {};
            // facebook profile data
            req.body.facebook = (profile._json) ? profile._json : {id: profile.id};
            // name
            ...
            // email
            ...
            next();
        }
    
        // check existing users (mongoose/mongodb)
        function checkUser(profile) {
            User.findOne({query}, function(err, userDoc) {
                if (err) {
                    return res.redirect(
                        'http://'+req.headers.host+
                        '?header=Sign-Up Error!'+
                        '&message=We had trouble signing you up with Facebook. Please try again'
                    );
                } else if (userDoc) {
                    // redirect to log-in fxn
                    return res.redirect('http://website/auth/facebook/log-in');
                } else {
                    parseProfile(profile);
                }
            });
        }
    
        // passport authentication
        function passportAuth() {
            passport.authenticate('facebookSignUp', function(profile) {
                if (!profile || !profile.id) {
                    return res.redirect(
                        'http://'+req.headers.host+
                        '?header=Sign-Up Error!'+
                        '&message=We had trouble signing you up with Facebook. Please try again or sign-up via email.'
                    );
                } else {
                    checkUser(profile);
                }
            })(req, res);
        }
    
        // start process
        passportAuth();
    };
    

    member.facebookLogIn、.facebookLogInClbk、.facebookConnect 和 .facebookConnectClbk 的设置方式类似,只是“Clbk”函数中的逻辑不同,具体取决于我要执行的操作。


    希望这会有所帮助!

    【讨论】:

    • 感谢您的努力
    • 首都发现!我面临着类似的问题。这太棒了。
    猜你喜欢
    • 2014-06-03
    • 2021-09-02
    • 2020-01-04
    • 1970-01-01
    • 1970-01-01
    • 2022-12-24
    • 2021-11-01
    • 2021-05-12
    • 2012-06-09
    相关资源
    最近更新 更多