Devise - Omniauth - Невозможно зарегистрироваться (электронная почта уже существует), если ранее авторизовался у провайдера - PullRequest
0 голосов
/ 06 мая 2018

Я работаю над мультивендорной аутентификацией в приложении Ruby on Rails, используя Devise и omniauth - *.

Я, в основном, следовал по этой ссылке за исключением omniauth_callbacks_controller.rb, где я добавил:

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
    def after_sign_in_path_for(resource)
        if resource.email_verified?
            super resource
        else
            finish_signup_path(resource)
        end
    end

    def all
        puts request.env["omniauth.auth"]
        user = User.find_for_oauth(request.env["omniauth.auth"], current_user)
        if user.persisted?
            sign_in_and_redirect user, notice: "Signed in!"
        else
            session["devise.all"] = request.env["omniauth.auth"]
            redirect_to new_user_registration_url
        end
    end
    alias_method :twitter, :all
    alias_method :google_oauth2, :all
    alias_method :facebook, :all
    alias_method :instagram, :all
end

и app/models/user.rb Я изменил self.find_for_oauth на:

def self.find_for_oauth(auth, signed_in_resource = nil)
    identity = Identity.find_for_oauth(auth)

    user = signed_in_resource ? signed_in_resource :identity.user
    if user.nil?
        email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
        email = auth.info.email || if auth.info.nickname then auth.info.nickname + "@twitter.org" end
        user = User.where("email = ?", email).first if email

        if user.nil?
            user = User.new(
                first_name: auth.extra.raw_info.name,
                email: if auth.info.email != nil and auth.info.email != "" then auth.info.email else if auth.info.nickname then auth.info.nickname + "@twitter.org" end end ,
                password: Devise.friendly_token[0, 20]
            )
            user.skip_confirmation!
            user.save!
        end
    end

    if identity.user != user
        identity.user = user

        identity.save!
    end
    user
end

Мне удалось сделать так, чтобы пользователь мог войти в систему с помощью различных социальных сетей, созданных с одним и тем же адресом электронной почты, создав модель identity, в которой user has_many identities.

Однако сейчас я не могу подписаться (с помощью электронной почты и паролей) на электронное письмо, которое уже было получено объектом user, созданным с помощью социальных сетей.

Как я могу решить эту проблему?

UPDATE

Подход, который я сейчас пробую, заключается в проверке того, выполнил ли пользователь ранее такой же адрес электронной почты. Если это так, учетная запись пользователя должна быть обновлена ​​с регистрационными данными и предоставлена ​​для более identity объекта с provider, установленным пустым.

ОБНОВЛЕНИЕ 2

Теперь я могу зарегистрировать пользователя по электронной почте и паролю, настроив метод create в registrations_controller.rb на:

def create
    build_resource(sign_up_params)

    resource[:provider] = "<default provider>"
    if !User.find_by_email(resource.email) then
        resource.save
        yield resource if block_given?
        if resource.persisted?
            if resource.active_for_authentication?
                set_flash_message! :notice, :signed_up
                sign_up(resource_name, resource)
                respond_with resource, location: after_sign_up_path_for(resource)
            else
                set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
                expire_data_after_sign_in!
                respond_with resource, location: after_inactive_sign_up_path_for(resource)
            end
        else
            set_flash_message! :error, :"Something went wrong"
            clean_up_passwords resource
            set_minimum_password_length
            respond_with resource
        end
    else
        user = User.find_by_email(resource.email)
        if user.identities.count > 0 and user.provider != "<default provider>" then
        @identity = Identity.new
        @identity.provider = "made up provider"
        @identity.save
        user.password = resource.password
        if resource.country != nil and resource.country != "" then
             user.country = resource.country
        end
        if resource.title != nil and resource.title != "" then
            if resource.title != nil and resource.title != "" then
                user.title = resource.title
            end
            if resource.first_name != nil and resource.first_name != "" then
                user.first_name = resource.first_name
            end
            if resource.last_name != nil and resource.last_name != "" then
                user.last_name = resource.last_name
            end
            if resource.phone_number != nil and resource.phone_number != "" then
                user.phone_number = resource.phone_number
            end
            if resource.country_code != nil and resource.country_code != "" then
                user.country_code = resource.country_code
            end
            user.provider = "<default provider>"

            user.save
            yield user if block_given?
            if user.persisted?
                if resource.active_for_authentication?
                    set_flash_message! :notice, :signed_up
                    respond_with resource, location: after_sign_up_path_for(resource)
                else
                    set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
                    expire_data_after_sign_in!
                    respond_with resource, location: after_inactive_sign_up_path_for(user)
                end
            else
            set_flash_message! :error, :"Something went wrong"
            clean_up_passwords resource
            set_minimum_password_length
            respond_with resource
        end
    else
        set_flash_message! :error, "This Account already exists"
        redirect_to new_user_session_path
    end
