From 75e105edfb9e6c6c76b40a4346d0438debdf5537 Mon Sep 17 00:00:00 2001 From: Abhishek Sarkar Date: Sun, 8 Sep 2024 23:17:33 +0530 Subject: [PATCH] Added web basic auth and updated README.md --- README.md | 41 ++++++++++++++++++++++++++++++----------- lib/apicraft/web/app.rb | 25 ++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index e0cc42c..5eac697 100644 --- a/README.md +++ b/README.md @@ -62,23 +62,13 @@ Add the APICraft Middleware into your Rails application, via the `config/applica # config/application.rb module App class Application < Rails::Application - # Rest of the configuration + # Rest of the configuration... config.middleware.use Apicraft::Middlewares::Mocker config.middleware.use Apicraft::Middlewares::Introspector end end ``` -```ruby -# config/routes.rb -# frozen_string_literal: true - -Rails.application.routes.draw do - # Rest of the routes - mount Apicraft::Web::App, at: "/apicraft" -end -``` - Now every API in the specification has a functional version. If a path isn't implemented, APICraft serves a mock response; otherwise, it forwards the request to your application as usual. ## Usage @@ -174,10 +164,35 @@ Example: `https://yoursite.com/api/orders` ``` ### 👀 API Documentation +Mount the documentation views in your route file. + +```ruby +# config/routes.rb + +Rails.application.routes.draw do + # Rest of the routes... + mount Apicraft::Web::App, at: "/apicraft" +end +``` + You can browse API Documentation at - `/apicraft/swaggerdoc` - `/apicraft/redoc` +Enable authentication for the `/apicraft` namespace. + +```ruby +# config/application.rb +module App + class Application < Rails::Application + # Rest of the configuration... + Apicraft::Web::App.use do |user, password| + [user, password] == ["admin", "password"] + end + end +end +``` + ## Configuration List of available configurations. @@ -218,6 +233,10 @@ Apicraft.configure do |config| mock: "Apicraft-Mock" } end + +Apicraft::Web::App.use do |user, password| + [user, password] == ["admin", "password"] +end ``` ## Contributing diff --git a/lib/apicraft/web/app.rb b/lib/apicraft/web/app.rb index 4343df3..d69dc8c 100644 --- a/lib/apicraft/web/app.rb +++ b/lib/apicraft/web/app.rb @@ -6,6 +6,8 @@ module Web # for all the views to be served class App def self.call(env) + return unauthorized_response unless authorized?(env) + uri = env["REQUEST_URI"] method = env["REQUEST_METHOD"] Router.namespace = env["SCRIPT_NAME"] @@ -14,7 +16,7 @@ def self.call(env) )[-1] content, content_type = Router.load_response!( - method, path + method, path || "/" ) raise Errors::RouteNotFound if content.nil? @@ -37,6 +39,27 @@ def self.call(env) ["Error: #{e.message}"] ] end + + def self.authorized?(env) + auth = Rack::Auth::Basic::Request.new(env) + username, password = auth.provided? && auth.basic? && auth.credentials + @use.call(username, password).present? + end + + def self.use(&block) + @use = block + end + + def self.unauthorized_response + [ + 401, + { + "Content-Type": "text/plain", + "WWW-Authenticate": "Basic realm=\"Restricted Area\"" + }, + ["Unauthorized"] + ] + end end end end