wolfmasa's blog

フロンターレとプログラミング関係の話題を、気が向いたときにつぶやくブログです。

Rails 6にdeviseを入れてみる

認証機能の実装を行う。

使うのは、有名なdevise

github.com

Gemfileにdeviseを追記し、bundle install

特に過去のバージョンから変わったことはなく、すんなりとインストール完了。

んで、実際にdeviseの設定を行っていくが、これが少し手順が多いため、後で軌道修正する力量がない人は、しっかりと説明の手順通りに進めるの吉。

rails g devise:install

deviseのインストールを行うと、初期化やローカライズファイルと共に、手順の説明が表示される。

これを見逃さずに1つ1つ対応していく。

Running via Spring preloader in process 4957 create config/initializers/devise.rb

  create  config/locales/devise.en.yml

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb:

    config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

    In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to something in your config/routes.rb. For example:

    root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example:

    <%= notice %>

    <%= alert %>

  4. You can copy Devise views (for customization) to your app by running:

    rails g devise:views

ActionMailerの設定がどこまで有効かわからないけど、rootパスの設定をし、HTMLのヘッダに警告を表示するコンポーネントを配置したら、viewのcreateを行う。これでわかる通り、まずはviewを作り、そのあと実際に認証を管理するUserクラスを作っていく。

$ rails g devise User
Running via Spring preloader in process 5500
      invoke  active_record
      create    db/migrate/20190910094526_add_devise_to_users.rb
      insert    app/models/user.rb
       route  devise_for :users
$ vim db/migrate/20190910094526_add_devise_to_users.rb 
$ rails db:migrate

deviseからUserモデルを作るが、すでに自分はUserモデルを作成済みで、かつemailのカラムも作っていたので、このままではdeviseが作ったmigrateとバッティングしてエラーになってしまう。そのため、add_devise_to_users.rb の中身でemailを追加する行をコメントアウトして実行する。

あとは、認証をして実際に表示するページを

$ rails g controller Pages index show

で作成して、routeの設定をすると完了。

では、認証とは何か。

まず、表示するページ(GETに応答するHTMLのデータ)をブラウザに返す前に、「認証されていること」を条件にしておく。もし認証されていなければ、403などのエラーを返すことを意味する。

次に、「認証」とは一般的の「ユーザ名」と「パスワード」の対であろう。これをサーバに保持しておき、ユーザが入力した値と比較して一致すれば「認証されている」としても良いことになる。ただし、セキュリティの観点から「パスワード」をそのままサーバ上に保存しておくのは好ましくない。例えばDBをハッキングされ、盗まれた場合や、そもそもサーバの管理者が悪意のある誰かだった場合などに、ユーザに不利益となるからだ。(多くの場合ユーザはパスワードを使い回すのでよりリスクが高い)

なので、サーバ上ではパスワードは暗号化して保存する。ここでは、digestと呼ばれるハッシュ値にして保存しておくことで、ユーザが入力した文字列のハッシュ値と、サーバに保存されているハッシュ値との比較をすることで認証が可能となる。

最後に、ステートレスなHTTP通信でステートを管理するセッションを利用する。おそらく、最も簡単な方法としては、認証が成功した場合にセッション情報としてユーザIDをサーバからブラウザに返し、次回以降の接続にはセッション情報にユーザIDを含めてもらうことで、認証されているものとして扱うことができる。

セッションはサーバ上で作るデータなので有効期限が設定でき、有効期間内であれば再度認証をする必要がないが、もしかしたらユーザIDだけでは、ユーザIDを盗まれた場合になりすましなどのリスクもあるような気がする。これには例えばブラウザ側のIPアドレスをセットでセッション管理に紐づけることで、簡単ななりすましは防げるのかもしれない。

セキュリティ的な観点は詳しくないが、ともあれ、基本的な認証の仕組みはこのようなもので、deviseはこれを簡単に実装してくれるライブラリである。