Avoid sign-in after confirmation link click using

2019-01-13 20:27发布

问题:

I am using devise gem, after clicking on the confirmation link, I want to directly sign-in. At present it is asking to sign-in again.

Recently I have added the following in the devise initialize file:

config.allow_insecure_token_lookup = true
config.secret_key = 'a8d814803c0bcc735ce657adc77793459d00154cdd7532c13d3489600dc4e963f86e14beb593a32cbe9dbbe9197c9ce50a30102f363d90350052dc8d69930033'

Any suggestions?

回答1:

In previous Devise versions, the user was automatically signed in after confirmation. This meant that anyone that could access the confirmation e-mail could sign into someone’s account by simply clicking the link.

Automatically signing the user in could also be harmful in the e-mail reconfirmation workflow. Imagine that a user decides to change his e-mail address and, while doing so, he makes a typo on the new e-mail address. An e-mail will be sent to another address which, with the token in hands, would be able to sign in into that account.

If the user corrects the e-mail straight away, no harm will be done. But if not, someone else could sign into that account and the user would not know that it happened.

For this reason, Devise 3.1 no longer signs the user automatically in after confirmation. You can temporarily bring the old behavior back after upgrading by setting the following in your config/initializers/devise.rb:

config.allow_insecure_sign_in_after_confirmation = true

This option will be available only temporarily to aid migration.



回答2:

The config.allow_insecure_sign_in_after_confirmation flag is no longer supported in Devise.

While you should be aware of the possible security concerns of automatically logging users in when they confirm their account (http://blog.plataformatec.com.br/2013/08/devise-3-1-now-with-more-secure-defaults/), for some apps the benefit in terms of user experience may be worth the security tradeoff.

After all, the security risk is that a) the user mis-types their email, b) they don't immediately correct their mistake, c) the email they typed corresponds to a valid and working email, d) the person who incorrectly receives the email opens it and clicks the link.

If this is an acceptable risk profile for your application, you can override the devise ConfirmationsController:

class ConfirmationsController < Devise::ConfirmationsController
  def show
    self.resource = resource_class.confirm_by_token(params[:confirmation_token])
    yield resource if block_given?

    if resource.errors.empty?
      set_flash_message(:notice, :confirmed) if is_flashing_format?
      sign_in(resource) # <= THIS LINE ADDED
      respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
    else
      respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
    end
  end
end

And route to it in your routes.rb:

devise_for :users, controllers: { confirmations: 'confirmations' }


回答3:

With more recent versions of Devise, you can do the following.

config/routes.rb:

devise_for :users, controllers: { confirmations: 'users/confirmations' }

app/controllers/users/confirmations_controller.rb:

class Users::ConfirmationsController < Devise::ConfirmationsController
  def show
    super do |resource|
      sign_in(resource)
    end
  end
end


回答4:

Looking at mb21's answer, it should be

def show
  super do |resource|
    if resource.confirmation_sent_at > DateTime.now-2.hours && resource.errors.empty?
      sign_in(resource)
    end
  end
end

confirmation_sent_at is the time the email was sent to the user, as opposed to confirmed_at, which is the moment the user clicks the link, which is always within 2 hours of now on the server when it happens...



回答5:

We wanted the user so sign in automatically if she clicks the link in the email 2 hours or less after user creation. Based on @Sjor's answer, we went with:

class ConfirmationsController < Devise::ConfirmationsController
  def show
    super do |resource|
      if resource.confirmed_at > DateTime.now-2.hours && resource.errors.empty?
        sign_in(resource)
      end
    end
  end
end


回答6:

Here you have how you can solve it.

This code will allow the user to automatically sign-in after confirming, only if is the first time confirming his/her account.

class ConfirmationsController < Devise::ConfirmationsController
  before_action :maybe_auto_sign_in, only: :show

  protected

  def after_confirmation_path_for(resource_name, resource)
    sign_in(resource) if @auto_sign_in
    super
  end

  private

  # Automatically sign in the user that confirmed his/her email first time.
  def maybe_auto_sign_in
    @auto_sign_in =
      User.first_time_confirming?(params[:confirmation_token])
  end
end

class User < ActiveRecord::Base
  def self.first_time_confirming?(confirmation_token)
    confirmation_token &&
      User.where(confirmation_token: confirmation_token, unconfirmed_email: nil)
          .exists?
  end
end