Abréviation de JSON Web Token.
Veuillez vous référer au lien ci-dessous pour plus de détails. https://openid-foundation-japan.github.io/draft-ietf-oauth-json-web-token-11.ja.html
Il se compose de trois parties, un en-tête, une charge utile et une signature, chacun encodé en Base64.
entête
{
"typ":"JWT",
"alg":"HS256"
}
charge utile
{
"sub": "1234567890",
"iss": "John Doe",
"aud": "audience",
"exp": 1353604926
}
Signature
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
Les trois parties sont reliées par un. (Point).
Si vous souhaitez créer facilement un en-tête, une charge utile et une preuve, vous pouvez le faire avec le lien ci-dessous. https://jwt.io/#debugger
JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyIiwic3ViIjoidGVzdCIsImF1ZCI6ImF1ZGllbmNlIiwicGFyYW1zIjoie1wiZW1haWxcIjogXCJ0ZXN0QGdtYWlsLmNvbVwiLCBcInBhc3N3b3JkXCI6IFwicGFzc3dvcmRcIn0iLCJleHAiOiIxNTkzODM2ODA2In0.4fC4yLEmYTjiwaXk3R_AUUPEQSuI_ARmkoMqosWEJ-c
Un ensemble de revendications JWT est un objet JSON, dont chaque membre est une revendication envoyée en tant que JWT. Le nom de revendication dans l'ensemble de revendications JWT doit être unique. Cette fois, j'utiliserai les quatre affirmations suivantes.
Réclamation "iss" (émetteur): identifiant de l'émetteur JWT Réclamation "sub" (Subject): identifiant du sujet faisant l'objet de JWT "aud" (Audience) Revendication: liste des identifiants des entités censées utiliser JWT "exp" (Expiration Time): date d'expiration JWT
Il s'agit d'une mise en œuvre de la vérification de signature pour détecter la falsification des paramètres de demande. Essayons une implémentation qui ajoute un paramètre de requête à la charge utile et vérifie que le paramètre et le paramètre réellement reçus ont été falsifiés.
Ajout de paramètres à la charge utile
"params": "{\"email\":\"[email protected]\",\"password\":\"password\"}",
console
$ rails new jwt --api
gem 'jwt'
app/controllers/concerns/signature.rb
module Signature
extend ActiveSupport::Concern
def verify_signature
render status: 401, json: { message: 'Une falsification a été trouvée.'} if request.headers['jwt-signature'].blank?
request_params = JSON.parse(request.body.read)
@signature ||= JwtSignature.new(jwt: request.headers['jwt-signature'])
@signature.verify!(params: request_params)
rescue JwtSignature::InvalidSignature
render status: 401, json: { message: 'Une falsification a été trouvée.'}
end
end
app/models/jwt_signature.rb
class JwtSignature
class InvalidSignature < StandardError; end
ALGORITHM = 'HS256'
ISSUER = 'user'
AUDIENCE = 'audience'
SUB = "test"
TOKEN_TYPE = 'JWT'
# SECRET_KEY est important, définissez-le pour chaque environnement et gérez-le en toute sécurité ~
SECRET_KEY = '1gCi6S9oaleH22KWaXyXZAQccBx4lUQi'
def initialize(jwt:)
@jwt = jwt
end
def verify!(params:)
raise InvalidSignature unless valid_payload? && valid_params?(params: params) && valid_header?
end
private
def valid_payload?
return false unless jwt_payload['iss'] == ISSUER
return false unless jwt_payload['sub'] == SUB
return false unless jwt_payload['aud'] == AUDIENCE
true
end
def valid_header?
return false unless jwt_header['alg'] == ALGORITHM
return false unless jwt_header['typ'] == TOKEN_TYPE
true
end
def valid_params?(params:)
JSON.parse(jwt_payload['params']) == params
end
def jwt_header
@jwt_header ||= decoded_jwt.second
end
def jwt_payload
@jwt_payload ||= decoded_jwt.first
end
def decoded_jwt
@decoded_jwt ||= JWT.decode(@jwt, SECRET_KEY, true, algorithm: ALGORITHM)
rescue JWT::DecodeError
raise InvalidSignature
end
end
JWT.decode renvoie un tableau de hachage Obtenez la charge utile avec decoded_jwt.first et l'en-tête avec decoded_jwt.second
app / models / user.rb est généré
$ rails g model User name:string email:string token:string expired_at:datetime
$ rails db:migrate
routes.rb
Rails.application.routes.draw do
post 'tokens/create'
end
tokens_controller.rb
class TokensController < ActionController::API
include Signature
#Vérifier la vérification de la signature uniquement lors de la création
before_action :verify_signature, only: %i(create)
def create
#Cette fois, seul le processus de vérification de signature est mis en œuvre
user = User.find_by(email: params[:email], password: params[:password])
return render status: 400, json: { message: 'L'utilisateur n'existe pas.' } unless user
#Mettre à jour si le jeton n'existe pas
if user.token.blank?
user.token = SecureRandom.uuid
user.save
end
render status: 200, json: { name: user.name, email: user.email, token: user.token }
end
end
$rails c
irb(main):001:0> User.new(name: 'test', email: '[email protected]', password: 'password')
(0.5ms) SELECT sqlite_version(*)
=> #<User id: nil, name: "test", email: "[email protected]", password: [FILTERED], token: nil, expired_at: nil, created_at: nil, updated_at: nil>
irb(main):002:0> User.new(name: 'test', email: '[email protected]', password: 'password').save
(0.1ms) begin transaction
User Create (0.9ms) INSERT INTO "users" ("name", "email", "password", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["name", "test"], ["email", "[email protected]"], ["password", "password"], ["created_at", "2020-07-04 02:30:17.701626"], ["updated_at", "2020-07-04 02:30:17.701626"]]
(0.8ms) commit transaction
=> true
https://jwt.io/#debugger Générez des données JwtEncoded à partir du lien ci-dessus La partie Payload ajoute les revendications Jwt et les paramètres dont vous avez besoin Ajout d'e-mail et de mot de passe aux paramètres et comparaison de Json des paramètres d'API avec Json de Payload Remplacez la clé de sécurité de VERIFY SIGNATURE par votre propre sécurité (en utilisant SECRET_KEY du modèle JwtSignature) Réglez l'heure Unix sur exp si vous souhaitez définir l'heure de maturité
unixtime(5 minutes après l'heure actuelle)
irb(main):040:0> (Time.now + 300).to_i
=> 1593838401
Ajoutez "jwt-signature" à l'en-tête et ajoutez les données JwtEncoded
Données JwtEncoded
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJ1c2VyIiwic3ViIjoidGVzdCIsImF1ZCI6ImF1ZGllbmNlIiwicGFyYW1zIjoie1wiZW1haWxcIjogXCJ0ZXN0QGdtYWlsLmNvbVwiLCBcInBhc3N3b3JkXCI6IFwicGFzc3dvcmRcIn0iLCJleHAiOiIxNTkzODM4NDAxIn0.dSNqdhHBJKUJHnJa_2sS_3Qr4oNNdr5MKFx5ufwqLv4
Ajout d'un e-mail et d'un mot de passe à Body au format json
json
{ "email": "[email protected]", "password": "password"}
Après avoir vérifié la signature, j'ai pu obtenir le jeton en toute sécurité ~
Étant donné que 5 minutes ont été définies pour exp, la vérification de la signature a échoué après 5 minutes.
Recommended Posts