[RUBY] Introduction de l'expert n ° 15 pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6

Création d'une API de babillard électronique avec certification et autorisation dans Rails 6 # 14 Affichage du temps d'exécution des semences

Différence entre authentification et autorisation

Tout d'abord, insérez l'expert. pundit est un joyau qui gère les autorisations.

Quelle est la différence entre l'authentification et l'autorisation?

[Certification], c'est comme montrer un permis de conduire. C'est un processus pour prouver qui vous êtes.

[Autorisation] est le type de voiture que vous pouvez conduire, ce qui est écrit sur la licence. En fonction de la licence, il existe différents types de licences, telles que les licences de taille moyenne et de grande taille, qui ne peuvent être utilisées qu'avec un cyclomoteur. En d'autres termes, même sur le système, vous savez qui vous êtes, mais vous devez gérer que ce processus n'est pas autorisé.

Et si vous ne pouvez pas simplement autoriser avec devise (devise_token_auth), vous le pouvez. Cependant, l'utilisation d'une gemme d'autorisation telle que pundit a de nombreux avantages, comme pouvoir la diviser en fichiers qui ne gèrent que le traitement des autorisations et le gèrent, et à mesure que l'application se développe, vous en ressentirez l'avantage.

Installer l'expert

Maintenant, mettons dans l'expert. C'est selon le document pundit, mais nous allons installer et initialiser comme suit.

Gemfile


+ gem “pundit”
$ bundle

app/controllers/v1/application_controller.rb


 class ApplicationController < ActionController::Base
+  include Pundit
…
 end
$ rails g pundit:install

Une fois installé, arrêtez une fois les rails et redémarrez.

Faire une politique de publication

Voir aussi: https://github.com/varvet/pundit#generator

$ rails g pundit:policy post

Une fois exécutés, un fichier de politique et un fichier de spécification seront créés.

Imaginez maintenant le comportement d'une application de tableau d'affichage typique.

Il y a trois fichiers principaux qui doivent être modifiés.

De plus, certains fichiers ne doivent être modifiés qu'une seule fois par défaut.

Comprenons le comportement de pundit lors de la modification de ces 4 fichiers.

app/controllers/v1/posts_controller.rb


     def index
       posts = Post.includes(:user).order(created_at: :desc).limit(20)
+      authorize posts
       render json: posts
     end
 
     def show
+      authorize @post
       render json: @post
     end
 
     def create
+      authorize Post
       post = current_v1_user.posts.new(post_params)
       if post.save
… 
     def update
+      authorize @post
       if @post.update(post_params)
… 
     def destroy
+      authorize @post
       @post.destroy
…

Ce qu'il faut noter ici, c'est où mettre «autoriser». Je vous l'expliquerai plus tard dans cet article.

Cette autorisation {model} appellera la méthode correspondante dans post_policy.rb. Je n'ai pas encore corrigé post_policy.rb, donc les index de la superclasse application_policy.rb? Et show? Sont appelés.

app/policy/application_policy.rb


  def index?
    false
  end

"Index?" Est-ce faux, n'est-ce pas? Si la valeur de retour de la méthode correspondant à {action}? Est vraie, elle est autorisée, et si elle est fausse, elle est refusée. Par conséquent, une erreur d'authentification se produira.

