Rails アプリに行レベル セキュリティを追加
する データベースを使用して Web アプリケーションを構築している場合、複数のユーザーが必要になる場合があります。これは、行レベル セキュリティと認証を追加することを意味します。
Rails は、Devise と呼ばれるクールな gem を支援します。Devise は User テーブルとビューを作成して、セッションで Web アプリに認証します。次に、各ビューに認証を追加して、そのビューを表示するための有効なセッションがあることを確認します。
それはすべてうまくいきますが、データベース内のデータをユーザーごとに制限するという私の他の問題は解決しません。そこで、Devise User モデル、特に id フィールドを使用することにし、他のデータベース テーブルによって id フィールドを含めるように変更しました (これを user_id と呼びました)。これはすべて、各 SQL クエリの一部としてセッション user_id を使用するモデル呼び出しのように、Rails アプリの残りの部分を微調整すると機能します。基本的な手順を説明します。これには詳細が含まれていますが、場合によっては即興で行う必要があります。
私の目に見えるプロセスは、Devise 固有の手順と行レベルのセキュリティ手順に分かれています。
手順を工夫する
Rails プロジェクトに Devise を追加する
add devise gem to gem file
gem ‘devise’
bundle install
rails generate devise:install
(devise を rails app にインストールします - app ディレクトリのルートにあります)
rails g devise:views
(オプションの手順: これによりビューがコピーされるため、カスタマイズおよびスタイルを設定できます)
rails generate devise User
(ユーザーモデルを作成します)
bundle exec rake db:migrate
(テーブルを作成します - データベース構造を変更するには yml での権限が必要です)
残りのデバイス関連の手順
トップ div を application.html.erb に追加して、ユーザーがログインしているかどうかを確認し、ログイン 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
他のすべての data/loggedin コントローラーで、アクションの前にコントローラーの先頭に次を追加します。
before_filter :authenticate_user!
行レベルの手順
行レベル セキュリティ「RLS」が必要なテーブルを user_id 列で変更します。
mysql> ALTER TABLE mytable ADD COLUMN user_id VARCHAR(255) AFTER id;
users テーブルの有効な user_id でテーブルを更新します (これは、登録フォームで既にユーザーを作成していることを前提としています。または、Devise が最初のユーザー ID を 1 で開始しているように見えるため、単に 1 を使用します)
mysql> UPDATE mytable SET user_id = ( SELECT id FROM users WHERE email = ‘mememe@me.com’ );
テーブル挿入への user_id の追加を処理します
data/loggedin コントローラーの CREATE アクションで、パラメーター オブジェクトの user_id フィールドを更新します。
def create
params[:mytable][:user_id] = current_user.id
…
end
パラメータとして user_id を渡すことにより、選択/クエリを処理します
data/loggedin モデルでは、user_id を新しい my query スコープに渡し、その新しいスコープを他のスコープと結合します (必ず user_id を他のスコープに渡します。これを行う方法は他にもありますが、私はスコープが大好きです)。
scope :my, -> (user_id) { where(“user_id = ?”, user_id) }
scope :mylovelyquery, -> (user_id) { my(user_id).where(:mylovelyselectioncriteria=>”A”).order(“mysortfield”) }
data/logged コントローラーで、 index アクションを変更して current_user.id を取得し、それを作成した ActiveRecord スコープに渡します。この手順は面倒で、頻繁に実行できます。RLS が必要なコントローラー インデックスまたは SELET を実行しているコントローラー アクションを探します。これは Ajax 呼び出しにも当てはまります。
def index
@user_id = current_user.id
@mytables = Mytable.my(@user_id).order(mylovelysortfield DESC”)
end
学んだ教訓
おそらく、データベースを取得する前に current_user.id を取得するのを忘れていたことが、最も電話を切ったことの 1 つです。