Ich bin ganz auf dünne Controller- und Fat-Modelle eingestellt, und ich denke, Auth sollte dieses Prinzip nicht brechen.
Ich programmiere jetzt seit einem Jahr mit Rails und komme aus der PHP-Community.Für mich ist es eine triviale Lösung, den aktuellen Benutzer als "anforderungslang global" festzulegen. Dies erfolgt standardmäßig in einigen Frameworks, zum Beispiel:
In Yii können Sie auf den aktuellen Benutzer zugreifen, indem Sie Yii :: $ app-> user-> identity aufrufen. Siehe http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html
In Lavavel können Sie dasselbe auch tun, indem Sie Auth :: user () aufrufen. Siehe http://laravel.com/docs/4.2/security
Warum, wenn ich nur den aktuellen Benutzer vom Controller übergeben kann?
Nehmen wir an, wir erstellen eine einfache Blog-Anwendung mit Unterstützung für mehrere Benutzer. Wir erstellen sowohl eine öffentliche Site (Anon-Benutzer können Blog-Beiträge lesen und kommentieren) als auch eine Admin-Site (Benutzer sind angemeldet und haben CRUD-Zugriff auf ihre Inhalte in der Datenbank.)
Hier sind "die Standard-ARs":
class Post < ActiveRecord::Base
has_many :comments
belongs_to :author, class_name: 'User', primary_key: author_id
end
class User < ActiveRecord::Base
has_many: :posts
end
class Comment < ActiveRecord::Base
belongs_to :post
end
Jetzt auf der öffentlichen Seite:
class PostsController < ActionController::Base
def index
@posts = Post.includes(:comments).latest(10)
end
end
Das war sauber und einfach. Auf der Admin-Site wird jedoch etwas mehr benötigt. Dies ist die Basisimplementierung für alle Admin-Controller:
class Admin::BaseController < ActionController::Base
before_action: :auth, :set_current_user
after_action: :unset_current_user
private
def auth
@user = login_or_redirect
end
def set_current_user
User.current = @user
end
def unset_current_user
User.current = nil
end
end
Daher wurde die Anmeldefunktion hinzugefügt und der aktuelle Benutzer wird in einem globalen Benutzer gespeichert. Das Benutzermodell sieht nun folgendermaßen aus:
class Admin::User < User
def self.current=(user)
Thread.current[:current_user] = user
end
def self.current
Thread.current[:current_user]
end
end
User.current ist jetzt threadsicher
Lassen Sie uns andere Modelle erweitern, um dies zu nutzen:
class Admin::Post < Post
before_save: :assign_author
def default_scope
where(author: User.current)
end
def assign_author
self.author = User.current
end
end
Das Post-Modell wurde erweitert, sodass das Gefühl besteht, dass derzeit nur die Beiträge des Benutzers angemeldet sind. Wie cool ist das!
Der Admin Post Controller könnte ungefähr so aussehen:
class Admin::PostsController < Admin::BaseController
def index
@posts = Post.all
end
def new
@post = Post.find_by_id(params[:id])
@post.attributes = params.require(:post).permit()
if @post.save
else
end
end
end
Für das Kommentarmodell könnte die Administratorversion folgendermaßen aussehen:
class Admin::Comment < Comment
validate: :check_posts_author
private
def check_posts_author
unless post.author == User.current
errors.add(:blog, 'Blog must be yours!')
end
end
end
IMHO: Dies ist eine leistungsstarke und sichere Methode, um sicherzustellen, dass Benutzer nur auf einmal auf ihre Daten zugreifen / diese ändern können. Überlegen Sie, wie viel Entwickler Testcode schreiben muss, wenn jede Abfrage mit "current_user.posts.whatever_method (...)" beginnen muss. Viel.
Korrigieren Sie mich, wenn ich falsch liege, aber ich denke:
Es geht um die Trennung von Bedenken. Selbst wenn klar ist, dass nur der Controller die Authentifizierungsprüfungen durchführen soll, sollte der aktuell angemeldete Benutzer keinesfalls in der Controller-Schicht bleiben.
Einziges, woran man sich erinnern sollte: NICHT überbeanspruchen! Denken Sie daran, dass es möglicherweise E-Mail-Mitarbeiter gibt, die User.current nicht verwenden, oder dass Sie über eine Konsole usw. auf die Anwendung zugreifen.