JSON Web Token(JWT):授权与认证

27

JWT术语一直困扰着我,有几个原因。JWT适用于授权还是只用于认证?

如果我说错了,请纠正我,但我一直将授权看作是允许某人访问资源的行为,然而JWT似乎没有任何实现可以真正允许用户访问特定资源。所有JWT实现都只是提供用户一个令牌。这个令牌随后在每次调用后端服务端点时传递,检查其有效性,如果有效则授予访问权限。因此,我们可以使用JWT对任何用户进行身份验证,但如何限制特定有效用户的访问权限呢?

我们如何使用JWT来限制具有特定角色的用户? JWT是否提供任何类型的授权详细信息,还是只提供身份验证?

感谢您事先帮助并耐心阅读我的疑问。


阅读以下内容:https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html - Ayush Gupta
4个回答

20

使用JWT进行授权可以通过令牌特定的声明实现。

Json Web Token中打包的许多其他用户信息一样,具体权限可以预先填充到令牌中,并稍后被授权服务截获。

通常,授权是基于权限的,其中权限用于限制对API端点的访问(也可以用于授予用户在前端应用程序上查看页面的访问权限)。

下面是一个带有权限元素的示例 JWT 令牌:

{
  "UserInfo": {
    "id": "#{USER_ID}",
    "roles": {
      "#{ROLE_NAME}": "#{ROLE_ID}"
    },
    "permissions": {
      "#{PERMISSION_NAME}": "#{PERMISSION_ID}",
    }
  },
  "exp": 1488888888
}

2
感谢您的回复。它对我很有帮助。 - Rohan Kadu

13

JWT有两个用途:

  1. 认证(如您所说)
  2. 信息交换。

第二部分非常有趣。 JWT包含:

  • 标题:包含算法和令牌类型
  • 载荷:关于实体(通常是用户)和其他元数据的语句。有三种类型的声明:注册,公共和私有声明。
  • 签名:用于验证JWT的发送方是其所说的人,并确保消息在传递过程中未更改。

有效载荷可以包含有关用户的信息,例如权限列表。 这样,您可以将其用于授权。

jwt.io的示例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

其中包含:

{
  "alg": "HS256",
  "typ": "JWT"
}
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

您可以看到负载包含身份和管理员权限信息。由于负载签名,您可以信任这些数据。


那么这个负载有任何标准吗?还是可以是任何自定义的JSON? - Rohan Kadu
2
你可以随意操作,但是https://www.iana.org/assignments/jwt/jwt.xhtml定义了标准公共声明,而https://tools.ietf.org/html/rfc7519则定义了注册声明。 - JEY
这些标头不能在中间进行修改,因为它们已经被编码和签名。我理解得对吗?因此,在标头中传输特定于角色的信息是安全的。对吗? - Rohan Kadu
是的,为了修改内容,您需要知道私钥或密钥(取决于所使用的算法)。 - JEY
这是不是意味着我需要为不同的角色或权限生成不同的Web令牌? - Olasunkanmi
什么意思。一个令牌可以具有多个角色或特权,但每个用户应该拥有自己的。 - JEY

2

用户首先登录。一旦用户通过登录过程,或者我们说一旦用户经过身份验证,您会签署一个JWT令牌并将其发送给用户。这是Node.js代码片段:

async postLogin(req, res, next) {
    // parse the req.body, get the email,password
    // check if the email exist, if exists check the passord
    // now you are sure credentials are true, create the jwt.
    const token = jwt.sign({ _id: this._id, email: this.email }, "this-is-secret", {
  expiresIn: "1h",
  res
    .status(200)
    .header("x-auth-token", token)
    .json({ token, userId: existingUser._id.toString() });
   });
  }

现在客户端将把它保存到localStorage中(为了简单起见,我使用localStorage)。在客户端,用户发送登录请求并获取我上面发送的内容。它将取出令牌并保存。由于它是异步请求,因此代码如下所示。以下是一个小的React代码示例:

  .then(resData => {
    localStorage.setItem('token', resData.token);
    localStorage.setItem('userId', resData.userId);

关于令牌,浏览器不会自动发送它,因此客户端必须手动将其附加到请求中。

fetch(url, {
      method: "post",
      headers: {
        Authorization: 'Bearer ' + localStorage.getItem('token')
      }
    })

当服务器收到请求时,您需要检查传入的令牌是否有效,如果是有效的令牌,则授权用户访问某些路由或服务。因此,用户将被授权。

认证是识别用户并验证他们所声称的身份的过程。最常见和明显的身份认证因素之一是密码。如果用户名与密码凭据匹配,则意味着身份是有效的,系统会授予用户访问权限,因此我们说用户已通过身份验证。


0
JWT适用于授权还是仅用于身份验证?
这个问题的答案在RFC7519标准的以下行中:
JSON Web Token(JWT)是一种紧凑的声明表示格式,旨在用于空间受限的环境,例如HTTP授权标头和URI查询参数。
JWT似乎没有任何实际允许用户访问给定资源的实现。
我会说你对此部分的理解需要稍微改进一下;-) 实际上,JWT有一个称为Claims的结构,在那里您可以找到与授权相关的主题。
你对JWT的理解还有一部分不正确。实际上,缺少一个叫做Token Issuer的组件。这个组件负责验证JWT令牌请求者的身份,并且只有在认证过程成功并且请求者被授权时才会发放JWT令牌。然后,发放的JWT令牌可以通过检查签名来进行验证,也就是说,通过像身份服务器这样的令牌发行者发放的令牌将包含消息的哈希码,这将允许令牌的使用者双重检查签名(哈希码),以确保在客户端和服务器之间的传输过程中未经授权的访问未修改令牌。然后,如果令牌是有效的,使用者在下一步可以提取令牌(JWT)声明以处理授权部分。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接