身份验证的逻辑封装在 thoughts_backend/token_validation.py 文件中。这包含标头的生成和验证。
以下函数生成 Bearer 令牌:
这会生成一个 JWT 有效负载。它包括要用作自定义值的 username,但它还添加了两个标准字段,一个 exp expiration date 和 iat 令牌的生成时间。
然后使用 RS256 算法使用私钥对令牌进行编码,并以正确的格式返回:Bearer
。
反向操作是从编码的标头中获取用户名。这里的代码更长,因为我们应该考虑到我们可能会收到 Authentication 标头的不同选项。该标头直接来自我们的公共 API,因此我们应该期望任何值和程序都为它做好防御准备。
令牌本身的解码很简单,因为 jwt.decode 操作将执行此操作:
但是在到达这一步之前,我们需要获取token并验证header在多种情况下是否有效,所以我们首先检查header是否为空,以及它是否具有正确的格式,提取token:
然后,我们解码令牌。如果无法使用公钥解码令牌,则会引发 DecodeError。令牌也可以过期:
然后,检查它是否具有预期的 exp 和 username 参数。如果缺少这些参数中的任何一个,则意味着令牌格式在解码后不正确。在不同版本中更改代码时可能会发生这种情况:
如果一切顺利,最后返回用户名。
每个可能的问题都以不同的严重性记录。大多数常见事件都使用信息级安全记录,因为它们并不严重。令牌解码后出现格式错误等情况可能表明我们的编码过程存在问题。
请注意,我们使用私钥/公钥架构而不是对称密钥架构来编码和解码令牌。这意味着解码和编码密钥是不同的。
从技术上讲,这是一个签名/验证,因为它用于生成签名,而不是编码/解码,但它是 JWT 中使用的命名约定。
在我们的微服务结构中,只有签名权限需要私钥。这增加了安全性,因为其他服务中的任何密钥泄漏都无法检索能够签署承载令牌的密钥。不过,我们需要生成正确的私钥和公钥。
要生成私钥/公钥,请运行以下命令:
然后,要提取公钥,请使用以下命令:
这将生成两个文件:key.pem 和 key.pub 带有一对私钥/公钥。以文本格式读取它们就足以将它们用作编码/解码 JWT 令牌的键:
请注意,对于测试,我们生成了一个作为字符串附加的示例密钥对。这些密钥是专门为此用途创建的,不会在其他任何地方使用。请不要在任何地方使用它们,因为它们在 GitHub 中公开可用。
请注意,您需要未加密的私钥,不受密码保护,因为 JWT 模块不允许您添加密码。
不要将生产密钥存储在不受保护的文件中。在
第三章,
使用 Docker 构建、运行和测试您的服务,我们将了解如何使用环境变量注入此密钥,并在
第 11 章,
处理系统中的更改、依赖项和机密,我们将了解如何在生产环境中正确处理机密。