在我的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)
答案 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 %>