session [:user_id]在浏览器返回按钮上从nil更改为之前的值

时间:2015-10-07 18:18:47

标签: ruby-on-rails session

在我的rails应用中,当我退出时,在destroy方法中我设置了session[:user_id]=nil。但是,当我按下浏览器上的后退按钮时,session[:user_id]会恢复其先前的值,并自动显示登录页面。为什么会这样?在更改之前,如何使session[:user_id]=nil持久化?

session_controller.rb

class SessionsController < ApplicationController

  def index
  end

  def show
  end

  def new
  end

  def create
    @user = User.find_by_email(params[:email])
    if @user && @user.authenticate(params[:password])
      session[:user_id] = @user.id
      redirect_to user_posts_path
    else 
      render 'new'
    end
  end

  def destroy
   session[:user_id] = nil
  end

end

application.html.erb

<% if !(session[:user_id].nil?)%>
    Logged in as <%= current_user.email %>
    <%= link_to 'Log Out', session_path(current_user), :method => :delete %>
<% else %>
    <% if current_page?(new_user_path) %>
        <%= link_to "Log in", login_path %>
    <% elsif current_page?(login_path)  %>
        <%= link_to "sign up",new_user_path%>
    <% else %>
        <%= link_to "Log in", login_path %>
        <%= link_to "sign up",new_user_path%>
    <% end %>
<% end %>

<%= yield %>

rails s控制台中没有错误。

控制台上的最后一条消息。

Started DELETE "/sessions/2" for 127.0.0.1 at 2015-10-08 00:23:11 +0530
Processing by SessionsController#destroy as HTML
  Parameters: {"authenticity_token"=>"B0QLdVrsV9ZgwjS/Y8qVb3ID0q9gsC2peFQAZ/0J638kUTpXcAYcg1I+ulX1UaLujr4C7NPgIann74UETMOz6w==", "id"=>"2"}
  Rendered sessions/destroy.html.erb within layouts/application (0.1ms)
Completed 200 OK in 144ms (Views: 143.4ms | ActiveRecord: 0.0ms)

1 个答案:

答案 0 :(得分:3)

在您的退出操作中使用reset_session。这将发出新的会话标识符并声明旧的会话标识符无效并阻止其他基于会话固定的攻击。

http://guides.rubyonrails.org/security.html#session-fixation-countermeasures

这是如何正确设置SessionsController:

会话实际上并不像标准的crud资源,您可以从中获取全部CRUD谓词并从数据库中获取记录。

从用户的角度来看,只有三个动作:

new - displays the login form
create - verifies the credentials and signs the user in.
destroy - logs user out by resetting the session.

更改路线定义,将会话视为单一资源:

resource :sessions, only: [:new, :create, :destroy]

然后我们将创建一个帮手:

module SessionsHelper
  def current_user
    @user ||= User.find!(session[:user_id]) if session[:user_id]
  end

  def user_signed_in?
    !current_user.nil?
  end

  def can_sign_in?
    user_signed_in? || current_page?(new_user_path) || current_page?(new_session_path)
  end 
end

这样,用户在会话中的存储方式的实际实现只在应用程序的一个位置,而不是遍布控制器和视图。

让我们确保我们可以从控制器中调用它:

class ApplicationController < ActionController::Base
  include SessionsHelper
end

然后让补救控制器:

class SessionsController < ApplicationController

  # GET /session
  def new
  end

  # POST /session
  def create
    reset_session # prevents sessions fixation!
    @user = User.find_by(email: params[:email])
    if @user && @user.authenticate(params[:password])
      session[:user_id] = @user.id
      redirect_to user_posts_path 
    else 
      render 'new', flash: "Invalid username or password."
    end
  end

  # DELETE /session
  def destroy
   reset_session 
   if user_signed_in?
     flash[:notice] = 'You have been signed out successfully.'
   else 
     flash[:error] = 'You are not signed in!'
   end
   redirect_to root_path
  end
end

application.html.erb

<%= render partial: 'sessions/actions' %>
<%= yield %>

我们使用部分,因为应用程序布局趋向于变成怪物。 sessions/_actions.html.erb

<% if user_signed_in? %>
  Logged in as <%= current_user.email %>
  <%= link_to 'Log Out', session_path, method: :delete %>
<% else %>
  <%= link_to 'Log in', new_session_path if can_sign_in? %>
<% end %>
相关问题