{"status":500,"error":"Internal Server Error","exception":"#\u003cNameError: undefined local variable or method `current_user' for #\u003cV1::PostsController:0x00000000036a49a8\u003e\nDid you mean?  current_v1_user

Cette erreur est tout à fait un auteur-compositeur. Il n'y a pas de variable ou de méthode appelée current_user Voilà l'erreur.

En fait, pundit, par défaut, appelle une méthode appelée current_user et la passe à @ user dans application_policy.rb et post_policy.rb. Cependant, dans cette application de test, l'espace de noms de la v1 est coupé, vous devez donc appeler current_v1_user au lieu de current_user.

Cela peut être résolu en remplaçant la méthode pundit_user dans application_controller.rb.

app/controllers/application_controller.rb


class ApplicationController < ActionController::API
…

+  def pundit_user
+    current_v1_user
+  end

Maintenant que «current_v1_user» est appelé dans pundit au lieu de «current_user», la précédente «variable ou méthode locale non définie» current_user »est résolue. Appuyez à nouveau sur Curl.

{"status":500,"error":"Internal Server Error","exception":"#\u003cPundit::NotAuthorizedError: not allowed to index? this Post::ActiveRecord_Relation

Il semble qu'une erreur 500 soit renvoyée lorsqu'elle n'est pas autorisée. Si vous n'avez pas la permission, une erreur 403 est appropriée, donc il semble bon de sauver Pundit :: NotAuthorizedError dans application_controller.rb.

app/controllers/application_controller.rb


 class ApplicationController < ActionController::API
   include DeviseTokenAuth::Concerns::SetUserByToken
+  rescue_from Pundit::NotAuthorizedError, with: :render_403
…

+  def render_403
+    render status: 403, json: { message: "You don't have permission." }
+  end
…

Essayons encore.

$ curl localhost:8080/v1/posts -i
HTTP/1.1 403 Forbidden
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
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
Cache-Control: no-cache
X-Request-Id: e19d413c-89c9-4701-94c5-ece2b12560a9
X-Runtime: 0.003657
Transfer-Encoding: chunked

{"message":"You don't have permission."}

Le code de réponse 403 et le message ont été renvoyés correctement. Si vous essayez de changer l'index def? Dans ʻapp / policy / application_policy.rb` de false à true, la liste des publications sera renvoyée normalement. Cependant, application_policy.rb est une superclasse, laissons donc tout faux ici en principe. Modifiez la sous-classe héritée post_policy.rb.

Modifier post_policy.rb

J'écrirai d'abord le code final.

app/policies/post_policy.rb


# frozen_string_literal: true

#
#post policy class
#
class PostPolicy < ApplicationPolicy
  def index?
    true
  end

  def show?
    true
  end

  def create?
    @user.present?
  end

  def update?
    @record.user == @user
  end

  def destroy?
    @record.user == @user
  end

  #
  # scope
  #
  class Scope < Scope
    def resolve
      scope.all
    end
  end
end

Cela devrait fonctionner comme prévu. De plus, j'écrirai le test à la fin cette fois car je donne la priorité à la compréhension du comportement de l'expert. Maintenant, rappelez la position où vous avez inséré «autoriser» dans le contrôleur.

app/controllers/v1/posts_controller.rb


     def index
       posts = Post.includes(:user).order(created_at: :desc).limit(20)
+      authorize posts
       render json: posts
     end
 
     def show
+      authorize @post
       render json: @post
     end
 
     def create
+      authorize Post
       post = current_v1_user.posts.new(post_params)
       if post.save
… 
     def update
+      authorize @post
       if @post.update(post_params)
… 
     def destroy
+      authorize @post
       @post.destroy
…

Notez qu'ils sont tous appelés ** avant que l'action ne doive être effectuée **.

Ce sera. Que faire si vous avez «autorisé» après l'enregistrement ou la mise à jour? Si vous n'avez pas l'autorisation, la réponse de 403 sera renvoyée, mais comme c'est une fois le processus de sauvegarde terminé, vous devriez avoir pu la réécrire sur la base de données. Cela n'a aucun sens de l'autorisation. Notez également que l'autorisation ne sera effectuée que si vous appelez «autoriser» en premier lieu.

En conclusion, vous devez être sûr d'appeler ʻauthorize` et de savoir où l'appeler.

Enfin, j'expliquerai le traitement de «create?» Et «update».

app/policies/post_policy.rb


  def create?
    @user.present?
  end

@ User contiendra current_v1_user, mais si vous n'êtes pas connecté, @ user contiendra nil. En d'autres termes, la méthode ci-dessus renvoie 200 pour vrai si connecté et 403 pour faux si non connecté.

app/controllers/v1/post_controller.rb


    def create
      authorize Post
      post = current_v1_user.posts.new(post_params)

Le côté contrôleur est également attentif. Notez que nous ne faisons pas ʻautoriser la publication sous post = current_v1_user.posts.new (post_params) . Parce que, comme mentionné ci-dessus, current_v1_user est nul, donc si vous essayez d'appeler ʻauthorize post sous post = current_v1_user.posts.new (post_params), la méthode posts n'existe pas et vous obtenez une erreur 500.

Comme ce n'est pas «post» mais «user» qui est nécessaire pour le jugement, «Post» est passé de manière appropriée en plus de cela pour exécuter authorize.

Deuxièmement, sur le comportement de la mise à jour et du destin.

app/policies/post_policy.rb


  def update?
    @record.user == @user
  end

Dans ce cas, puisque l'enregistrement à mettre à jour est passé en tant que «autoriser @ post» dans le contrôleur, l'enregistrement à mettre à jour / supprimer est passé à «@ enregistrement». Comparez l '«utilisateur» de cet enregistrement avec le «@ utilisateur» auquel le «current_v1_user» passe et déterminez s'ils correspondent. Alors, est-ce votre propre message? Vous jugez.

Dans le prochain article, j'expliquerai comment tester l'expert et comment découper le processus en méthodes.

A continué

Création d'une API de tableau d'affichage avec certification et autorisation dans les paramètres de stratégie Rails 6 # 16 [Vers la table de sérialisation]

Recommended Posts

Introduction de l'expert n ° 15 pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
Introduction de # 10 devise_token_auth pour créer une API de tableau d'affichage avec autorisation d'authentification dans Rails 6
Implémentation n ° 8 pour créer une API de tableau d'affichage avec autorisation de certification dans Rails 6
Créer une API de tableau d'affichage avec autorisation de certification dans Rails 6 # 13 Accorder l'en-tête d'authentification
Présentation du sérialiseur n ° 9 pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
Créez une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 6 show, créez une implémentation
Construire une API de tableau d'affichage avec certification et autorisation dans le contrôleur Rails 6 # 5, implémentation des routes
Présentation de # 2 git et rubocop pour créer une API de tableau d'affichage avec autorisation d'authentification dans Rails
Créez une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 17 Ajoutez des privilèges d'administrateur
Créer une API de tableau d'affichage avec autorisation de certification dans la mise à jour Rails 6 # 7, détruire l'implémentation
Construire une API de tableau d'affichage avec certification et autorisation dans Rails 6 # 14 Seed Affichage du temps d'exécution
Créez une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 1 Construction de l'environnement
Créer une API de tableau d'affichage avec autorisation dans Rails 6 # 12 Association d'utilisateur et de publication
Créer une API de tableau d'affichage avec autorisation de certification dans Rails 6 # 11 Test et validation du modèle utilisateur ajoutés
Construire une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 18 ・ Implémentation du contrôleur de l'utilisateur final
Créez une API de tableau d'affichage avec certification et autorisation avec Rails 6 # 3 RSpec, FactoryBot introduit et post-modèle
# 4 post-validation et mise en œuvre de test pour créer une API de tableau d'affichage avec certification et autorisation dans Rails 6
J'ai essayé de créer une fonction de groupe (babillard) avec Rails
Essayez de créer un babillard en Java
Comment créer une API avec GraphQL et Rails
[Comment insérer une vidéo dans un hameau avec Rails]
Comment configurer un proxy avec authentification dans Feign
Présentation de React to Rails avec react-rails
Comment renommer un modèle avec des contraintes de clé externes dans Rails
Étapes pour créer un environnement de développement Ruby on Rails avec Vagrant
Comment insérer une vidéo dans Rails
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 6.x)
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 5.x)
Comment créer un environnement Rails 6 avec Docker
Comment stocker simultanément des données dans un modèle associé à une forme imbriquée (Rails 6.0.0)
Convertir en balise dans la chaîne d'URL avec Rails
Créez un tableau d'affichage simple avec Java + MySQL
[Rails] rails nouveau pour créer une base de données avec PostgreSQL
Comment implémenter une fonctionnalité similaire dans Rails
Comment créer facilement un pull-down avec des rails
[Rails] Comment créer un environnement avec Docker
[Rails] [Docker] Le copier-coller est OK! Comment créer un environnement de développement Rails avec Docker
Commande Docker pour créer un projet Rails avec un seul coup dans l'environnement sans Ruby
J'ai créé une fonction pour enregistrer des images avec l'API dans Spring Framework. Partie 1 (édition API)
Comment gérer les erreurs dans Rails? Impossible de trouver un runtime JavaScript.
Lancer du SQL brut pour lire le réplica avec Rails
[Note] Créez un environnement Python3 avec Docker dans EC2
Comment écrire une recherche de comparaison de dates dans Rails
Je souhaite définir une fonction dans la console Rails
Comment interroger Array dans jsonb avec Rails + postgres
[Rails 6] Comment définir une image d'arrière-plan dans Rails [CSS]
Environnement Build Rails (API) x MySQL x Nuxt.js avec Docker
[Rails] Comment charger JavaScript dans une vue spécifique
Un nouvel employé a tenté de créer une fonction d'authentification / autorisation à partir de zéro avec Spring Security
J'ai créé une fonction pour enregistrer des images avec l'API dans Spring Framework. Partie 2 (édition client)
Présentation de Bootstrap à Rails 5
Présentation de Bootstrap aux rails !!