【问题标题】:Token based authorization in nodejs/ExpressJs and Angular(Single Page Application)nodejs/ExpressJs 和 Angular(单页应用程序)中基于令牌的授权
【发布时间】:2015-06-07 20:12:17
【问题描述】:

在我的应用程序中,在注册用户时,我在 MONGO DB 中使用这些字段保存用户名、密码和 jwt 生成的令牌。当用户尝试使用正确的凭据登录时,我将使用存储的令牌发送响应。然后在客户端(在我的控制器中)我使用本地存储来存储令牌,以便我可以为客户端发送的每个请求发送相同的令牌。但是我发现了有关此过程的一些问题:

  1. 我每次都为一个用户生成相同的令牌。因此,如果任何第三人能够获得令牌,那么他就可以访问受限页面。
  2. 我将生成的令牌存储在 MONGODB 中是否浪费了数据库中的空间
  3. 除用户外,任何人都可以访问存储在本地存储中的令牌。
  4. 对于我的单页应用程序中的每个请求,我再次查询 mongodb 以获取该用户的令牌并进行验证。在这里,我正在检查客户端和服务器端。

我正在使用 jwt 在我的应用程序中生成令牌、Node、Express、Mongoose

我是否遵循良好的程序。如果没有,您能否为我的方法或任何新方法提供解决方案。 我已经在许多网站上搜索了基于令牌的授权和基于会话的授权,但是对我没有任何帮助。 注意:我是 Nodejs、AngularjS 的初学者

