0

I want to allow authorized users to create (and destroy) user accounts. I have gotten this part working according to hints I found in this and other questions.

But I also want to prevent unauthorized users from creating and destroying accounts.

I have my own registration_controller:

class RegistrationsController < Devise::RegistrationsController

  skip_before_action :require_no_authentication, only: [:new, :create, :destroy]
  skip_before_action :authenticate_scope!, only: [:destroy]
  before_action :authenticate_user!, only: [:new, :create, :destroy] # why doesn't this work? 
  
  def new
    super
  end

  def sign_up(resource_name, resource)
    # don't sign in as the new user
  end

  def destroy
    User.find(params[:id]).destroy
    redirect_to(users_path) 
  end

end

And have directed my routes to use it in routes.rb:

  # Standard devise setup but allow registration when logged in
  # https://stackoverflow.com/a/31946248/1404185
  devise_for :users, controllers: {:registrations => "registrations"}

  # Work around already-existing session controller
  # https://stackoverflow.com/a/21024350/1404185
  devise_scope :user do
    post '/sessions/user', to: 'devise/sessions#create', via: :post
    delete '/users/:id', to: 'registrations#destroy', via: :delete
  end

  # Show and index for users
  # https://stackoverflow.com/a/32056094/1404185
  resources :users, :only => [:show,:index]  


For some reason before_action :authenticate_user! does not work... unauthenticated users can still invoke these actions. I've also tried prepend_before_action :authenticate_user!, and I've tried putting the filters in different orders-- invoking the before_action first in my controller.

I've just upgraded my app to rails 6.0.3.5 and added devise 4.7.1.

Why do I want this unusual setup? This is a hobby project and only my girlfriend and I are users. We don't want just anybody on the internet to sign up. But we occasionally may want to give another person access, who will be sitting next to us (pandemic permitting) when creating their account.

I do have a workaround for now: Since the site will have an obfuscated URL and since it is an extremely low value target (I can't imagine anyone would be interested in our home inventory) I simply don't provide a link to the signup page unless someone is logged in. This opens the possibility that a knowledgeable hacker could craft a request manually, but the risk is very very low.

But I still like to do things the "right" way, so I am asking this question. I have looked at devise_invitable but that seems way too complex for my needs.

UPDATE: One experiment I tried was instead of instead of inheriting from Devise::RegistrationsController and overriding methods, I just copied it to my registrations_controller and edited it. Then I deleted the :require_no_authenticaton and :authenticate_scope! prepend_before_actions and replaced them with prepend_before_action :authenticate_user!

This should eliminate doubt about whether the before_actions were being processed in the wrong order and ensure that only :authenticate_user! was being called.

The experiment failed. Apparently :authenticate_user! always returns true at this point whether or not a user is really authenticated. Why?

chetstone
  • 650
  • 1
  • 9
  • 19

1 Answers1

0

Apparently this has been an issue with devise for a long time.

The workaround is to change the before_action to:

prepend_before_action -> {authenticate_user!(force:true)}, only: [:new, :create, :destroy]

as suggested in this issue comment.

chetstone
  • 650
  • 1
  • 9
  • 19