prémices d'une API avec authentification
This commit is contained in:
parent
4707a7da36
commit
41d1d6d8fe
30
app/controllers/api/v1/api_keys_controller.rb
Normal file
30
app/controllers/api/v1/api_keys_controller.rb
Normal file
|
@ -0,0 +1,30 @@
|
|||
class Api::V1::ApiKeysController < Api::V1::BaseController
|
||||
# include ApiKeyAuthenticable
|
||||
|
||||
# # Require API key authentication
|
||||
# prepend_before_action :authenticate_with_api_key!, only: %i[index destroy]
|
||||
|
||||
def index
|
||||
render json: current_bearer.api_keys
|
||||
end
|
||||
|
||||
def create
|
||||
authenticate_with_http_basic do |email, password|
|
||||
user = User.find_by email: email
|
||||
|
||||
if user&.authenticate(password)
|
||||
api_key = user.api_keys.create! token: SecureRandom.hex
|
||||
|
||||
render json: api_key, status: :created and return
|
||||
end
|
||||
end
|
||||
|
||||
render status: :unauthorized
|
||||
end
|
||||
|
||||
def destroy
|
||||
api_key = current_bearer.api_keys.find(params[:id])
|
||||
|
||||
api_key.destroy
|
||||
end
|
||||
end
|
25
app/controllers/api/v1/base_controller.rb
Normal file
25
app/controllers/api/v1/base_controller.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class Api::V1::BaseController < ApplicationController
|
||||
# before_action :authenticate
|
||||
|
||||
protect_from_forgery with: :null_session
|
||||
|
||||
def ping
|
||||
render json: { message: "pong" }, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authenticate
|
||||
authenticate_user_with_token || handle_bad_authentication
|
||||
end
|
||||
|
||||
def authenticate_user_with_token
|
||||
authenticate_with_http_token do |token, options|
|
||||
@user ||= User.find_by(private_api_key: token)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_bad_authentication
|
||||
render json: { message: "Bad credentials" }, status: :unauthorized
|
||||
end
|
||||
end
|
25
app/controllers/api/v1/checks_controller.rb
Normal file
25
app/controllers/api/v1/checks_controller.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class Api::V1::ChecksController < Api::V1::BaseController
|
||||
|
||||
# POST /checks or /checks.json
|
||||
def create
|
||||
@check = Check.new(check_params)
|
||||
|
||||
if @check.save
|
||||
render json: { message: "created" }, status: :created
|
||||
else
|
||||
render json: @check.errors, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# Use callbacks to share common setup or constraints between actions.
|
||||
def set_check
|
||||
@check = Check.find(params[:id])
|
||||
end
|
||||
|
||||
# Only allow a list of trusted parameters through.
|
||||
def check_params
|
||||
params.require(:check).permit(:name, :description, :hostname)
|
||||
end
|
||||
|
||||
end
|
31
app/controllers/concerns/api_key_authenticatable.rb
Normal file
31
app/controllers/concerns/api_key_authenticatable.rb
Normal file
|
@ -0,0 +1,31 @@
|
|||
module ApiKeyAuthenticatable
|
||||
include ActionController::HttpAuthentication::Basic::ControllerMethods
|
||||
include ActionController::HttpAuthentication::Token::ControllerMethods
|
||||
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
attr_reader :current_api_key
|
||||
attr_reader :current_bearer
|
||||
|
||||
# Use this to raise an error and automatically respond with a 401 HTTP status
|
||||
# code when API key authentication fails
|
||||
def authenticate_with_api_key!
|
||||
@current_bearer = authenticate_or_request_with_http_token &method(:authenticator)
|
||||
end
|
||||
|
||||
# Use this for optional API key authentication
|
||||
def authenticate_with_api_key
|
||||
@current_bearer = authenticate_with_http_token &method(:authenticator)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_writer :current_api_key
|
||||
attr_writer :current_bearer
|
||||
|
||||
def authenticator(token, options)
|
||||
@current_api_key = ApiKey.authenticate_by_token token
|
||||
|
||||
current_api_key&.bearer
|
||||
end
|
||||
end
|
|
@ -1,49 +1,49 @@
|
|||
module Authentication
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
|
||||
included do
|
||||
before_action :current_user
|
||||
helper_method :current_user
|
||||
helper_method :user_signed_in?
|
||||
end
|
||||
|
||||
|
||||
def authenticate_user!
|
||||
store_location
|
||||
redirect_to login_path, alert: "You need to login to access that page." unless user_signed_in?
|
||||
end
|
||||
|
||||
|
||||
def login(user)
|
||||
reset_session
|
||||
user.regenerate_session_token
|
||||
session[:current_user_session_token] = user.reload.session_token
|
||||
end
|
||||
|
||||
|
||||
def forget(user)
|
||||
cookies.delete :remember_token
|
||||
user.regenerate_remember_token
|
||||
end
|
||||
|
||||
|
||||
def logout
|
||||
user = current_user
|
||||
reset_session
|
||||
user.regenerate_session_token
|
||||
end
|
||||
|
||||
|
||||
def redirect_if_authenticated
|
||||
redirect_to root_path, alert: "You are already logged in." if user_signed_in?
|
||||
end
|
||||
|
||||
|
||||
def remember(user)
|
||||
user.regenerate_remember_token
|
||||
cookies.permanent.encrypted[:remember_token] = user.remember_token
|
||||
end
|
||||
|
||||
|
||||
def store_location
|
||||
session[:user_return_to] = request.original_url if request.get? && request.local?
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
|
||||
def current_user
|
||||
Current.user ||= if session[:current_user_session_token].present?
|
||||
User.find_by(session_token: session[:current_user_session_token])
|
||||
|
@ -51,9 +51,8 @@ module Authentication
|
|||
User.find_by(remember_token: cookies.permanent.encrypted[:remember_token])
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def user_signed_in?
|
||||
Current.user.present?
|
||||
end
|
||||
end
|
||||
|
15
app/models/api_key.rb
Normal file
15
app/models/api_key.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class ApiKey < ApplicationRecord
|
||||
encrypts :token, deterministic: true
|
||||
|
||||
belongs_to :bearer, polymorphic: true
|
||||
|
||||
def self.authenticate_by_token!(token)
|
||||
find_by! token: token
|
||||
end
|
||||
|
||||
def self.authenticate_by_token(token)
|
||||
authenticate_by_token! token
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
nil
|
||||
end
|
||||
end
|
|
@ -5,6 +5,8 @@ class User < ApplicationRecord
|
|||
|
||||
attr_accessor :current_password
|
||||
|
||||
has_many :api_keys, as: :bearer
|
||||
|
||||
has_secure_password
|
||||
has_secure_token :remember_token
|
||||
has_secure_token :session_token
|
||||
|
|
|
@ -1 +1 @@
|
|||
LAf4+kWkL2cPoqOeoqqfRaf2Y00zX7cZEAFlZGQkK//YR3Fm2SRb9IeTkKM7Hr57zT+DIXRP5RIA1+p7fa7Bazkg21JGnpMQDbCGTuztA139rUVMcCWoM0tq2S1JnFh3kplxkSC3QLTIEhBcBlbINwXwlKgYcLATE5fR7eFwY3TcSmNnEKuIOliBp1GAs+0ZLDFD1ZR+hGmiOKeIefMzZ8vmoyDGzeEHFKALapLU9fqr+xD/W2AvPd5w30ZUv3bz7yBx4y5NhR1qlvZdR+dFdQK426ObyWfptL4mkc7PJHs47D0S1TtDc8Q7TH4jrxJkfiKU+cWfXcJWDomZVnsfQPocJYg2XPMbstQHRWYOlnVPci5UsEXmzxosjD/I4p1Wb6gBXEa21pxu4abhQraIx3fmzokav8a+hrRC--3aQgyb/0RcdkvuWC--zE2XmPmYd5thg8yPD1YbJA==
|
||||
tX8j9/8froZx8hSUXJ1zaO6Fmn3jkubOCTvLpVsEGPvTf11VOtyL2LE7Hlgfsx9W0ZEVLlD5cIu09okLO6LpiHUOiTKRxzO/z32c+hT6eZyvCcWRJJewvitfsNxnSL/NN/TN2YgrQC7yEYqR5qQ2oyTFnpyN8VlmyGRJQhjJ5U8DZbPcyFmQ/wO6s05/jxRQU016+/dHG4Pa+7q//I6VHNe9TWsUNo6coVpjGtzyvPdeigfC3l9VoM88bdKuXx9wvQMu0usHhFDLkt5u18AW3A346+2xN+NJegVXH0Hr1NbhVPCNLkSYwy083ismXwisVj1bofENRzt0mf5Yjj8t2KsdtzQ+erXq9wb4scgx5U76hHC8qZXC36Z8S08k9Iq5Z7dECWzafXTiHjqkbjXifn/Zd0PcwGqj93NFOeIreP4SxWWYhic0lte2Ulx2vgLr6KV5U55syDQP5cSAqY8fA1OwcDseUN1O2JGLvLfI17+fjD/rbv5N1mzIV23l9NkyLsHySzyFW05wiPrqH4a2dM8uadhAsfr5g7PdbDfomF3JdVzP5ZNynUh4tzqdlXx6/dfZqcYs+7IWjNHRFrS9vd5D6mwI79QkxaGMVhXCY21IPADcTJI2avDqnJbxcb7cYmtj/zzZF2Qr4pHYHq8=--JXt6Z4gua+B0tGrh--iUcqTF0pAQA4ExORRzEx3w==
|
|
@ -1,5 +1,15 @@
|
|||
Rails.application.routes.draw do
|
||||
|
||||
namespace :api do
|
||||
namespace :v1 do
|
||||
defaults format: :json do
|
||||
get '/ping', to: 'base#ping'
|
||||
resources :api_keys, path: 'api-keys', only: %i[index create destroy]
|
||||
resources :checks, only: [:create]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||
root "static_pages#home"
|
||||
|
||||
|
|
15
db/migrate/20220124181635_create_api_keys.rb
Normal file
15
db/migrate/20220124181635_create_api_keys.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
class CreateApiKeys < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
create_table :api_keys do |t|
|
||||
t.string :token
|
||||
t.references :bearer, polymorphic: true, null: false
|
||||
end
|
||||
|
||||
add_index :api_keys, [:bearer_id, :bearer_type]
|
||||
add_index :api_keys, :token, unique: true
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :api_keys
|
||||
end
|
||||
end
|
11
db/schema.rb
generated
11
db/schema.rb
generated
|
@ -10,7 +10,16 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2022_01_23_074307) do
|
||||
ActiveRecord::Schema.define(version: 2022_01_24_181635) do
|
||||
|
||||
create_table "api_keys", force: :cascade do |t|
|
||||
t.string "token"
|
||||
t.string "bearer_type", null: false
|
||||
t.integer "bearer_id", null: false
|
||||
t.index ["bearer_id", "bearer_type"], name: "index_api_keys_on_bearer_id_and_bearer_type"
|
||||
t.index ["bearer_type", "bearer_id"], name: "index_api_keys_on_bearer"
|
||||
t.index ["token"], name: "index_api_keys_on_token", unique: true
|
||||
end
|
||||
|
||||
create_table "checks", force: :cascade do |t|
|
||||
t.string "name"
|
||||
|
|
Loading…
Reference in a new issue