【问题讨论】:

    标签: javascript angularjs node.js mongodb http-token-authentication


    【解决方案1】:

    您应该将令牌存储在高级键值缓存工具中,例如:Redis 这将显着提高性能。

    您将第一次从数据库中获取令牌,然后将其存储在 Redis 中。我曾经将令牌设置为键,将用户名设置为值。下一个请求,令牌将从缓存中给出。使用 Redis,您可以为令牌设置过期时间。

    【讨论】:

    • 在数据库中存储令牌是好事还是坏事??我可以在数据库中存储令牌的情况下做同样的事情吗?即当用户使用正确的凭据登录时,我将使用 JWT.Sign("with some secret key") 生成一个令牌并将其存储在某个位置以供服务器端访问(不知道我可以在哪里存储这个??你能请简要介绍一下)我将使用生成的令牌发送响应,以便在客户端(在我的控制器中)我可以将令牌存储在 $rootScope 中(如果没有错,存储在本地存储中不是一件好事)。对于每个请求,我会检查双方的令牌!我做得对吗!
    • 我可以通过 Redis 在页面空闲 15 秒时设置令牌的到期时间吗?这样当用户处于空闲状态 15 秒时我将在客户端和服务器端重置令牌再次显示登录页面。 @Maher Abuthraa
    • 这里是 restify+mongoose+redis 的工作版本:github.com/rgallagher27/… 了解如何在该项目中使用 Redis。您真正需要了解的是 oAuth2.0 是如何工作的。对我来说,如果过期是长期的,并且如果您不需要用户经常插入凭据,那么使用数据库是件好事......许多移动应用程序都使用这种方式。或者,在您的情况下,您只能将令牌保留在缓存中,因为空闲时间仅为 15 秒。使用 Redist,您可以轻松快速地做到这一点。
    【解决方案2】:

    当用户注册时,您需要像现在一样生成 JWT。没关系。但是,您不需要将其保存到数据库中。您没有问,但我认为密码不应以明文形式存储。您可以在将其保存到数据库之前使用 bcrypt 进行加密。

    当用户尝试使用正确的凭据登录时,我将使用存储的令牌发送响应

    是的,这是正确的做法。

    然后在客户端(在我的控制器中)我使用本地存储来存储令牌,以便我可以为客户端发送的每个请求发送相同的令牌。

    是的,在客户端,您可以将 JWT 保存到本地存储并在后续请求中将其发送到服务器。

    现在你的要点:

    1. 为了避免每次都使用相同的 JWT,您可以在有效负载中包含“exp”声明(我假设您正在使用类似 jwt-simple 的东西来生成 JWT)。比如:

      var payload = { sub: account.username, exp: moment().add(10, 'days').unix() }; var token = jwt.encode(payload, "secret");

    2. 您不需要将 JWT 存储在数据库中。在某些情况下,令牌颁发者(授权服务器)与资源服务器不同。资源服务器仅在请求中接收 JWT,但资源服务器无法访问授权服务器使用的数据库。旁注:如果您最终需要支持刷新令牌,即您交给客户端的 JWT 最终需要过期,那么您可以将刷新令牌存储在数据库中。刷新令牌与 JWT(访问令牌)不同。支持刷新令牌的复杂性将会增加。

    3. 本地存储不是您存储密码的地方,但它可用于存储 JWT。出于这个原因,JWT 必须并且应该在一定时间后过期。

    4. 不知道您所说的同时检查客户端和服务器端是什么意思。当客户端需要访问资源时(再次假设资源服务器可能与授权服务器不同),唯一传递资源服务器的是 JWT。任何人都可以解码 JWT。例如,尝试将您的 JWT 粘贴到此站点 http://jwt.io/。这就是 JWT 不应包含任何敏感数据的原因。但是,如果资源服务器知道授权服务器在对 JWT 进行编码时使用的秘密,则资源服务器可以验证签名。回到第三个项目符号,这就是为什么可以将 JWT 存储在客户端的本地存储中的原因。

    更新我正在更新此内容以回答您在评论框中的一些问题。

    用户点击“登录”按钮会触发 Angular 控制器向服务器发送请求,类似于:

    $http.post(url, {
        username: $scope.username,
        password: $scope.password
    }).success(function(res) { ... })
    

    服务器收到 POST 请求,检查用户名/密码,然后生成 JWT,并发送回浏览器。请注意,它不必将 JWT 保存到数据库中。代码类似于

    var payload = {
        sub: account.username,
        exp: moment().add(10, 'days').unix()
    };
    var token = jwt.encode(payload, "secret");
    res.status(200).json({      
      token: token
    });
    

    回到客户端,在上面的 success() 回调中,现在可以将 JWT 保存到本地存储中:

    .success(function(res) { $window.localStorage.setItem('accessJWT', res.token) })
    

    用户现在已通过身份验证。现在,当用户想要访问受保护的资源时,用户不必提供用户名/密码。通过可以从本地存储中检索到的 JWT,客户端现在可以使用承载方案将 JWT 放入请求的 Authorization 标头中,并将请求发送到服务器。在代码中,它会:

    headers.Authorization = 'Bearer ' + token;
    

    服务器收到请求。同样,接收此请求的服务器不必与生成上述 JWT 的服务器相同。两台服务器可以位于 2 个不同的大陆。即使您保存了上面的 JWT,这对无法访问存储 JWT 的数据库的服务器也没有任何好处。但是这个服务器可以从请求的头部中取出不记名令牌,验证令牌并继续正常的任务。

    希望这会有所帮助。

    【讨论】:

    • 如果不将令牌存储在数据库中,我如何在每次用户登录时在服务器端操作我的令牌。我想我可以将令牌存储在 $rootscope 中,而不是本地存储?如果我不是错误的!或者我应该去参加会议吗?还有我怎样才能为特定用户每次生成不同的令牌??
    • 不,对于旨在在移动设备中工作的 JWT,会话从来都不是必需的。正如我所说,要获得不同的令牌,请添加基于时间的过期声明。每次生成token的时间都会不一样,所以claim不一样,所以payload不一样,所以token也不一样。同样,您不需要存储令牌。当用户登录时,您检查有效的凭据。如果有效,则发出令牌。当用户想要访问某个资源时,请求头中会传入一个token,然后资源服务器可以验证这个token。
    • 一切都很好,但是我如何才能在服务器端(在 server.js 中)为每个请求获取生成的令牌,因为我没有在我的 mongodb 中存储使用 jwt 生成的令牌?跨度>
    【解决方案3】:

    您不想将 JWT 存储在 mongoose 中,因为它会在登录时出现在标头中。您首先生成一个令牌,然后使用 crypto 之类的模块对其进行哈希处理。

    有不同的方法可以做到这一点,它们都使用处理令牌的Passport。这是一个示例项目Satellizer

    我建议您生成angular-fullstack 项目。然后通过 server/auth 文件夹和 client/account 文件夹。您将了解如何在基于 MEAN 的应用中安全地处理身份验证。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-02-26
      • 2020-08-29
      • 2014-11-08
      • 1970-01-01
      • 2019-01-10
      • 2018-05-31
      • 2015-07-15
      • 2016-05-21
      相关资源
      最近更新 更多