JSON Web Tokens 遵循 RFC 7519 标准, 是一种身份认证( Authenticate ) 方式, 充当身份token的同时可以携带一些简单的信息.

简单的Ruby实现

require 'base64'
require 'openssl'
require 'json'

def base64url_encode(str)
  Base64.encode64(str).tr('+/', '-_').gsub(/[\n=]/, '')
end

def jwt_encode(header:, payload:, secret_key:)
  header_encoded = base64url_encode(JSON.generate(header))
  payload_encoded = base64url_encode(JSON.generate(payload))

  header_and_payload_encoded = "#{header_encoded}.#{payload_encoded}"
  algorithm = header.dig("alg")
  digest = OpenSSL::Digest.new(algorithm.sub('HS', 'sha'))
  hmac = OpenSSL::HMAC.digest(digest, secret_key, header_and_payload_encoded)

  "#{header_and_payload_encoded}.#{base64url_encode(hmac)}"
end

header = { "alg" => "HS256" }
payload = { "data" => "test" }
p jwt_encode(header: header, payload: payload, secret_key: 'XXxxx')
# eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.twOQcHUwfKdAltXCsYY-5xA5bVxUFlwxqjX28rUgN9k

JWT Gem

有现成的Gem处理以上流程:

require 'jwt'

payload = { data: 'test' }
secret_key = 'XXxxx'

token = JWT.encode payload, secret_key, 'HS256'
# "eyJhbGciOiJIUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.twOQcHUwfKdAltXCsYY-5xA5bVxUFlwxqjX28rUgN9k"

decoded_token = JWT.decode token, secret_key
# [{ "data" => "test" }, { "alg" => "HS256" }]

当然还可以使用非对称加密算法:

require 'jwt'
require 'openssl'

rsa_private = OpenSSL::PKey::RSA.generate 2048
rsa_public = rsa_private.public_key

token = JWT.encode payload, rsa_private, 'RS256'

# eyJhbGciOiJSUzI1NiJ9.eyJkYXRhIjoidGVzdCJ9.GplO4w1spRgvEJQ3-FOtZr-uC8L45Jt7SN0J4woBnEXG_OZBSNcZjAJWpjadVYEe2ev3oUBFDYM1N_-0BTVeFGGYvMewu8E6aMjSZvOpf1cZBew-Vt4poSq7goG2YRI_zNPt3af2lkPqXD796IKC5URrEvcgF5xFQ-6h07XRDpSRx1ECrNsUOt7UM3l1IB4doY11GzwQA5sHDTmUZ0-kBT76ZMf12Srg_N3hZwphxBtudYtN5VGZn420sVrQMdPE_7Ni3EiWT88j7WCr1xrF60l8sZT3yKCVleG7D2BEXacTntB7GktBv4Xo8OKnpwpqTpIlC05dMowMkz3rEAAYbQ
puts token

decoded_token = JWT.decode token, rsa_public, true, { algorithm: 'RS256' }

# Array
# [
#   {"data"=>"test"}, # payload
#   {"alg"=>"RS256"} # header
# ]
puts decoded_token

注意: 该 Gem JWT.encode 的时候要自己补全 { algorithm: 'RS256' } 的选项, 否则会报算法不匹配.

Reference

https://jwt.io/

https://github.com/jwt/ruby-jwt

http://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html