我正在创建一个React Native应用程序,用户应该可以使用Facebook登录(当然)。我在节点后端使用快速会话(与MongoDB结合存储会话)与护照(本地策略)和passport-facebook(Facebook策略)集成,以实现某种会话管理,用户不会在在关闭应用程序后,需要再次登录。 一切都适合当地的战略;用户可以登录,并在会话到期之前向API发出请求。 我试图让Facebook的策略正常运行,但我现在面临的问题是我几天来一直试图解决这个问题...
使用React Native,该应用程序将弹出一个窗口,询问您的Facebook凭据,询问该应用是否可以使用您的个人资料的必要信息。这发生在以下代码中:
// Set up Linking
componentDidMount() {
// Add event listener to handle OAuthLogin:// URLs
Linking.addEventListener('url', this.handleOpenURL);
// Launched from an external URL
Linking.getInitialURL().then((url) => {
if (url) {
this.handleOpenURL({ url });
}
});
}
componentWillUnmount() {
// Remove event listener
Linking.removeEventListener('url', this.handleOpenURL);
}
loginWithFacebook() {
this.openURL('http://localhost:3002/v1/auth/facebook');
}
// Open URL in a browser
openURL(url) {
// Use SafariView on iOS
if (Platform.OS === 'ios') {
SafariView.show({
url: url,
fromBottom: true
});
}
// Or Linking.openURL on Android
else {
Linking.openURL(url);
}
}
handleOpenURL({ url }) {
const [, user_string] = url.match(/user=([^#]+)/);
console.log(JSON.parse(decodeURI(user_string)));
let result = JSON.parse(decodeURI(user_string));
if(result.success) {
this.props.loginFbComplete(result.user);
} else {
}
if (Platform.OS === 'ios') {
SafariView.dismiss();
}
}
单击“登录”屏幕中的按钮时,将调用loginWithFacebook()。一切都按计划运行,因此Facebook开发者帐户已正确配置。
在后端,我的passport-facebook策略配置如下:
// Register Facebook Passport strategy
passport.use(new FacebookStrategy.Strategy(facebook,
function (req, accessToken, refreshToken, profile, done) {
process.nextTick(function() {
Users.findOne(
{
Provider: 'facebook',
ProviderId: profile.id,
Email: profile.emails[0].value
}, (err, user) => {
if (err) {
return done(err, null);
} else {
if (!user) {
let providerData = profile._json;
providerData.accessToken = accessToken;
providerData.refreshToken = refreshToken;
let providerUserProfile = {
FullName: profile.displayName,
FirstName: profile.name.givenName,
LastName: profile.name.familyName,
Email: profile.emails[0].value,
Provider: 'facebook',
ProviderId: profile.id,
ProviderData: providerData,
};
let newUser = new Users(providerUserProfile);
newUser.save((err) => {
if (err) {
return done(err, null);
} else {
return done(null, newUser);
}
});
} else {
return done(null, user);
}
}
}
);
});
}
));
deserializeUser function:
passport.deserializeUser(function(id, done) {
Users.findById(id, function(err, user) {
done(err, user);
});
});
serializeUser函数:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
对于身份验证路由,添加以下内容:
router.route('/auth/facebook')
.get((req, res, next) => {
passport.authenticate('facebook')(req, res, next)
});
对于Facebook登录成功/失败后的回叫路线,添加以下内容:
router.route('/auth/facebook/callback')
.get(loginFbUser);
const loginFbUser = (req, res) => {
passport.authenticate('facebook', (error, user, info) => {
let result = {};
console.log('REQ SESSION 1', req.session);
if (error || !user) {
result = {success: false, message: info.message};
return res.redirect('OAuthLogin://login?user=' + JSON.stringify(result))
} else if (user) {
req.login(user, loginErr => {
if (loginErr) {
result = {success: false, message: loginErr.message};
} else {
Users.findOneAndUpdate({_id: user._id}, {LastOnline: new Date()}, {new: true}).lean().exec((err, testUser) => {
if (err) {
result = {success: false, message: err.message};
} else if (!testUser) {
result = {success: false, message: 'User not found.'};
} else {
result = {success: true, user: testUser};
}
console.log('isAuthenticated?', req.isAuthenticated());
req.session.save(function() {
console.log('session after save', req.session);
res.redirect('OAuthLogin://login?user=' + JSON.stringify(result));
});
});
}
});
}
})(req, res);
};
第一个console.log显示会话中没有设置护照(user._id)的会话。 在req.login()函数之后,我可以清楚地看到用户通过req.isAuthenticated()方法进行了身份验证。我强迫用req.session.save()将会话保存到MongoDB。在最后一个console.log中,我可以看到与第一个console.log-statement的区别; user(_id)被添加到会话中。 我在我的React Native应用程序中重定向回正确的路由以捕获facebook登录的结果。问题出在这里:当我在登录后执行另一个请求时,用户会话消失了,它是空的,用户实际上未经授权执行对API的任何进一步请求,会话被清除,我有不明白为什么。
有没有人知道这可能是什么?