使用Passport和OAuth2 +社交网络的NodeJS REST身份验证
我正在使用NodeJS
的REST
API。为了验证,我决定使用Passport
。我想要真正的RESTful api。所以这意味着我必须使用令牌而不是会话。使用Passport和OAuth2 +社交网络的NodeJS REST身份验证
我想让用户使用用户名和密码登录,或使用Facebook,Google和Twitter等社交网络。
我制作我自己的OAuth2.0
服务器用于发行Access
和Refresh tokens
使用oauth2orize
模块。所以现在我可以注册新用户,然后发布它们的令牌。 我跟着这个教程:
http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/
验证用户的路线:
// api ------------------------------------------------------------------------------------
app.get('/api/userInfo',
passport.authenticate('bearer', { session: false }),
function(req, res) {
// req.authInfo is set using the `info` argument supplied by
// `BearerStrategy`. It is typically used to indicate scope of the token,
// and used in access control checks. For illustrative purposes, this
// example simply returns the scope in the response.
res.json({ user_id: req.user.userId, name: req.user.username, scope: req.authInfo.scope })
}
);
这一切都工作得很好。不幸的是我不知道如何实现社交认证。
我阅读本教程:
http://scotch.io/tutorials/javascript/easy-node-authentication-facebook
但在本教程中他们没有做一个真正的RESTful API。根据本教程,我已经实现了用户模式,其中本地用户的令牌存储在分离的模型中。
// define the schema for our user model
var userSchema = mongoose.Schema({
local: {
username: {
type: String,
unique: true,
required: true
},
hashedPassword: {
type: String,
required: true
},
created: {
type: Date,
default: Date.now
}
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
twitter: {
id: String,
token: String,
displayName: String,
username: String
},
google: {
id: String,
token: String,
email: String,
name: String
}
});
但现在,我该如何验证用户?
passport.authenticate('bearer', { session: false }),
这是验证只有持票人令牌反对我的数据库,但我如何验证社交令牌?我错过了什么吗?
我正在使用Facebook登录为我自己的RESTful API my Notepads app here。我开始将应用程序作为一个将用作网页的应用程序,但仍然是通过API登录后的通信。
然后我决定创建一个使用API的mobile version of the same app。我决定这样做:移动应用程序通过Facebook登录并将Facebook用户ID和FB访问令牌发送到API,API调用Facebook的API来验证这些参数,并且如果成功注册新用户(或登录现有的)在我的应用程序的数据库中,为此用户创建一个自定义标记并将其返回给移动应用程序。从这里开始,移动应用程序发送这个自定义标记以通过API对应用程序进行身份验证
下面是一些代码:
API中的身份验证(使用fbgraph NPM模块):
var graph = require('fbgraph'),
Promise = require('bluebird')
...
Promise.promisify(graph.get);
...
var postAuthHandler = function (req, res) {
var fbUserId = req.body.fbId,
fbAccessToken = req.body.fbAccessToken,
accessToken = req.body.accessToken;
...
graph.setAppSecret(config.facebook.app.secret);
graph.setAccessToken(fbAccessToken);
var graphUser;
var p = graph.getAsync('me?fields=id,name,picture')
.then(function (fbGraphUser) {
//when the given fb id and token mismatch:
if (!fbGraphUser || fbGraphUser.id !== fbUserId) {
console.error("Invalid user from fbAccessToken!");
res.status(HttpStatus.FORBIDDEN).json({});
return p.cancel();
}
graphUser = fbGraphUser;
return User.fb(fbUserId);
})
.then(function (user) {
if (user) {
//user found by his FB access token
res.status(HttpStatus.OK).json({accessToken: user.accessToken});
//stop the promises chain here
return p.cancel();
}
...create the user, generate a custom token and return it as above...
用户模型:
var userSchema = new mongoose.Schema({
facebookId: { type: String, required: true, unique: true },
accessToken: { type: String, required: true, unique: true },
name: { type: String, required: true },
photo: { type: String, required: true },
categories: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Category' }],
notepads: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Notepad' }]
});
Facebook的AUTH在移动应用中:
auth: function(fbId, fbAccessToken) {
return $http({
url: apiBase + '/users/auth',
data: {
fbId: fbId,
fbAccessToken: fbAccessToken
},
method: 'POST',
cache: false
});
},
...
https://github.com/iliyan-trifonov/notepads-ionic/blob/master/www/js/services.js#L33。
移动应用发送所述令牌与所述请求:
notepads: {
list: function() {
return $http({
url: apiBase + '/notepads?insidecats=1' + '&token=' + User.get().accessToken/*gets the token from the local storage*/,
method: 'GET',
cache: false
});
},
这是一种离子/角/科尔多瓦应用程序。来自移动应用程序的Facebook登录启动安装在手机上的Facebook应用程序,或打开弹出窗口登录Facebook。然后回调将Facebook用户的ID和访问令牌返回给我的移动应用程序。
fbgraph npm模块:https://github.com/criso/fbgraph
只需格式化网址,它们就会处于活动状态。没有权限需要这个。 – 2015-06-08 23:38:14
谢谢@NickVolynkin!昨天我只能做出前两个活跃的网站,并且收到一个警报,说我至少需要10个代表。对于其余的。但是今天,我已经成功地将这些网址格式化了。 – 2015-06-09 11:30:32
护照的社交媒体策略取决于会话。没有一个,它们就不会运作。
我正在运行int相同的问题,我希望我的REST服务器是无状态的。
在我看来有2个选项。
- 加入会话您的休息服务器
- 添加一个新的auth服务器负责创建和发放令牌。
PS:您应该将其标记为passport,以便pass port devs可以看到它。
而不是aleksandrov教程(http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/)为什么不能使用passport-oauth? http://passportjs.org/guide/oauth/ – 2015-04-16 00:50:41
这是本教程所使用的模块。它是使用会话的人。令牌存储在会话中,以便在浏览器重定向时它可以关联返回的用户/令牌。由于这个原因,我的身份验证服务是有状态的,我的API是无状态的。 – 2015-04-16 14:00:58
Iv'e创建以下架构的:
var userSchema = mongoose.Schema({
local: {
username: String,
password: String
},
facebook: {
id: String,
token: String,
email: String,
name: String
},
google: {
id: String,
token: String,
email: String,
name: String
},
token: {
type: Schema.Types.ObjectId,
ref: 'Token',
default: null
}
});
var tokenSchema = mongoose.Schema({
value: String,
user: {
type: Schema.Types.ObjectId,
ref: 'User'
},
expireAt: {
type: Date,
expires: 60,
default: Date.now
}
});
当登录到我的web应用程序,我用一个PassportJS社交插件,如Facebook /谷歌。示例:
//auth.js(router)
router.get('/facebook', passport.authenticate('facebook', {scope: ['email']}));
router.get('/facebook/callback',
passport.authenticate('facebook', { successRedirect: '/profile',
failureRedirect: '/' }));
现在,当我想浏览我的Web应用程序时,我使用通过Facebook插件提供给我的会话身份验证。当用户想要请求API令牌时,他们需要登录,以便我可以将该令牌与用户关联。
因此,现在用户有一个与它们关联的令牌,它们可以用于我的API的令牌认证。
我的API路由不关心或看看会话,他们关心的只是令牌。通过创建一个快速路由器,并使用护照承载策略作为所有路由的中间件,向我的API发送信息。
//api.js (router)
//router middleware to use TOKEN authentication on every API request
router.use(passport.authenticate('bearer', { session: false }));
router.get('/testAPI', function(req, res){
res.json({ SecretData: 'abc123' });
});
所以,现在我只用令牌认证为我的API的(不永远看会话数据)和会话认证轻松浏览我的web应用程序。我使用会话浏览我的应用程序的一个示例如下所示:
//secure.js(router) - Access private but NON-API routes.
//router middleware, uses session authentication for every request
router.use(function(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.redirect('/auth');
});
//example router
router.get('/profile', function(req, res){
res.send("Private Profile data");
});
希望这会帮助你!
再次感谢!是的,我了解你的概念。然而,这并没有使后端纯粹的RESTful - 没有从说安卓设备的Facebook身份验证的入口点。应该有一个RESTful机制来做到这一点。在此之后,您的解决方案是完美的,因为持票人代币接管生成特定于应用程序的令牌。因此我在视频中留下了这个想法https://www.youtube.com/watch?v=VVFedQZgUgw – 2015-04-16 02:43:36
如果您使用持票人令牌,您只需将唯一标识符传递给API的用户。这很可能是以登录的形式在一个单独的电话中完成的。然后,每次调用API都需要验证令牌的令牌存在于数据库中,并更新其“生存时间”值。您不需要在架构中为您的每个登录需要单独的具有生存时间值(TTL)的令牌的架构
你能详细说明你最终如何解决这个问题吗?你还可以留下你的Twitter手柄进一步通信。谢谢:) – 2015-04-15 21:29:32
而不是aleksandrov教程,为什么不能使用passport-oauth? http://passportjs.org/guide/oauth/ – 2015-04-16 00:49:59
也为什么为你自己的服务器实现oAuth?为什么不使用护照本地,然后通过载体策略发布令牌? – 2015-04-16 12:16:31