設計使用者驗證,製作 API 內的 current_user
這裡會先建立一個 Api access token 的 model,是比較基本的作法而已,實際的作法通常還會加上
- Log 記錄
- Expire 有效期限
這邊先不考慮上述的狀況,只把 api access token 當作能夠確認身份的令牌而已,所以要關聯 user 來做到透過 api endpoint 的請求能夠確認身份
建立 model rails g model api_access_token user_id:integer key:string
class ApiAccessToken < ApplicationRecord
belongs_to :user
before_create :generate_keys
private
def generate_keys
begin
self.key = SecureRandom.urlsafe_base64(30).tr('_-', 'xx')
end while ApiAccessToken.where(key: key).any?
end
end
確認 api access token 被建立後會建立一個隨機的密鑰,因為這樣的作法沒有避免碰撞,也就是生出一樣的 key ,所以額外做了一個簡單的判斷,建立直到沒有重複的 key 為止。
建立 auth 資料夾
mkdir app/api/api_v0/auth
實做 middleware 讓我們在中間層先處理用戶發進來的請求,去判斷是否要將用戶數據提前塞到 object 裡面。
touch app/api/api_v0/auth/middleware.rb
module ApiV0
module Auth
class Middleware < Grape::Middleware::Base
def before
if auth_provided?
@env["api_v0.token"] = Authenticator.new(request, params).authenticate!
@env["api_v0.user"] ||= @env["api_v0.token"].try(:user)
end
end
def request
@request ||= ::Grape::Request.new(env)
end
def params
@params ||= request.params
end
def auth_provided?
params[:access_key].present?
end
end
end
end
依照 middleware 規劃,實做 authenticator.rb
touch app/api/api_v0/auth/authenticator.rb
module ApiV0
module Auth
class Authenticator
def initialize(request, params)
@request = request
@params = params
end
def authenticate!
check_token!
token
end
def token
@token = ApiAccessToken.joins(:user).where(key: @params[:access_key]).first
end
def check_token!
return @params[:access_key] unless token
end
end
end
end
在 api/api_v0/base.rb
中加上
module ApiV0
class Base < Grape::API
#...
use ApiV0::Auth::Middleware
#...
end
end