0% ont trouvé ce document utile (0 vote)
11 vues10 pages

Authentification API avec Devise et JWT

Ce tutoriel explique comment configurer une authentification avec JWT pour une API Rails en mode API à l'aide des gems Devise, Devise JWT et Rack CORS. Il décrit les étapes d'installation de ces gems, de configuration des modèles User et JwtDenylist, des controllers et des routes pour la gestion des sessions et des enregistrements.

Transféré par

lolo
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
11 vues10 pages

Authentification API avec Devise et JWT

Ce tutoriel explique comment configurer une authentification avec JWT pour une API Rails en mode API à l'aide des gems Devise, Devise JWT et Rack CORS. Il décrit les étapes d'installation de ces gems, de configuration des modèles User et JwtDenylist, des controllers et des routes pour la gestion des sessions et des enregistrements.

Transféré par

lolo
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Devise API Authentication | Ruby on Rails 7

Tutorial
[!

Vidéo de base :

Création de l’API 🛤
Création d’une app Rails en mode API (donc sans front)
rails new my_api --api

Rajout de 3 gems : devise, devise-jwt, et rack-cors


bundle add devise devise-jwt rack-cors

Devise sert au setup de tout le système d’authentification en tant que tel


Devise-jwt est une extension de Devise permettant d’utiliser les JWT token pour
l’authentification
Rack CORS permet de faire des requêtes cross-domains (en gros de pouvoir faire
des requêtes à l'API depuis un autre domaine)
Configuration de Rack CORS
C’est parti pour quelques modifications dans le fichier config/initializers/[Link]

Ces changements permettent d’autoriser n’importe quel site à faire des requêtes à l’API,
pour autoriser une seule origine➡️
origins "[url]"

# config/initializers/[Link]

# Be sure to restart your server when you modify this file.

# Avoid CORS issues when API is called from the frontend app.

# Handle Cross-Origin Resource Sharing (CORS) in order to accept cross-origin


AJAX requests.

# Read more: [Link]

[Link].insert_before 0, Rack::Cors do

allow do

origins '*'

resource '*',

headers: :any,

methods: %i[get post put patch delete options head],

expose: %w[Authorization Uid]

end

end

Installation de Devise et génération de la table User


rails g devise:install

rails g devise User

Devise JWT 💲
Génération de la Denylist
La DenyList est une méthode révocation de Token JWT, en gros à chaque fois qu'un
utilisateur se déconnecte ou que le token est expiré un nouveau token sera généré pour
cet utilisateur

rails g model jwt_denylist jti:string exp:datetime


Le jti est l’identifiant unique d’un token
Exp contient sa date d’expiration

⚠️Pour que tout fonctionne, vous devez renommer le fichier de migration


(de [timestamp]_create_jwt_denylists.rb à
[timestamp]_create_jwt_denylist.rb), la classe et la table au singulier (voir
en-dessous)

Fichier de migration :

# db/migrate/20220228223034_create_jwt_denylist.rb

class CreateJwtDenylist < ActiveRecord::Migration[7.0]

def change

create_table :jwt_denylist do |t|

[Link] :jti, null: false

[Link] :exp, null: false

[Link]

end

add_index :jwt_denylist, :jti

end

end

Petit changements au modèle User


:jwt_authenticatable permet de dire à Devise que User utilise jwt pour
l’authentification
:jwt_revocation_strategy permet de dire à User comment il doit révoquer les
tokens, et qu’il doit utiliser le modèle JwtDenylist pour ça

# app/models/[Link]

class User < ApplicationRecord

# Il faut ajouter les deux modules commençant par jwt

devise :database_authenticatable, :registerable,

:jwt_authenticatable,

jwt_revocation_strategy: JwtDenylist

end

Petits ajouts des familles au Model JwtDenylist


On indique aussi au modèle JwtDenylist qu’il doit utiliser la stratégie de révocation
denylist (oui oui)

# app/models/jwt_denylist.rb

class JwtDenylist < ApplicationRecord

include Devise::JWT::RevocationStrategies::Denylist

self.table_name = 'jwt_denylist'

end

rails db:migrate 🙂
Devise API JWT Controllers for Sessions and
Registrations 🧒
Créer le fichier members_controller.rb
La méthode show permettra de s’authentifier avec un token au lieu d’avec l’email et le
password

# app/controllers/members_controller.rb

class MembersController < ApplicationController

before_action :authenticate_user!

def show

user = get_user_from_token

render json: {

message: "If you see this, you're in!",

user: user

end

private

def get_user_from_token

jwt_payload = [Link]([Link]['Authorization'].split(' ')[1],

[Link][:jwt_secret_key]).first

user_id = jwt_payload['sub']

[Link](user_id.to_s)

end

end

Création des Users


Deux nouveaux controllers à créer, qui modifieront les controllers de registration et de
session de Devise

⚠️Il faut créer ces fichiers dans un dossier users dans app/controllers (voir
le commentaire en haut des snippets)

# app/controllers/users/registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController

respond_to :json

private

def respond_with(resource, _opts = {})

register_success && return if [Link]?

register_failed

end

def register_success

render json: {

message: 'Signed up sucessfully.',

user: current_user

}, status: :ok

end

def register_failed

render json: { message: 'Something went wrong.' }, status:


:unprocessable_entity

end

end

# app/controllers/users/sessions_controller.rb

class Users::SessionsController < Devise::SessionsController

respond_to :json

private

def respond_with(_resource, _opts = {})

render json: {

message: 'You are logged in.',

user: current_user

}, status: :ok

end

def respond_to_on_destroy

log_out_success && return if current_user

log_out_failure

end

def log_out_success

render json: { message: 'You are logged out.' }, status: :ok

end

def log_out_failure

render json: { message: 'Hmm nothing happened.' }, status: :unauthorized

end

end

Devise JWT Secret Key 🔑


Config du secret JWT utilisé pour décoder les tokens dans
config/initializers/[Link]

[Link] do |config|

# Plein de code

[Link] do |jwt|

[Link] =
[Link][:jwt_secret_key]

end

# Encore tout plein de code

end

1. Génération du secret

rake secret
Copie de la string générée
EDITOR=nano rails credentials:edit
Ajout en bas du fichier de :
devise:

jwt_secret_key: [clé copiée] // ⚠ Il faut mettre 2 espaces au début de


cette ligne

Routes 🛣
Go config/[Link]

# config/[Link]

[Link] do

devise_for :users,

controllers: {

sessions: 'users/sessions',

registrations: 'users/registrations'

get '/member-data', to: 'members#show'

# Define your application routes per the DSL in


[Link]

# Defines the root path route ("/")

# root "articles#index"

end

Configure Session Store in Rails 7


1. Config pour utiliser les cookies dans config/[Link]

# config/[Link]

module DeviseVue

class Application < Rails::Application

# Du code cool

# This also configures session_options for use below

config.session_store :cookie_store, key: '_interslice_session'

# Required for all session management (regardless of session_store)

[Link] ActionDispatch::Cookies

[Link] config.session_store, config.session_options

# Plein de code

end

end

Et voilà ! 🎉
Et les routes c’est quoi ?
Register
POST /users

Données attendues :

"user": {

"email": string,

"password": string

Pour la tester :

curl -XPOST -H "Content-Type: application/json" -d '{ "user": { "email":


"test@[Link]", "password": "12345678" } }' [Link]

Réponse :

=> {"message":"Signed up successfully.","user":{"id":


[id],"email":"test@[Link]","created_at":[timestamp],"updated_at":
[timestamp]}

Login
POST /users/sign_in

Données attendues

"user": {

"email": string,

"password": string

Pour la tester :

curl -XPOST -i -H "Content-Type: application/json" -d '{ "user": { "email":


"test@[Link]", "password": "12345678" } }'
[Link]

Réponse :

HTTP/1.1 200 OK

X-Frame-Options: SAMEORIGIN

X-XSS-Protection: 0

X-Content-Type-Options: nosniff

X-Download-Options: noopen

X-Permitted-Cross-Domain-Policies: none

Referrer-Policy: strict-origin-when-cross-origin

Content-Type: application/json; charset=utf-8

Vary: Accept, Origin

Authorization: Bearer
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIyMDQiLCJzY3AiOiJ1c2VyIiwiYXVkIjpudWxsLCJpYXQi
OjE2NDYyMTk4MTEsImV4cCI6MTY0NjIyMzQxMSwianRpIjoiZWMxNDk3NWItOTNkYS00YTE1LTg1Y
[Link]-Ahh4To9qdheeMewFHmbZtvWa_gSYx5mD38

Set-Cookie:
_interslice_session=vOm61TiX5r758FI7DXxo07gRo%2F1lB08%2BrjKnf5N2q5oIOA4P3CI94
3u%2FbLSS3lJCyu%2FrFmLF8%2FliLCxhQTZN4DqNGgGgjZh6koGGyCxdFwshloUmSByg0D8vRA21
kEQcCguvQ8BwJ1alzn6N9fAjXussdx63iL87TSUGhuWgSv3Ze4BkD1WsRG%2FFlH%2BJ%2Ba4mraP
kGZCiQmfBlRLDjZ7n4mmWaE1ASsAhXmhf%2BeC79ag%2BQgE3ZOHkTzRUmnQft4BGeVC51ITCfvW4
7Cbi8elBQsfs2IzROxe9qtDOklzDcA%3D%3D--U%2FLRbl1%2FWXHqxKhR--
lcsdl17IGM7jOT14NN8qZg%3D%3D; path=/; HttpOnly; SameSite=Lax

ETag: W/"3f408df0bede3cd5797e2190eefd79d9"

Cache-Control: max-age=0, private, must-revalidate

X-Request-Id: f1e51158-e4c6-42f2-bb94-535869cdccb5

X-Runtime: 0.256978

Server-Timing: start_processing.action_controller;dur=0.2275390625,
sql.active_record;dur=1.86376953125,
instantiation.active_record;dur=0.0888671875,
process_action.action_controller;dur=234.275390625

Transfer-Encoding: chunked

{"message":"You are logged in.","user":


{"id":204,"email":"test@[Link]","created_at":"2022-03-
01T19:50:54.482Z","updated_at":"2022-03-01T19:50:54.482Z"}}

Login with token


GET /member-data

Authentification nécessaire

Pour la tester :

curl -XGET -H [le token qui était dans Authorization dans la requête de
login] -H "Content-Type: application/json" [Link]

Réponse :

{"message":"If you see this, you're in!","user":


{"id":204,"email":"test@[Link]","created_at":"2022-03-
01T19:50:54.482Z","updated_at":"2022-03-01T19:50:54.482Z"}}

Logout
DELETE /users/sign_out

Authentification nécessaire

Pour la tester :

curl -XDELETE -H "Authorization: [le token qui était dans Authorization dans
la requête juste avant]" -H "Content-Type: application/json"
[Link]

Réponse :

{"message":"You are logged out."}

Vous aimerez peut-être aussi