over 3 years ago

系統:

Mac OS X Yosemite 10.10.1
Ruby 2.2.0
Rails 4.2.0

相關連結

sorcery ( https://github.com/NoamB/sorcery )

前言

近期想把以前的 PHP 網站用 Ruby on Rails 重寫,其需要有一個簡單的使用者認證登入的管理後台,但常使用的使用者認證 devise 功能過於完整,比較不符合我的簡單需求,於是就用 sorcery 來弄一個簡單的使用者登入介面。

設定步驟如下

1. Gemfile 設定

添加必要的 gem 套件至 Gemfile 檔中

# Use sorcery control User
gem 'sorcery'

之後,執行以下指令安裝以上的 gems

$ bundle install

2. sorcery 設定

安裝 sorcery

$ rails g sorcery:install

修改以下檔案內容

config/initializers/sorcery.rb
Rails.application.config.sorcery.configure do |config|
  ...
  config.user_config do |user|
    ...
    user.username_attribute_names = [:username]
    ...
  end
end

:email 改成 :username

db/migrate/xxxxxxxxxxxxxx_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :username,         :null => false
      t.string :crypted_password, :null => false
      t.string :salt,             :null => false

      t.timestamps
    end

    add_index :users, :username, unique: true
  end
end

安裝 User Table

$ rake db:migrate

PS. 如果出現錯誤訊息 ActiveRecord::NoDatabaseError,請先執行以下指令

$ rake db:create

3. 建立使用者的 CRUD

使用鷹架(scaffold)建立 User 的 CRUD

執行時,請略過已經建立的檔案 app/models/user.rb

$ rails g scaffold user username:string crypted_password:string salt:string --migration false
修改 UsersController
app/controllers/users_controller.rb
class UsersController < ApplicationController
  ...
  private
    ...
    def user_params
      params.require(:user).permit(:username, :password, :password_confirmation)
    end
end
修改 User Model
app/models/user.rb
class User < ActiveRecord::Base
  authenticates_with_sorcery!

  validates :password, length: { minimum: 4 }
  validates :password, confirmation: true
  validates :password_confirmation, presence: true

  validates :username, uniqueness: true
end
修改 User form
  # 移除以下 code
  <div class="field">
    <%= f.label :crypted_password %><br>
    <%= f.text_field :crypted_password %>
  </div>
  <div class="field">
    <%= f.label :salt %><br>
    <%= f.text_field :salt %>
  </div>
  # 在上面 code 的位子插入以下 code
  <div class="field">
     <%= f.label :password %><br />
     <%= f.password_field :password %>
  </div>
  <div class="field">
     <%= f.label :password_confirmation %><br />
     <%= f.password_field :password_confirmation %>
  </div>
新增 User

開啟伺服器並打開網頁 http://localhost:3000/users 新增任意使用者例如 demo/demo

4. User 的登入機制

建立登入機制的 controller
$ rails g controller UserSessions new create destroy
修改 controller 內容
app/controllers/user_sessions_controller.rb
class UserSessionsController < ApplicationController
  def new
    redirect_back_or_to(:users, notice: '已登入!') if logged_in?
    @user = User.new
  end

  def create
    if @user = login(params[:username], params[:password])
      redirect_back_or_to(:users, notice: '登入成功!')
    else
      flash.now[:alert] = '帳號或密碼錯誤!'
      render 'new'
    end
  end

  def destroy
    logout
    redirect_to login_path
  end
end
routes 設定

新增以下 routes

config/routes.rb
  ...
  get 'login' => 'user_sessions#new', as: :login
  post 'login' => 'user_sessions#create'
  delete 'logout' => 'user_sessions#destroy', as: :logout
  
  root 'users#index'
  ...
views 設定

刪除用不到的 views app/views/user_sessions/create.html.erbapp/views/user_sessions/destroy.html.erb
修改登入 view

app/views/user_sessions/new.html.erb
<h1>登入</h1>

<%= form_tag login_path do %>
  <div class="field">
    <%= label_tag :username %><br />
    <%= text_field_tag :username %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="actions">
    <%= submit_tag "登入" %>
  </div>
<% end %>

新增導航連結 (可以選擇在 layout 中)

app/views/layouts/application.html.erb
<body>
  <div id="nav">
    <% if current_user %>
      <%= link_to "編輯個人資料", edit_user_path(current_user.id) %>
      <%= link_to "登出", :logout, method: :delete %>
    <% else %>
      <%= link_to "註冊", new_user_path %> |
      <%= link_to "登入", :login %>
    <% end %>
  </div>
  <div>
    <p id="notice"><%= flash[:notice] %></p>
    <p id="alert"><%= flash[:alert] %></p>
  </div>
</body>

5. 設定需要認證的 controller action

可以使用以下 code 來驗證使用者是否登入,未登入則回登入頁面。

before_filter :require_login

以下是本篇文章設定的範例

# app/controllers/users_controller.rb
before_filter :require_login, only: [:show, :edit, :update, :destroy]
# app/controllers/user_sessions_controller.rb
before_filter :require_login, only: [:destroy]

6. 修改認證不成功時的導向

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  ...
  private
  def not_authenticated
    redirect_to login_path, alert: "請先登入"
  end
end

這時候回首頁點擊 修改使用者刪除使用者 都會轉向登入頁面。

← 使用 Better Errors 和 Rails Panel 讓除錯更輕鬆快速 使用 paperclip 實作任意格式檔案上傳 →
 
comments powered by Disqus