使用节点 js、AngularJs 和 JWT 使用用户名和密码进行身份验证

Posted

技术标签:

【中文标题】使用节点 js、AngularJs 和 JWT 使用用户名和密码进行身份验证【英文标题】:Authentication with username & password with node js, AngularJs and JWT 【发布时间】:2015-04-28 06:15:59 【问题描述】:

我正在创建一个生产 angularJs 应用程序。

现在我创建了我的部分RESTFul API

这个API 会在登录时生成一个user 对象,但是我并不热衷于通过HTTP 标头发送未加密/未加密的password

让您了解我的API

登录时:

    var jwt = require('jwt-simple');

// Route: /login
module.exports = function (express, sequelize, router) 

    var DataTypes = require("sequelize");
    var crypto = require('crypto');

    var User = sequelize.define('user', 
            id: DataTypes.INTEGER,
            username: DataTypes.STRING,
            name: DataTypes.STRING,
            organization_id: DataTypes.INTEGER,
            type_id: DataTypes.INTEGER,
            division_id: DataTypes.INTEGER
        , 
            freezeTableName: true,
            instanceMethods: 
                retrieveByNamePassword: function (username, onSuccess, onError) 
                    User.find(where: username: username, raw: true)
                        .then(onSuccess).catch(onError);
                
            
        
    );

    router.route('/login')

        .post(function (req, res) 
            var user = User.build();

            var username = req.body.username || '';
            var password = req.body.password || '';

            if (username == '' || password == '') 
                res.status(401);
                res.json(
                    "status": 401,
                    "message": "Invalid credentials"
                );
                return;
            

            user.retrieveByNamePassword(username, function (users) 
                if (users) 
                    // If authentication is success, we will generate a token
                    // and dispatch it to the client
                    res.json(genToken(users));
                    return;
                 else 
                    // If authentication fails, we send a 401 back
                    res.status(401);
                    res.json(
                        "status": 401,
                        "message": "Invalid credentials"
                    );
                    return;
                
            , function (error) 
                res.status(401);
                res.json(
                    "status": 401,
                    "message": "Invalid credentials"
                );
                return;
            );
        );

    var genToken = function(user) 
        var expires = expiresIn(7); // 7 days
        var token = jwt.encode(
            exp: expires,
            user_id: user.id,
            organization_id: user.organization_id,
            type_id: user.type_id,
            division_id: user.division_id

        , require('./config/secret')());

        return 
            token: token,
            expires: expires,
            user: user
        ;
    ;

    var expiresIn = function(numDays) 
        var dateObj = new Date();
        return dateObj.setDate(dateObj.getDate() + numDays);
    ;

正如你现在所看到的(因为我还不确定如何处理它)我只是在寻找用户名,然后检查用户名是否存在。

我的问题很简单,你如何加密密码,然后在它到达 API 后对其进行验证?

【问题讨论】:

【参考方案1】:

JWT 可用于加密和非加密数据。但是,无论您是否对要传输的信息进行加密,都需要一个签名过程,让您在阅读之前验证您收到的信息没有被篡改。

对于通过域之间的 URL 传输登录状态的用例,我会说 在您的 JWT 中根本不包含密码将是最好的选择。

以如下流程为例:

    通过 HTTP 将您的登录详细信息发布到 domain1。

    对用户进行身份验证。如果成功,创建一个至少包含以下内容的 JWT:

    2.1。 exp:过期时间(比如说当前时间+最多10到15秒)

    2.2。 iat:令牌创建时间

    2.3。 电子邮件:用户的电子邮件地址

    2.4。 不要包含用户密码(或任何其他敏感数据)。

    使用 URL 中的 JWT 令牌将您的用户重定向到您的域 2

    您的其他服务器/域可以检查 JWT 签名、iat 和 exp 时间,以验证 JWT 未被篡改且有效。 如果都有效,请将您的用户登录到其他域。

这是有效的,因为只要 JWT 数据验证,第二个域实际上不需要知道您的用户密码,因为 domain1 服务器已经验证了登录并且只是告诉 domain2 接受它。只要您的 JWT 密钥完全保密,这应该是相当安全的。 如果可能的话,我还鼓励使用自动化方法定期随机更改两台服务器上的密钥。

注意:使用此方法,任何掌握 JWT 的人都可以查看其中包含的数据 - 所以不要在那里传输任何机密或敏感信息。

注意 2:无论您在 JWT 的到期字段中设置的任何时间段,此方法都容易受到重放攻击。如果第三方可以在该时间段内获得令牌,他们也可以使用令牌以该用户身份登录。出于这个原因,您必须将到期字段保持在尽可能低的位置以降低这种风险。

【讨论】:

所以我无法避免通过 HTTP 发布用户名和密码?如果我使用套接字连接然后将元素推送到套接字怎么办? @MarcRasmussen 我的回答主要是指使用 JWT 并且仅对数据进行签名以创建令牌。您可以选择在将要发送的数据编码到 JWT(使用公钥/私钥)之前对其进行加密,然后在稍后读取令牌时再次对其进行解密。此处提供有关此内容的完整信息:tools.ietf.org/html/draft-ietf-jose-json-web-encryption-40 并且您最有可能使用的任何 JWT 库都有一个简单的方法可以让您执行此操作。注意 - 我回答上述问题是因为完全不发送敏感数据总比加密要好。 @Joel:您知道在更改密码/注销时使 jwt 无效的最佳做法是什么 - ***.com/questions/28759590/…【参考方案2】:

这已经很晚了,但是你能不能在使用 crypt 的用户模型之后添加一个钩子? (像这样:https://www.youtube.com/watch?v=pquxHIBx8ks)

// User model...
,   
hooks: 
    beforeValidate: function() 

    ,
    afterValidate: function(User) 
        User.hashword = bcrypt.hashSync(User.hashword, 10);



    ,
    beforeCreate: function() 

    ,
    afterCreate: function() 

    

);

【讨论】:

以上是关于使用节点 js、AngularJs 和 JWT 使用用户名和密码进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

AngularJS 拦截器没有将 JWT Bearer 放入 node.js 应用程序的每个请求中

使用 JWT 管理多个设备节点 js 的用户会话

在 Rest API 中使用 Facebook 在 Express 和 NodeJS 中维护 JWT 的密钥和访问令牌

用户无法使用 JWT 和 Node API 登录 Angular js

使用 httponly cookie 将 JWT 从节点 REST API 发送到 Vue.js SPA

使用 Expressjs + JWT + Angularjs 的回调问题