电子邮件字段在 passportjs facebook 策略中是可选的

email field is optional in passportjs facebook strategy

我编写了使用 facebook 登录的代码,一切正常,我正在获取用户的电子邮件地址。但是 facebook 上还有另一个选项,它允许用户 select 我的应用程序将要访问的数据。

如果用户点击它,他将看到名称和所有标记为必需的内容,但电子邮件是可选的,用户可以将其从将要提供给应用程序的数据中删除。

在申请中,需要电子邮件。那么我如何才能在 facebook 上将电子邮件标记为需要?

这是我在代码中使用的片段。

passport.use(new FacebookStrategy({
        clientID: config.social.facebook.clientID,
        clientSecret: config.social.facebook.clientSecret,
        callbackURL: config.url+'auth/facebook/cb',
        enableProof: false,
        profileFields:['id', 'name', 'emails'],
        scope: "email"
    }, function(accessToken, refreshToken, profile, done) {
        // doing the rest of the thing
    }
));

// ...

app.get('/auth/facebook', passport.authenticate('facebook', {scope: ['email']}));
app.get('/auth/facebook/cb', passport.authenticate('facebook'), function(req, res, next) {
    res.redirect("/");
});

我通过重新请求权限解决了问题。

结果我可以将 authType: 'rerequest' 添加到 passport.authenticate('facebook', {scope: ['email'], authType: 'rerequest'})

我所做的是检查结果中是否存在 emails 字段,如果不存在,我调用 done 并出错。

function(accessToken, refreshToken, profile, done) {
    if (profile.emails === undefined) {
        done('email-required')
        return;
    }
    // doing the rest of the thing
}

然后为了捕获错误,我不得不为 passport.authenticate('facebook') 编写自定义回调。

app.get('/auth/facebook/cb', function(req, res, next) {
    passport.authenticate('facebook', function (err, user, info) {
        if (err) {
            if (err == 'email-required') res.redirect('/auth/facebook/rerequest');
            // check for other kinds of errors and show proper messages
            return;
        }
        req.user = user;
        // do the rest of the thing
    })(req, res, next)
});

如您所见,我将用户重定向到另一条路线 /auth/facebook/rerequest 以防出现错误。

app.get('/auth/facebook/rerequest',
    passport.authenticate('facebook', {
        scope: ['email'],
        authType: 'rerequest' // this is important
    }
));

这将再次将用户重定向到 FB 上的同一页面,这次需要电子邮件字段。我不能在同一条路线上做到这一点;显然它使用相同的生成代码与 fb 通信,这是 fb 不能接受的。

这就是我设法解决问题的方法。

您需要在 profileFields 的 Strategy 中指定电子邮件 属性

passport.use('facebook', new FacebookStrategy({
  clientID: config.facebook.appId,
  clientSecret: config.facebook.appSecret,
  callbackURL: config.facebook.callbackURL,
  profileFields: ['emails', 'first_name', 'last_name', 'locale', 'timezone']
}, function (token, refreshToken, profile, done) {
  // you will get emails in profile.emails
}));