首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >使用Passport和OAuth2 +社交网络的NodeJS REST身份验证

使用Passport和OAuth2 +社交网络的NodeJS REST身份验证
EN

Stack Overflow用户
提问于 2014-10-10 02:34:41
回答 3查看 10.8K关注 0票数 22

我正在使用NodeJS开发REST应用程序接口。对于身份验证,我决定使用Passport。我想要真正的RESTful应用编程接口。所以这意味着我必须使用令牌而不是会话。

我想让用户使用用户名和密码登录,或者使用Facebook、Google和Twitter等社交网络登录。

我使用oauth2orize模块制作了自己的OAuth2.0服务器,用于发布AccessRefresh tokens。因此,现在我可以注册新用户,然后向他们发出令牌。我遵循了以下教程:

http://aleksandrov.ws/2013/09/12/restful-api-with-nodejs-plus-mongodb/

验证路由的用户:

代码语言:javascript
复制
// 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 })
        }
    );

所有这些都运行得很好。不幸的是,我不知道如何实现社交身份验证。

我正在读这篇教程:

代码语言:javascript
复制
http://scotch.io/tutorials/javascript/easy-node-authentication-facebook 

但在本教程中,他们并不是在制作一个真正的RESTful应用程序接口。我已经根据本教程实现了用户模式,其中本地用户的令牌存储在单独的模型中。

代码语言:javascript
复制
// 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
    }
});

但是现在,我如何验证用户呢?

代码语言:javascript
复制
passport.authenticate('bearer', { session: false }),

这是仅针对我的数据库验证不记名令牌,但我如何验证社交令牌?我是不是遗漏了什么?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-09 06:49:27

我正在使用Facebook登录我自己的my Notepads app here的RESTful应用程序接口。我将应用程序作为网页启动,但登录后的通信仍将通过API进行。

然后,我决定创建一个将使用该mobile version of the same app的API。我决定这样做:移动应用程序通过Facebook登录,并将facebook用户id和FB访问令牌发送到API,API调用facebook的API来验证这些参数,如果成功,则在我的应用程序的DB中注册新用户(或登录现有用户),为该用户创建自定义令牌,并将其返回给移动应用程序。移动应用程序从此处发送此自定义令牌,以使用API对应用程序进行身份验证。

下面是一些代码:

API中的auth (使用fbgraph npm模块):

代码语言:javascript
复制
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...

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/6617a5cb418ba8acd6351ef9a9f69228f1047154/src/routes/users.js#L46

用户模型:

代码语言:javascript
复制
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' }]
});

https://github.com/iliyan-trifonov/notepads-nodejs-angularjs-mongodb-bootstrap/blob/master/src/models/user.js#L9

移动应用程序中的Facebook身份验证:

代码语言:javascript
复制
               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

移动应用程序将令牌与请求一起发送:

代码语言:javascript
复制
  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
                });
            },

这是一个Ionic/Angular/Cordova应用程序。从移动应用程序登录Facebook会启动安装在手机上的Facebook应用程序,或者打开一个弹出窗口登录Facebook。然后回调将Facebook用户的id和访问令牌返回给我的移动应用程序。

fbgraph npm模块:https://github.com/criso/fbgraph

票数 7
EN

Stack Overflow用户

发布于 2015-04-16 10:30:21

Iv'e创建了以下架构:

代码语言:javascript
复制
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 /google这样的社交插件。示例:

代码语言:javascript
复制
//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路由并不关心或查看会话,它们只关心令牌。Iv'e通过创建一个express路由器,并使用passport的承载策略作为所有通向我的API的路由的中间件来做到这一点。

代码语言:javascript
复制
//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使用令牌身份验证(从不查看会话数据),并使用会话身份验证轻松导航我的webapp。我使用会话来导航我的应用的示例如下所示:

代码语言:javascript
复制
//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");
    });

希望这能对你有所帮助!

票数 2
EN

Stack Overflow用户

发布于 2015-05-16 01:13:33

如果您使用的是持有者令牌,那么您所要做的就是将唯一标识符传递给API的用户。这很可能在一个单独的调用中完成,可能是以登录的形式。然后,每次对API的调用都需要该令牌,该令牌验证该令牌是否存在于数据库中,并将其Time更新为Live值。对于每个登录,您不需要在方案中使用单独的令牌,您需要具有生存时间值( Time To Live Value,TTL)的令牌的单独方案

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26285642

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档