10.2 protect pages.

 

again, we will start from TDD!!!

 

 

1. since both edit and update need the same authentication, we can put their test together:

  describe "authentication of edit/update pages" do
    before(:each) do
      @user = Factory(:user)
    end
    describe "for not signed-in users" do
      it "should redirect to sign in page" do
        get :edit, :id => @user
        response.should redirect_to signin_path
      end
      it "should deny access to update" do
        put :update, :id => @user, :user => {}
        response.should redirect_to signin_path
      end
    end
  end
 
2. we will add before_filter to user controller to make this test pass:
class UsersController < ApplicationController
  before_filter :authenticate, :only => [:edit, :update]
  .
  private

    def authenticate
      deny_access unless signed_in?
    end
end
 
we still need to define the deny_access method, since it is kind of authentication, I'll put it into session helper:

def deny_access
  redirect_to signin_path, :notice => "please sign in first."
end
 note, this line of code is equivalent with two
flash[:notice] = ""
redirect_to signin_path
 you can also use:
redirect_to signin_path, :alert => "fdsfdsfsdf"
 but you can't use :success or :error in this contruction.

3. except need of user to sign in, we still need to make sure current user can't edit other user info.

start from TDD again!!!
describe UsersController do
  render_views
  .
  .
  .
  describe "authentication of edit/update pages" do
    .
    .
    .
    describe "for signed-in users" do

      before(:each) do
        wrong_user = Factory(:user, :email => "user@example.net")
        test_sign_in(wrong_user)
      end

      it "should require matching users for 'edit'" do
        get :edit, :id => @user
        response.should redirect_to(root_path)
      end

      it "should require matching users for 'update'" do
        put :update, :id => @user, :user => {}
        response.should redirect_to(root_path)
      end
    end
  end
end
 
4. now to make the test pass, we need to add a new before filter to user controller.
class UsersController < ApplicationController
  before_filter :authenticate, :only => [:edit, :update]
  before_filter :correct_user, :only => [:edit, :update]
  .
  .
  .
  def edit
    @title = "Edit user"
  end
  .
  .
  .
  private

    def authenticate
      deny_access unless signed_in?
    end

    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_path) unless current_user?(@user)
    end
end
 
module SessionsHelper
  .
  .
  .
  def current_user?(user)
    user == current_user
  end

  def deny_access
    redirect_to signin_path, :notice => "Please sign in to access this page."
  end

  private
    .
    .
    .
end
 
now we have make our site very safe.

5. now we are doing some useful thing:

if a unsigned in user try to visit a protected page, he is redirected to the sign in page, then after he sign in, he is always redirected to the profile page, what we want is to redirect the user to the page he was trying to visit.

this is a very good work flow to be tested by the integration test!

so let's write a integration test for this flow first.
require 'spec_helper'

describe "FriendlyForwardings" do

  it "should forward to the requested page after signin" do
    user = Factory(:user)
    visit edit_user_path(user)
    # The test automatically follows the redirect to the signin page.
    fill_in :email,    :with => user.email
    fill_in :password, :with => user.password
    click_button
    # The test follows the redirect again, this time to users/edit.
    response.should render_template('users/edit')
  end
end
 
you may wondering, why I use 
should render_template()
instead of 
should redirect_to()

because, in integration test, it will follow the redirect, so response.should redirect_to will not work.

6. next, we will do the implementation to make the test pass.
how do we do this?
a. since http is stateless, we have to use session to store the requested url in last request, then get it from session in the new request.(the things in session will expire when browser close.)
b. we will use the request object to get the url.

module SessionsHelper
  .
  .
  .
  def deny_access
    store_location
    redirect_to signin_path, :notice => "Please sign in to access this page."
  end

  def redirect_back_or(default)
    redirect_to(session[:return_to] || default)
    clear_return_to
  end

  private
    .
    .
    .
    def store_location
      session[:return_to] = request.fullpath
    end

    def clear_return_to
      session[:return_to] = nil
    end
end
 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值