我想限制用户只能查看和编辑来自公寓的数据。我已将他们的apartment_id保存在会话[:apartment_id]中。所以,我有CRUD,我想限制用户不能进行/ data / ID / edit只能更改ID然后编辑数据。有没有一种很好的方法可以做到这一点,比方说,通过一些范围,或者我必须在每个操作中验证控制器中的所有内容。 先感谢您。 Dorijan
编辑: 这个更详细: 假设在执行/数据时有一个用户列表,当你想要查看某个具有ID的用户的特定数据时,你会去/ data / ID example / data / 27。 在我的数据库中,对于模型数据,我得到了行apartment_id,它告诉用户属于哪个公寓。
现在,我想基于会话数据限制某些用户的视图。例如,当用户登录时,他得到了会话[:apartment_id]。
所以,我希望能够限制用户无法访问例如user_id = 34的/ data / 34,其中apartment_id与session [:apartment_id]不同。
另外,当用户访问/数据时只显示用户的明显。
我知道我可以在每个控制器中执行此操作,因为每种方法都可以检查这一点,但是我可以在模型中的某个位置执行此操作吗? 谢谢
答案 0 :(得分:2)
向您的Rails应用添加行级安全性 如果您正在使用数据库构建Web应用程序,则可能需要多个用户,这意味着要添加行级安全性和身份验证。
Rails帮助一个名为Devise的酷炫宝石。 Devise创建一个User表和视图,通过会话对Web应用程序进行身份验证,然后您可以为每个视图添加身份验证,以确保您有一个有效的会话来查看该视图。
这一切都很好,但是没有解决我的另一个问题,那就是用户限制数据库中的数据。所以我选择使用Devise User模型,特别是id字段,并由其他数据库表改变以包含id字段(我称之为user_id)。这一切都适用于您随后调整Rails应用程序的其余部分,如模型调用,以使用会话user_id作为每个SQL查询的一部分。让我来解释一下基本步骤,这些步骤有一些细节,但你需要即兴发挥你的情况。
我眼中的过程分为特定于Devise的步骤和行级安全步骤。
设计步骤
为您的Rails项目添加设计
add devise gem to gem file
gem ‘devise’
bundle install
rails generate devise:install
(安装到rails应用程序 - 在app目录根目录中)
rails g devise:views
(可选步骤:这会复制视图,因此我们可以自定义和设置样式)
rails generate devise User
(创建用户模型)
bundle exec rake db:migrate
(创建表 - 注意您需要yml中的权限才能更改数据库结构)
与设计相关的剩余步骤
向application.html.erb添加一个top div,检查用户是否已登录,并显示登录ID或新用户和登录链接
<div class=”top”>
<p class=”notice”><%= notice %></p>
<p class=”alert”><%= alert %></p>
<p>
<% if user_signed_in? %>
Logged in as <strong><%= current_user.email %></strong>.
<%= link_to ‘Edit profile’, edit_user_registration_path %> |
<%= link_to “Logout”, destroy_user_session_path, method: :delete %>
<% else %>
<%= link_to “Sign up”, new_user_registration_path %> |
<%= link_to “Login”, new_user_session_path %>
<% end %>
</div>
创建了一个“访客”控制器和视图,以显示未登录时 - 还更新routes.rb以使其成为根目录 - 即,当有人第一次访问您的网站时,您应该将它们带到访客控制器,而不是数据!你还没有会话。
更新了访客/根控制器,特别是,如果用户已登录,则转到登录控制器的索引操作
if user_signed_in?
redirect_to :controller=>’home’, :action=> ‘index’
end
在所有其他数据/登录控制器中,在操作之前将以下内容添加到控制器的顶部:这将确保没有人可以使用URL路径登陆页面而不进行身份验证。
before_filter :authenticate_user!
行级步骤
使用user_id列更改要使用行级安全性“RLS”的表。
mysql> ALTER TABLE mytable ADD COLUMN user_id VARCHAR(255) AFTER id;
使用users表中的有效user_id更新表(这假设您已经创建了一个具有注册表单的用户。或者只使用1,因为它出现Devise在1处开始第一个用户ID)
mysql> UPDATE mytable SET user_id = ( SELECT id FROM users WHERE email = ‘mememe@me.com’ );
处理将user_id添加到表插入
在数据/登录控制器CREATE操作中,更新参数对象中的user_id字段。
def create
params[:mytable][:user_id] = current_user.id
…
end
通过将user_id作为参数传递来处理选择/查询
在data / loggedin模型中,将user_id传递给新的查询范围,然后将该新范围与其他范围合并(确保将user_id传递到其他范围;还有其他方法可以执行此操作,但我喜欢范围) :
scope :my, -> (user_id) { where(“user_id = ?”, user_id) }
scope :mylovelyquery, -> (user_id) { my(user_id).where(:mylovelyselectioncriteria=>”A”).order(“mysortfield”) }
在数据/记录控制器中,更改索引操作以获取current_user.id并将其传递给您创建的ActiveRecord范围。这个步骤是乏味的,可以经常完成 - 寻找任何控制器索引或执行SELET的任何控制器操作 - 需要RLS!这也适用于Ajax调用。
def index
@user_id = current_user.id
@mytables = Mytable.my(@user_id).order(mylovelysortfield DESC”)
end
经验教训
在做任何检索数据库之前,可能最让我感到困惑的是忘记获取current_user.id。
答案 1 :(得分:1)
如果您的用户有很多公寓,那么通常您可以在控制器中执行此操作:
def edit
current_user.apartments.find(params[:id])
end
这只会找到属于当前用户的公寓。
更新
看起来你没有current_user对象......所以:
def edit
@apartment = Apartment.find(params[:id])
redirect_to root_path, error: "You do not have access for this apartment"
end
答案 2 :(得分:0)
您可以对要在控制器中限制的任何操作使用before_filter
。以下是关于这个主题的一些阅读:http://guides.rubyonrails.org/action_controller_overview.html#filters