はじめに
knockというJWT認証のGemを使ってRails5.2のAPIモードで構築したWebAPIにユーザ認証を付けてみます。
準備
てことで、とりあえずknockをbundle installして、完了したらRailsにインストールします。
rails g knock:install
これでconfig/initializers/knock.rb
が生成されてるはず。
knockはAuth0っていうユーザ認証サービス?に対応しているらしいんですけど、
今回はUserモデルを用意して認証情報は自前で管理します。
下記コマンドでUserリソースで認証するためのコントローラを生成します。
$ rails g knock:token_controller user
app/controllers/user_token_controller.rb
っていうコントローラが生成されてると思います。
ついでにconfig/routes.rb
に生成したコントローラに対するルーティングも追加されます。
これで必要なファイルは揃ったので実装していきましょう。
実装
まずUserモデルのマイグレーションを作成。
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :email
t.string :password_digest
t.timestamps
end
add_index :users, :email, unique: true
end
end
サクッとマイグレーションしましょう。
$ rails db:migrate
次にUserモデルにhas_secure_password
メソッドを追加します。
class User < ApplicationRecord
has_secure_password
end
最後にapplication_controllerにknockの認証モジュールをインクルード。
class ApplicationController < ActionController::API
include Knock::Authenticable
end
動作確認
適当なユーザを作ってHTTPクライアントからconfig/routes.rb
に追加されたルートに、
POST /user_token
{"auth": {"email": "作成したユーザのメールアドレス", "password": "作成したユーザのパスワード"}}
を送信するとステータスコード201と共にJWTトークンが返ってくる。
はずなんだけど…
上手くいきませんでした、TypeErrorが返ってきます。
GitHubを調べてたら似たようなIssueを見つけました。
https://github.com/nsarno/knock/issues/205
どうやらRails.application.secrets.secret_key_base
はRails5.2以降はnilを返すようで、
config/initializers/knock.rb
のconfig.token_secret_signature_key
を変更する必要があるようです。
てことで下記のように変更しました。
## Signature key
## -------------
##
## Configure the key used to sign tokens.
##
## Default:
# config.token_secret_signature_key = -> { Rails.application.secrets.secret_key_base }
# 以下を追加
config.token_secret_signature_key = -> { Rails.application.credentials.read }
これでちゃんとJWTトークンが返ってくるようになりました。
あとは認証が必要なコントローラにbefore_action :autheticate_user
を追記すれば
認証されていないリクエストはステータスコード401が返ってくるようになります。