14: AUTH: Autenticación y Autorización - LPC-Ltda/Ruby-on-Rails GitHub Wiki
Gracias a Dios [sic], sólo hay alrededor de mil millones de estos porque DHH no piensa aut / aut pertenece al núcleo -George Hotelling
Si usted está construyendo una aplicación web, frecuentemente usted necesitará alguna forma de seguridad de usuario. La seguridad de usuario puede ser rota en en dos categorías: autenticación, la cual verifica la identidad del usuario y autorización, la cual verifica lo que ellos pueden hacer.
En la versión 3.1 Rails introduce has_secure_password, lo que agrega métodos para setear y autenticar contra una password BCrypt. Aunque esta funcionalidad ahora existe en el framework, es sólo una pequeña parte de una solución de autenticación robusta. Aun nececitamos escribir nuestro propio código de autenticación o mirar fuera del núcleo de Rails por una solución adecuada.
En este capítulo, cubriremos la librería de autenticación Devise, escribiendo su propio código de autenticación con has_secure_password y la librería de autorización Pundit.
##14.1 Devise
Devise (https://github.com/plataformatec/devise) es un framework de autenticación basado en Rack altamente modular que se sienta en la cima de Warden. Tiene un conjunto robusto de características y refuerza el uso de los generadores de Rails, y usted sólo necesita usar lo adecuado para su aplicación.
###14.1.1 Poniendolo en marcha
Agregue la gema devise al Gemfile de su proyecto y corra bundle install. Luego usted puede generar la configuración de Devise al correr lo siguiente:
$ rails generate devise:install
Esto creará el inicializador para Devise y un YAML I18n en ingles para los mensajes de Devise. Devise también le alertará en este paso sobre algunos pasos obligatorios en la configuración de Rails si es que ya no los ha hecho. Esto incluye setear su host por defecto para Active Mailer, setar su ruta raíz y asegurarse de que los mensajes flash se rendereen en el layout por defecto de la aplicación.
###14.1.2 Módulos
Agregar funcionalidad de autenticación a sus modelos usando Devise se basa en el concepto de agregar diferentes módulos a su clase sólo en lo que necesita. Los módulos disponibles para su uso son los siguientes:
database-authenticatable Maneja la autenticación de un usuario así como la ancriptación de passwords.
confirmable Agrega la habilidad de requerir confirmación de emails para las cuentas de usuarios.
lockable Puede lockear una cuenta después de n intentos de login fallidos.
recoverable Provee la funcionalidad de reseteo de password.
registerable Altera el sign-up del usuario para ser manejado en un proceso de registro, junto con la administración de cuenta.
rememberable Provee la funcionalidad recuerdame.
timeoutable Permite que las sesiones expiren en un marco de tiempo configurable.
trackable Almacena recuentos de login, timestamps y direcciones IP.
validatable Agrega validaciones personalizabes para email y password.
omniauthable Agrega soporte Omniauth (https://github.com/intridea/omniauth).
Saber qué módulos desea incluis en su modelo es importante para setear sus modelos, migraciones y opciones de configuración más adelante.
###14.1.3 Modelos
Para setear la autenticación en un modelo, corra el generador Devise para el modelo y luego editelo. Para nuestro ejemplo, usaremos el siempre exitante modelo User.
rails generate devise User
Esto creará su modelo, una migración de base de datos, una ruta para su resplandecientemente nuevo modelo. Devise ha dado por defecto algunos módulos para usar, los que deberá alterar en su migración y modelo si desea usar modelos diferentes. En nuestro ejemplo, usamos solo un subconjunto de lo ofrecido.
Nuestra migración de base de datos resultante luce así:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0 # Only if lock strategy
# is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
Entonces modificamos el modelo User para reflejar los módulos que incluimos en nuestra migración.
class User < ActiveRecord::Base
# Include default devise modules. Others available are the following:
# :confirmable, :lockable, :timeoutable, y :omniauthable
devise :database_authenticable, :registerable, :recoverable,
:rememberable, :trackable, :validatable
end
Ahora estamos listos para el rake db:migrate y dejar que la magia pase.
###14.2.4 Controladores
Devise provee algunos métodos helper útiles que que pueden ser usados en sus controladores para autenticar su modelo o obtener el acceso para la persona actualmente sign-in. Por ejemplo, si usted desea restringir el acceso en un controlador, usted debe usar uno de los helpers como una before_action.
class MeatProcessorController < ApplicationController
before_action :authenticate_user!
end
Usted puede acceder también al usuario actual con sign-in vía el método helper current_user o a la sesión actual vía el método user_session. Use user_signed_in? si usted desea chequear si el usuario se ha loggeado dentro sin usar before_action.
Los métodos helper son generados dinámicamente, Así que en caso donde sus modelos autenticados son nombrados diferente, use el nombre del modelo en lugar del usuario en los ejemplos. Una instancia de esto puede ser con un modelo
Admin-sus helpers seríancurrent_admin, admin_sugned_in?, yadmin_session`.
###14.1.5 Vistas
Devise es construido como un motor Rails y viene con vistas para todos sus modulos incluidos. Todo lo que usted necesita es escribir algo de CSS y estará listo, y Devise provee un elegante script para copiar todas las vistas internas en su aplicación.
rails generate devise_views
Si usted está autenticando más de un modelo y no desea usar las mismas vistas para ambos, sólo setee la siguiente opción en su config/initializers/devise.rb:
config.scoped_views = true
ERb a Haml Las vistas extraidas desde el Devise Rails Engine son templates ERb. Si su preferencia es usar Haml para los templates, uno puede convertir los templates ERb vía la gema
html2haml. Después de que la gema está instalada, corra el siguiente comando desde la raíz de su proyecto Rails:
for file in app/views/devise/**/*.erb; do html2haml -e $file ${file%erb}haml && rm $file; done
###14.1.6 Configuración
Cuando usted recién setea Devise usando rails generate devise:install, un devise.rb es sacudido dentro de su directorio config/initializers. Este inicializador es donde toda la configuración de Devise es seteada, y esto esta ya empaquetado lleno de golosinas comentadas para todas las opciones de configuración con excelentes descripciones de cada opción.
Usar MongoDB como su base de datos principal? Bajo la sección configuración general en el inicializador, cambie el require de
active--recordamongoidpor pura genialidad
Devise viene con soporte de internacionalización en alto nivel y lo envían con la definición de mensajes en inglés ubicados en config/locales/devise.en.yml. (Usted verá que esto fue creado después de correr el generador install y el seteo) Este archivo puede ser usado como un tamplate para mensajes de devise en otro lenguaje al conservar la convención de nombres para cada archivo. Crea una traducció a español chileno en config/locales/devise.cl.yml, huevon.
###14.1.7 Parámetros fuertes
Con la adición de Parámetros Fuertes a Rails 4, Devise ha seguido el ejemplo y ha trasladado la preocupación de asignación masiva al controlador. En Devise la sanitación de parámetros de asignación masiva ocurre en las tres acciones siguientes:
sign_in Correspondiente a la acción del controlador Devise::SessionsController#new, sólo llaves de autenticación, como email, son permitidas.
sign_up Correspondiente a la acción del controlador Devise::RegistrationsController#create, permite llaves de autenticación password y password_confirmation.
account_update Correspondiente a la acción del controlador Devise::RegistrationsController#update paermite llaves de autenticación, password, password_confirmation y current_password.
Si usted requiere parámetros adicionales a los permitidos por Devise, la forma simple de hacerlo es a través del callback before_action en el ApplicationController.
class ApplicationController < ActionController::Base
before_action :devise_permitted_parameters, if: :devise_controller?
protected
def devise_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :phone_number
end
end
Adicionalmente, pasar pasando un bloque a devise_parameter_sanitizer, uno puede cambiar completamente los defaults de Devise.
class ApplicationController < ActionController::Base
before_action :devise_permitted_parameters, if: :devise_controller?
protected
def devise_permitted_parameters
for(:sign_in) {|user| user.permit(:email, :password, :remember_me, :username)}
end
end
Para más detalles sobre parámetros fuertes, ver Capítulo 15 "Seguridad".
###14.1.8 Extensiones
Hay muchas extensiones de terceros para Devise afuera que son cómodas si usted desea autenticar usando diferentes métodos.
cas_authenticatable Permite sing-on único usando CAS.
ldap_authenticatable Autentica usuarios usando LDAP.
rpx_connectable Agrega soporte para usar autenticación RPX.
Una lista completa de extensiones puede ser encontrada en https://github.com/plataformatec/devise/wiki/Extensions.
###14.1.9 Probando con Devise
Para habilitar los helpers de prueba de Devise en specs del controllador, cree el archivo de soporte spec devise.rb en la carpeta spec/support.
# spec/support/devise.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
Esto agregará los métodos sign_in y sign_out, que le permiten crear y destruir una sesión para un spec de controlador, respectivamente. Ambos métodos aceptan una instancia de un modelo Devise.
require 'spec_helper'
describe AuthenticatedController do
let(:user) { FactoryGirl.create(:user) }
before do
sign_in user
end
...
end
##14.2 has_secure_password