Авторизация в Ruby on Rails с помощью плагина restful-authentication

Сидя в Москве (как тут у вас многолюдно :) , нашел время на написание серии статей по Rails.
Сегодняшняя тема навеяна печальным сообщением. Итак моя задача: показать как можно легко сделать авторизацию в Ruby on Rails. Задача новичков прочитать и попробовать, задача не новичков прочитать и написать как сделать лучше и/или указать на ошибки.

Использованные инструменты:

  • Ruby 1.8.6
  • Mac OS X 10.5.6
  • Rails 2.2.2
  • Mongrel 1.1.5
  • MySQL 5.0.51b

Стандартные операции:

rails auth -d [любимая БД]
cd auth
rm public/index.html
[отредактировать config/database.yml]
rake db:create

Для авторизации в RoR существует куча плагинов. Я буду использовать restful-authentication.
Установка достаточно стандартна:

script/plugin install git://github.com/technoweenie/restful-authentication.git

Теперь нужно создать модель пользователя, в которой будет храниться логин пароль и другие пользователь-related данные. Так же понадобиться два контроллера. Один для регистрации, а другой для логина/логаута. Пусть модель пользователя будет user, а контроллер для логина логаута sessions, тогда выполнив такую команду:

script/generate authenticated user sessions

плагин все сделает за нас. У этого генератора есть несколько опций, например –include-activation, которая добавит активацию пользователя по e-mail. За более подробной информацией рекомендую обратиться к документации.
Генератор создаст два контроллера users и sessions, модель user, миграцию для модели user, записи в config/routes.rb и пару виюх которые скорей всего вы сразу же замените своими.
Роуты выглядят следующим образом:

Copy SourceCopy HTML
ActionController::Routing::Routes.draw do |map|
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.login '/login', :controller => 'sessions', :action => 'new'
map.register '/register', :controller => 'users', :action => 'create'
map.signup '/signup', :controller => 'users', :action => 'new'
map.resources :users
map.resource :session
end

Как видно все довольно хорошо вписывается в REST:

sessions/new [GET] форма логина
sessions [POST] авторизация
sessions [DELETE] logout
users/new [GET] форма регистрации
users [POST] регистрация

Я рекомендую с помощью опций роутов(введенных не так давно, не помню с какой версии) :o nly и :except, отредактировать запись map.resources :users (map.resources :users, :except => [:edit, :update, :destroy], for example). Например редактирование лучше перенести в отдельный роут: map.resource :profile, (редактирование в таком случае будет выглядить так: /profile/edit), так как скорей всего в вашем приложении одни пользователи других редактировать не должны.
Посмотрим на модель app/models/user.rb:

Copy SourceCopy HTML
require 'digest/sha1'

class User < ActiveRecord::Base
include Authentication
include Authentication::ByPassword
include Authentication::ByCookieToken

validates_presence_of :login
validates_length_of :login, :within => 3..40
validates_uniqueness_of :login
validates_format_of :login, :with => Authentication.login_regex, :message => Authentication.bad_login_message

validates_format_of :name, :with => Authentication.name_regex, :message => Authentication.bad_name_message, :allow_nil => true
validates_length_of :name, :maximum => 100

validates_presence_of :email
validates_length_of :email, :within => 6..100
validates_uniqueness_of :email
validates_format_of :email, :with => Authentication.email_regex, :message => Authentication.bad_email_message

attr_accessible :login, :email, :name, :password, :password_confirmation

def self.authenticate(login, password)
return nil if login.blank? || password.blank?
u = find_by_login(login.downcase) # need to get the salt
u && u.authenticated?(password) ? u : nil
end

def login=(value)
write_attribute :login, (value ? value.downcase : nil)
end

def email=(value)
write_attribute :email, (value ? value.downcase : nil)
end
end

В принципе ничего интересного разве что, мне не совсем нравится, что логином выступает не e-mail. Чтобы это поправить нужно сдеать следующее: удалить из миграции db/migrate/xxxx_users.rb запись t.column :login, :string, :limit => 40. Модель пользователя сделать такой:

Copy SourceCopy HTML
require 'digest/sha1'

class User < ActiveRecord::Base
include Authentication
include Authentication::ByPassword
include Authentication::ByCookieToken

validates_format_of :name, :with => Authentication.name_regex, :message => Authentication.bad_name_message, :allow_nil => true
validates_length_of :name, :maximum => 100

validates_presence_of :email
validates_length_of :email, :within => 6..100
validates_uniqueness_of :email
validates_format_of :email, :with => Authentication.email_regex, :message => Authentication.bad_email_message

attr_accessible :email, :name, :password, :password_confirmation

def self.authenticate(login, password)
return nil if login.blank? || password.blank?
u = find_by_email(login.downcase) # need to get the salt
u && u.authenticated?(password) ? u : nil
end

def email=(value)
write_attribute :email, (value ? value.downcase : nil)
end
end

Файл app/views/users/new.html.erb тоже придеться изменить:

<h1>Sign up as a new user</h1>
<% @user.password = @user.password_confirmation = nil %>

<%= error_messages_for :user %>
<% form_for :user, :url => users_path do |f| -%>

<p><%= label_tag ‘email’ %><br/>
<%= f.text_field :email %></p>

<p><%= label_tag ‘password’ %><br/>
<%= f.password_field :password %></p>

<p><%= label_tag ‘password_confirmation’, ‘Confirm Password’ %><br/>
<%= f.password_field :password_confirmation %></p>

<p><%= label_tag ‘name’ %><br/>
<%= f.text_field :name %></p>

<p><%= submit_tag ‘Sign up’ %></p>
<% end -%>

* This source code was highlighted with Source Code Highlighter.

Все готово! Осталось выполнить миграции и запустить проект.
Для полноты можно добавить рутовый роут. Генерация рутового контроллера:

script/generate controller home index

в config/routes.rb добавить:

map.root :controller => 'home'

Добавить лайтаут (app/views/layouts/application.html.erb):

<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<title>auth demo</title>
</head>
<body>
<%= render :partial => 'users/user_bar' %>
<%= yield %>
</body>
</html>

* This source code was highlighted with Source Code Highlighter.

Некоторые пояснения. В контроллере/виюхе «залогиненность» нужно проверять функцией logged_in? (true/false) доступ к пользователю который сейчай авторизован осуществляется через current_user. Готовый проект, в котором есть несколько исправлений не отраженных в статье.

Комментариев: 2 на “Авторизация в Ruby on Rails с помощью плагина restful-authentication”

  1. ruscustom:

    первый раз не увидел спама в комментариях :)

Добавить комментарий

Fill in your details below or click an icon to log in:

Логотип WordPress.com

You are commenting using your WordPress.com account. Log Out / Изменить )

Фотография Twitter

You are commenting using your Twitter account. Log Out / Изменить )

Фотография Facebook

You are commenting using your Facebook account. Log Out / Изменить )

Connecting to %s


Follow

Get every new post delivered to your Inbox.