Estoy todo por delgado controlador & modelos de grasa, y creo que auth no debe romper este principio.
He estado programando con Rails desde hace un año y vengo de la comunidad de PHP. Para mí, es una solución trivial configurar al usuario actual como "global de solicitud de larga duración". Esto se realiza de forma predeterminada en algunos marcos, por ejemplo:
En Yii, puede acceder al usuario actual llamando a Yii :: $ app-> user-> identity. Ver http://www.yiiframework.com/doc-2.0/guide-rest-authentication.html
En Lavavel, también puede hacer lo mismo al llamar a Auth :: user().Ver http://laravel.com/docs/4.2/security
¿Por qué si puedo pasar al usuario actual del controlador?
Supongamos que estamos creando una aplicación de blog simple con soporte multiusuario. Estamos creando tanto un sitio público (los usuarios pueden leer y comentar en las publicaciones de blog) como un sitio de administración (los usuarios están conectados y tienen acceso CRUD a su contenido en la base de datos).
Aquí están las "AR estándar":
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
Ahora, en el sitio público:
class PostsController < ActionController::Base
def index
# Nothing special here, show latest posts on index page.
@posts = Post.includes(:comments).latest(10)
end
end
Eso estaba limpio & sencilla. En el sitio de administración, sin embargo, se necesita algo más. Esta es la implementación básica para todos los controladores administrativos:
class Admin::BaseController < ActionController::Base
before_action: :auth, :set_current_user
after_action: :unset_current_user
private
def auth
# The actual auth is missing for brievery
@user = login_or_redirect
end
def set_current_user
# User.current needs to use Thread.current!
User.current = @user
end
def unset_current_user
# User.current needs to use Thread.current!
User.current = nil
end
end
Se agregó la funcionalidad de inicio de sesión y el usuario actual se guarda en un servidor global. Ahora modelo de usuario se ve así:
# Let's extend the common User model to include current user method.
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 ahora es seguro para subprocesos
Ampliemos otros modelos para tomar ventaja de esto:
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
modelo Post se amplió de manera que se siente como si solo hubiera entradas de usuarios actualmente conectadas. ¡Qué bueno es eso! Controlador de post
de administración podría ser algo como esto:
class Admin::PostsController < Admin::BaseController
def index
# Shows all posts (for the current user, of course!)
@posts = Post.all
end
def new
# Finds the post by id (if it belongs to the current user, of course!)
@post = Post.find_by_id(params[:id])
# Updates & saves the new post (for the current user, of course!)
@post.attributes = params.require(:post).permit()
if @post.save
# ...
else
# ...
end
end
end
Para el modelo de comentario, la versión de administración podría tener este aspecto:
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
mi humilde opinión: Esto es de gran alcance & manera segura de hacer Seguro que los usuarios pueden acceder/modificar solo sus datos, todo de una vez. Piense en cuánto necesita el desarrollador escribir el código de prueba si cada consulta necesita comenzar con "current_user.posts.whatever_method (...)"? Mucho.
corrígeme si me equivoco, pero creo que:
Se trata de la separación de las preocupaciones. Incluso cuando está claro que solo el controlador debe manejar las comprobaciones de autenticación, de ninguna manera el usuario actualmente conectado debe permanecer en la capa de controlador.
Lo único que debe recordar: ¡NO lo use en exceso! Recuerde que puede haber trabajadores de correo electrónico que no usen User.current o que tal vez accedan a la aplicación desde una consola, etc ...
Irónicamente, siete años después de que esto se le preguntó, "hacerlo mal" es 404ing. :) –
"Pensé que sería mejor dejar que los recursos respectivos (es decir, la instancia de un modelo) decidan si un determinado usuario puede leer o escribir en él". El modelo puede no ser el mejor lugar para esa lógica. Las gemas como Pundit y Authority establecen un patrón de tener una clase separada de "política" o "autorizador" designada para cada modelo (y los modelos pueden compartirlas, si lo desea). Estas clases proporcionan formas de trabajar fácilmente con el usuario actual. –