以下の続き。
sorceryでログイン機能のAPIを作成 - Rails技術ブログ
ユーザー新規登録機能のAPIを作成 - Rails技術ブログ
①ApiKeyモデルを作成。
$ rails g model ApiKey user:references access_token:string expires_at:datetime
class CreateApiKeys < ActiveRecord::Migration[6.0] def change create_table :api_keys do |t| t.references :user, null: false t.string :access_token, null: false t.datetime :expires_at t.timestamps t.index ["access_token"], unique: true end end end
$ rails db:migrate
②モデルを設定。
# app/models/api_key.rb class ApiKey < ApplicationRecord belongs_to :user validates :access_token, uniqueness: true scope :active, -> { where('expires_at >= ?', Time.current) } # 初期化時にaccess_tokenとexpires_atを設定 def initialize(attributes = {}) super self.access_token = SecureRandom.uuid self.expires_at = 1.week.after end end
# app/models/user.rb class User < ApplicationRecord . . . def activate_api_key! return api_keys.active.first if api_keys.active.exists? api_keys.create end end
③新規登録とログインの際にApiKeyを作成するようにコントローラーを設定。
※ユーザーが期限内のApiKeyを持っている場合はそれを使用。
# app/controllers/api/v1/base_controller.rb module V1 class BaseController < ApplicationController class BaseController < ApplicationController . . . protected def set_access_token!(user) api_key = user.activate_api_key! response.headers['AccessToken'] = api_key.access_token end . . .
# app/controllers/api/v1/authentications_controller.rb module Api module V1 class AuthenticationsController < BaseController def create @user = login(params[:email], params[:password]) raise ActiveRecord::RecordNotFound unless @user json_string = UserSerializer.new(@user).serialized_json set_access_token!(@user) render json: json_string end end end end
# app/controllers/api/v1/registrations_controller.rb module Api module V1 class RegistrationsController < BaseController def create @user = User.new(user_params) if @user.save json_string = UserSerializer.new(@user).serialized_json set_access_token!(@user) render json: json_string else render_400(nil, @user.errors.full_messages) end end private def user_params params.require(:user).permit(:name, :email, :password) end end end end
④記事一覧、記事詳細APIを取得する際にAPIトークンで認証する。
# app/controllers/api/v1/base_controller.rb module Api module V1 class BaseController < ApplicationController . . . # authenticate_or_request_with_http_tokenを使うために記載が必要。 include ActionController::HttpAuthentication::Token::ControllerMethods protected def authenticate # トークンが誤っていると(HTTP Token: Access denied.)を返す。 authenticate_or_request_with_http_token do |token, _options| @_current_user ||= ApiKey.active.find_by(access_token: token)&.user end end def current_user @_current_user end def set_access_token!(user) api_key = user.activate_api_key! response.headers['AccessToken'] = api_key.access_token end . . . end end end
# app/controllers/api/v1/articles_controller.rb module Api module V1 class ArticlesController < BaseController before_action :set_article, only: :show before_action :authenticate def index articles = Article.all json_string = ArticleSerializer.new(articles).serialized_json render json: json_string end def show options = { include: %i[user 'user.name' 'user.email'] } json_string = ArticleSerializer.new(@article, options).serialized_json render json: json_string end private def set_article @article = Article.find(params[:id]) end end end end
参考記事:
[Ruby on Rails]sorceryによる認証 – (5)APIでの認証 #3 モデル | Developers.IO
【Rails】RailsでAPIの簡単なトークン認証を実装する - Qiita