Rails: How to add HTTP AUTH at custom action - ruby-on-rails

How to add HTTP AUTH at custom controller action?
class MyController < ApplicationController
def index
#NO AUTH
end
def custom
#I NEED HTTP AUTH ONLY HERE
end
end
routes.rb:
get 'my/custom', to: 'my#custom'

class MyController < ApplicationController
http_basic_authenticate_with name: "dhh", password: "secret", only: [:custom]
def custom
#I NEED HTTP AUTH ONLY HERE
end
end
You can also call the auth directly in the action:
class MyController < ApplicationController
def custom
authenticate_or_request_with_http_basic do |username, password|
username == "dhh" && password == "secret"
end
...
end
end
Here are the docs for more advanced usage: https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html

You can use the http_basic_authenticate_with method. I have passed the :custom symbol to the :only option, which means the authentication will only apply to that method.
class MyController < ApplicationController
http_basic_authenticate_with name: "username", password: "password", only: :custom
def index
#NO AUTH
end
def custom
#I NEED HTTP AUTH ONLY HERE
end
end

Related

Rails check if Devise has any errors?

I am looking for a way to check if Devise has any errors (invalid credentials etc.) for a before_action method in my ApplicationController. There is code in that method that I need only to run if Devise has no errors.
class ApplicationController < ActionController::Base
before_action :foo
def foo
if !devise_errors?
end
end
You can check credential errors like this:
class ApplicationController < ActionController::Base
before_action :foo
def foo
if !devise_errors?
end
..
private
def devise_errors?
login_params = devise_parameter_sanitizer.sanitize(:sign_in)
email = login_params.dig(:email)
password = login_params.dig(:password)
user = User.find_by(email: email)
return true if user.blank?
!user.valid_password?(password)
end
..
end
Do you mean sign in errors? Wouldn't you only need this in the session controller?
You could check the flash messages...
But you might be better off checking in Warden:
Warden::Manager.warden_callback do |user, auth, opts|
# code
end

Rails 5, pundit authorization

Pundit works well, if action has resources like:
class Admin::PagesController << ApplicationController
def index
#pages = Page.all
end
end
How to authorise method without any resources in action?
class Admin::DashboardController << ApplicationController
def index
end
end
I hav file policies/admin/dashboard_policy.rb
class Admin::DashboardPolicy < ApplicationPolicy
class Scope < Scope
def resolve
scope.all
end
end
end
This file was generated by command:
rails g pundit:policy Admin/Dashboard
File views/admin/index.html.slim has only static text. Nothing more.
How to authorise action without any resources?
Regards
Sssebaaa
To authorize without a scope or model instance call authorize with a symbol or array of symbols (when namespaced):
class Admin::DashboardController << ApplicationController
def index
authorize [:admin, :dashboard]
end
end
This will call the #index? method on the policy class:
class Admin::DashboardPolicy < ApplicationPolicy
def index?
user.admin?
end
end
You can also remove the scope completely from your policy.
If you don't have any callbacks checking that the policy is scoped, as pundit doc suggests, like
class ApplictationController < ActionController::Base
include Pundit
after_action :verify_policy_scoped, only: :index
end
You don't have anything to do.
However if you do have a callback, you can just skip it in your controller action like this:
class Admin::DashboardController << ApplicationController
skip_after_action :verify_policy_scoped, only: [:index]
def index
end
end

Authenticate two different devise classes in same controller in Rails

I have this view called Intranet where only authenticated "devise clients" can access.
class IntranetController < ApplicationController
before_action :authenticate_client!
def index
end
end
On the other side, I also have other "devise admin", this devise admin requires to access the same view. How can I handle this situation?
Try this:
class IntranetController < ApplicationController
before_action :authenticate_all!
def index
end
def authenticate_all!
if admin_signed_in?
true
else
authenticate_client!
end
end
end

Undefined method error for displaying in JSON

I'm writing a simple Ruby API for a to-do list. Here is what I have so far:
API CONTROLLER:
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
private
def authenticated?
authenticate_or_request_with_http_basic {|username, password| User.where( username: username, password: password).present? }
end
end
API/USERS_CONTROLLER:
class Api::UsersController < ApplicationController
before_action :authenticated?
def index
users = User.all
render json: users, each_serializer: UserSerializer
end
end
ROUTES:
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
resources :users
end
resources :welcome, only: [:index]
root 'welcome#index'
end
When I try to navigate to the api_users_path, it brings up the error:
undefined method `authenticated?' for # Api::UsersController:0x007f36a3f779f8
I'm sure there is something simple I am missing, can someone point me in the right direction?
To make the authenticated? method available to your Api::UsersController, change private to protected in application_controller.rb:
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
protected
def authenticated?
authenticate_or_request_with_http_basic {|username, password| User.where( username: username, password: password).present? }
end
end
Changing to protected will make that method available to ApplicationController and all of it's sub-classes. If it's set to private that method will only be available to ApplicationController itself.
You should also make sure that Api::UsersController inherits from ApiController:
class Api::UsersController < ApiController
...
end
The method authenticated? is defined on ApiController. Api::UsersController does not have access to this method. To use it on all your controllers you can define this method on ApplicationController as protected.

How to exclude a single controller action from a filter in Rails 3.07?

class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :check_session_expiry, :except => :login
How do you exclude a single controller's (the users controller, for example) login action?
First, I'm not on a machine with rails to test it, but the following should work:
class UserController < ApplicationController
skip_filter :check_session_expiry, :only => :foo
# following is DEPRECATED as far as I know
#skip_before_filter :check_session_expiry, :only => :foo
def foo
end
end
class ApplicationController < ActionController::Base
before_filter :check_session_expiry
def check_session_expiry
return true if self.class != UsersController && self.action == "login"
# do your thing
end
I would just redefine check_session_expiry in your controller to be an empty method.
class UserController < ...
...
private
def check_session_expire
# optional if other actions shall still use the filter
super unless self.action == 'login'
end
end

Resources