end

Тем не менее, сообщение с «письмом-подтверждением отправлено на вашу электронную почту», в то время как письмо-подтверждение не отправлено.

Как я могу заставить его отправлять подтверждение по электронной почте, когда пользователь вводит пароль впервые (регистрация пользователя с электронной почтой и паролем)?

Update3

Мой текущий вопрос:

Используя Devise, как я могу отправить электронное письмо с подтверждением (идентично электронному письму с подтверждением регистрации) при первом обновлении пароля (или о конкретном действии)?

1 Ответ

0 голосов
/ 24 мая 2018

Я исправил проблемы с регистрацией и подтверждением, изменив Devise registrations_controller.rb, confirmations_controller.rb и sessions_controller.rb

В registrations_controller.rb Я изменил create метод на:

def create
    build_resource(sign_up_params)

    resource[:provider] = "<default provider>"
    if !User.find_by_email(resource.email) then
      resource.save
      yield resource if block_given?
      if resource.persisted?
        if resource.active_for_authentication?
          set_flash_message! :notice, :signed_up
          sign_up(resource_name, resource)
          respond_with resource, location: after_sign_up_path_for(resource)
        else
          set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
          expire_data_after_sign_in!
          respond_with resource, location: after_inactive_sign_up_path_for(resource)
        end
      else
        set_flash_message! :error, :"Something went wrong"
        clean_up_passwords resource
        set_minimum_password_length
        respond_with resource
      end
    else
      user = User.find_by_email(resource.email)
      if user.identities.count > 0 and (user.provider != "<default provider>" or user.provider != "<default provider>-confirmed") then
        @identity = Identity.new
        @identity.provider = "<default provider>"
        @identity.save
        user.password = resource.password
        if resource.username != nil and resource.username != "" then
            user.username = resource.username
        end
        if resource.phone_number != nil and resource.phone_number != "" then
            user.phone_number = resource.phone_number
        end
        ...
        user.provider = "<default provider>"
        user.save
        user.send_confirmation_instructions
        yield user if block_given?
        if user.persisted?
          if resource.active_for_authentication?
            set_flash_message! :notice, :signed_up
            respond_with resource, location: after_sign_up_path_for(resource)
          else
            set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
            expire_data_after_sign_in!
            respond_with resource, location: after_inactive_sign_up_path_for(user)
          end
        else
          set_flash_message! :error, :"Something went wrong"
          clean_up_passwords resource
          set_minimum_password_length
          respond_with resource
        end
      else
        set_flash_message! :error, "This Account already exists"
        redirect_to new_user_session_path
      end
    end
end

В confirmations_controller.rb Я изменил create и show методы:

# POST /resource/confirmation
def create
  self.resource = resource_class.send_confirmation_instructions(resource_params)
  yield resource if block_given?

  if successfully_sent?(resource)
    respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
  else
    if User.find_by_email(resource.email).provider != "<default provider>-confirmed" then
     User.find_by_email(resource.email).send_confirmation_instructions
     respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name))
    else
      respond_with(resource)
    end
  end
end

# GET /resource/confirmation?confirmation_token=abcdef
def show
  self.resource = resource_class.confirm_by_token(params[:confirmation_token])
  yield resource if block_given?

  if resource.errors.empty?
    resource.provider = "<default provider>-confirmed"
    resource.save
    set_flash_message!(:notice, :confirmed)
    respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
  else
    if User.find_by_email(resource.email).provider != "<default provider>-confirmed" then
      a = User.find_by_email(resource.email)
      a.provider = "<defualt provider>-confirmed"
      a.save
      set_flash_message!(:notice, :confirmed)
      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

В sessions_controller.rb Я также модифицировал create метод:

def create
    self.resource = warden.authenticate!(auth_options)
    if User.find_by_email(resource.email) and User.find_by_email(resource.email).provider == "<default provier>-confirmed" then
      self.resource = warden.authenticate!(auth_options)
      set_flash_message!(:notice, :signed_in)
      sign_in(resource_name, resource)
      yield resource if block_given?
      respond_with resource, location: after_sign_in_path_for(resource)
    else
      signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
      set_flash_message!(:error, "You have not yet confirmed your email");
      redirect_to root_path
    end
end
...