如何签署JWT?

How to sign JWT?

我正在尝试保护 Sinatra API。

我正在使用 ruby-jwt 创建 JWT,但我不知道用什么来签名。

我正在尝试使用用户的 BCrypt password_digest,但每次调用 password_digest 它都会发生变化,导致签名在我去验证时无效。

使用任何类型的应用程序密钥,而不是用户的 bcrypt 密码摘要。

例如,使用点环境 gem 和一个 .env 文件,其中包含一个条目,例如:

JWT_KEY=YOURSIGNINGKEYGOESHERE

我使用一个简单的随机十六进制字符串亲自生成了一个密钥:

SecureRandom.hex(64)

十六进制字符串仅包含 0-9 和 a-f,因此该字符串 URL 安全。

根据wikipedia,密码学中使用的密钥基本上就是一把开锁的钥匙。钥匙应该是一致的和可靠的,但不容易复制,就像你在家里使用的钥匙一样。

所述,密钥应该是随机生成的。但是,您仍然希望保留密钥以便在整个应用程序中使用。通过使用来自 bcrypt 的密码摘要,您实际上是在使用从基本密钥(密码)派生的散列密钥。因为散列是随机的,所以正如您所说,这不是一个可靠的密钥。

之前使用 SecureRandom.hex(64) 的回答是创建初始基础应用程序密钥的好方法。但是,在生产系统中,您应该将其作为配置变量并将其存储起来,以便在您的应用程序的多次运行中一致使用(例如,在服务器重新启动后,您不应该使所有用户的 JWT 失效)或在多个分布式服务器。 This article 给出了从 rails.

的环境变量中提取密钥的示例

对于 RS256 public 和私钥策略,您可以使用 Ruby OpenSSL 库:

正在生成密钥:

key = OpenSSL::PKey::RSA.new 2048

open 'private_key.pem', 'w' do |io| io.write key.to_pem end
open 'public_key.pem', 'w' do |io| io.write key.public_key.to_pem end

从 .pem 文件加载密钥以签署令牌:

priv_key = OpenSSL::PKey::RSA.new File.read 'private_key.pem'
token = JWT.encode payload, priv_key, 'RS256'

从 .pem 文件加载密钥以验证令牌(为此创建一个中间件):

      begin
        # env.fetch gets http header
        bearer = env.fetch('HTTP_AUTHORIZATION').slice(7..-1)
        pub_key = OpenSSL::PKey::RSA.new File.read 'public_key.pem'
        payload = JWT.decode bearer, pub_key, true, { algorithm: 'RS256'}
        
        # access your payload here
  
        @app.call env

      rescue JWT::ExpiredSignature
        [403, { 'Content-Type' => 'text/plain' }, ['The token has expired.']]
      rescue JWT::DecodeError
        [401, { 'Content-Type' => 'text/plain' }, ['A token must be passed.']]
      rescue JWT::InvalidIssuerError
        [403, { 'Content-Type' => 'text/plain' }, ['The token does not have a valid issuer.']]
      rescue JWT::InvalidIatError
        [403, { 'Content-Type' => 'text/plain' }, ['The token does not have a valid "issued at" time.']]
      end

要在 .env 中使用 RSA 密钥而不是加载文件,您需要使用 gem 'dotenv' 并使用换行符将密钥作为单行变量导入 '\n'.查看此 了解如何操作。示例:

PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nmineminemineminemine\nmineminemineminemine\nmineminemine...\n-----END PUBLIC KEY-----\n"

作为.env PUBLIC_KEY变量,加载key会变成这样:

key = OpenSSL::PKey::RSA.new ENV['PUBLIC_KEY']