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.
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.
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.
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 **.
render json
render json
@ post.destroy
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.
→ 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]