代码之家  ›  专栏  ›  技术社区  ›  Tom Stock

将用户的权限存储在JWT声明中或在每次请求时在服务器上检查它是否更有效?

  •  4
  • Tom Stock  · 技术社区  · 7 年前

    JWT 这是一个很好的方法来确保发送给用户和返回的数据不会被篡改,但这会导致一些艰难的选择。目前,我正处于两难的选择中,要么将授权数据存储在JWT声明中,要么只接触数据库一次进行授权,要么只存储用户ID并检查每个请求的授权级别。

    使这成为一个如此艰难的选择的是,应用程序使用多个授权级别,这使得base64编码的url相当长和庞大(请参见下面可以预期存储为授权级别的内容)。

    另一方面,要获得授权,需要在数据库中进行两次查找。

    所以我的问题是:; 通过将权限发送到服务器,每个请求的额外开销是否值得避免在每次请求时查找权限的麻烦?

    作为补充说明;在权限更改的情况下,在数据库中查找方法的好处是不需要用户再次登录( see post ).

    "perms": {
        "roles": [
            {
                "name": "Admin",
                "id": 1,
                "assigned": true
            },
            {
                "name": "Webmaster",
                "id": 8,
                "assigned": true
            }
        ],
        "actions": [
            {
                "id": 1,
                "name": "cms-edit",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 9,
                "name": "admin-syslog",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 10,
                "name": "admin-debug",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 12,
                "name": "member-list-extended",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 2,
                "name": "cms-list",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 3,
                "name": "cms-add",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 5,
                "name": "member-list",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 7,
                "name": "member-view",
                "parameters": null,
                "parameterized": null
            },
            {
                "id": 8,
                "name": "member-edit",
                "parameters": null,
                "parameterized": null
            }
        ]
    
    2 回复  |  直到 7 年前
        1
  •  12
  •   Akar BUGinator86    7 年前

    你的第一个问题:

    通过将权限发送到服务器,每个请求的额外开销是否值得避免在每次请求时查找权限的麻烦?

    回答:

    让我们看看jwt.io提供的关于何时使用jwt s的描述:

    授权:这是使用JWT最常见的场景。一旦用户登录,随后的每个请求都将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录(Single Sign-On)是目前广泛使用JWT的一个特性,因为它的开销很小,并且可以方便地跨域使用。

    这意味着您需要在用户登录后在服务器端生成令牌。

    它包含:

    • 用户(作为id或名称)
    • 客户机的角色(用户、管理员、来宾,等等)

    一旦客户端向服务器请求或发送数据,服务器首先检查给定的令牌是否有效和已知,然后检查角色是否满足访问特定资源的条件。

    所有角色/访问数据都可以在系统启动时读取一次并保存在内存中。此外,当客户机登录时,只从数据库中读取一次客户机拥有的角色。这样,您就没有后续的数据库访问,因此,性能大大提高。

    另一方面,如果客户端请求数据或希望执行操作,则需要一个身份验证机制,该机制评估传递的令牌是否获得了执行此操作所需的角色。

    这样我们就解决了数据库的麻烦,并且消除了向客户端暴露太多信息的危险(即使客户端不能篡改数据,它也可以读取数据!)

    请注意: https://jwt.io/introduction

    请注意,使用签名的令牌,令牌中包含的所有信息都将公开给用户或其他方,即使他们无法更改它。这意味着您不应将机密信息放入令牌中。

    见A3(敏感数据曝光): https://www.owasp.org/index.php/Top_10-2017_Top_10

    最后:如果客户端空闲时间过长或有意注销,也要使令牌失效。

    后续问题:

    在权限更改的情况下,在数据库中查找方法的好处是不需要用户再次登录

    回答:

    根据服务器的基础结构,您可以在服务器端编写刷新机制(如果角色更新,服务器将生成新令牌并将其与生成的答案一起发送给客户端,从而使旧令牌失效,客户端仅使用最近的令牌并覆盖旧令牌),或者添加一些状态,如客户端会话:

    删除令牌上的角色/权限。最好为客户端生成会话,并在服务器端提供会话角色/权限。客户端获取它可以进行身份验证的会话令牌(通常是一个id)。一旦权限/角色更改,我们必须做两件事:

    1. 更新数据库
    2. 更新会话的角色/权限

    同样,每个后续请求都将在内存中执行角色/权限检查,并且不需要数据库通信,而客户端只有一个小的会话令牌(或JWT)。因此,角色/权限更改对客户端是透明的(不需要重新记录),并且我们消除了JWT刷新要求。

        2
  •  2
  •   Felix K.    6 年前

    取决于你如何解释效率。在谈到资源效率时,请记住JWT是根据每个请求发送的。因此,如果您有一个具有细粒度访问控制列表(acl)的大型应用程序,并且您总是在每个请求响应上来回ping这些列表,那么根据您发出的请求数,这肯定会花费您几千字节。