从密码更新控制器操作

时间:2016-09-25 10:25:02

标签: ruby-on-rails ruby-on-rails-4 devise

My Rails 5应用程序仅允许管理员或支持用户创建用户,在创建用户时生成密码并通过电子邮件发送给用户,在第一次用户登录时,应用程序强制他们更改密码。

我的架构中有一个password_updated字段,我想在密码更新时填写为true,但是我在这里碰壁,不确定它的编码器眼睛和我只是看不出哪里出错了。

我的应用程序控制器:

  # Force User To Change Password On First Login
  def after_sign_in_path_for(resource)
    if current_user.password_updated == "false"
      edit_passwords_path
    else
      authenticated_root_path
    end
  end

我已将其设置为如果用户尝试跳过或跳过密码更改,则会将其重定向到密码更改。

我的密码控制器:

class PasswordsController < ApplicationController
  def edit
    @user = current_user
  end

  def update
    if current_user.update_with_password(user_params)
      current_user.password_updated = "true"
      flash[:notice] = 'Your Password Has Been Sucessfully Updated.'
      redirect_to authenticated_root_path
    else
      flash[:error] = 'Oh No! Something Went Wrong, Please Try Again.'
      render :edit
    end
  end

  private
    def user_params
      params.require(:user).permit(:password_updated, :current_password, :password, :password_confirmation)
    end

end

最初我让应用程序控制器查看登录计数,但是如果用户关闭并等待足够长时间,他们可以重新登录而不必更改密码。我觉得这更有风险。

非常感谢这里的任何帮助。

3 个答案:

答案 0 :(得分:1)

我建议允许管理员创建没有密码的用户。您必须从设计中覆盖password_required方法。

def password_required?
   new_record? ? false : true
end

对于新记录,当admin创建它时,不需要密码,但是当用户注册时,它将提示添加密码。 或者您甚至可以保持条件,例如当用户是管理员时,返回false,否则返回true。

答案 1 :(得分:1)

我认为问题在于,在将current_user设置为true后,您不会保存password_updated 所以代码应该像

def update
  update_params = user_params.merge(password_updated: true)
  if current_user.update_with_password(update_params)
    flash[:notice] = 'Your Password Has Been Successfully Updated.'
    redirect_to authenticated_root_path
  else
    flash[:error] = 'Oh No! Something Went Wrong, Please Try Again.'
    render :edit
  end
end

这样您只需保存一次current_user

我认为password_updated是DB中的布尔字段 然后在application_controller.rb current_user.password_updated?中,您可以查看BrandName Expense Apple $1.8B Google $3.2B GE - facebook $281M McDonald $719M

答案 2 :(得分:1)

我会选择使用邀请的不同方法。

使用令牌(密码学随机字符串)创建受邀用户,该令牌用于标识用户。这消除了以明文形式传达临时密码的需要,例如,您可以为邀请令牌添加到期时间以确保安全。

所以app流程如下:

  • 管理员访问/invitiations/new
  • 他使用新用户的电子邮件和POST填写表单/invitations
  • 向新用户发送一封电子邮件,其中包含带有访问令牌的链接。
  • 新用户点击该链接并发送至/invitations/edit?invitation_token=ABCD12
  • 用户使用密码填写表单,并在请求正文中使用邀请令牌向/invitations发送PATCH。
  • 然后,系统会提示用户使用新密码进行签名。

最小的例子是:

class AddInvitationTokenToUser < ActiveRecord::Migration[5.0]
  def change
    add_column :users, :invitation_token, :string
    # this may not work on DBs that do not allow NULL on unique columns
    add_index :users, :invitation_token, unique: true
  end
end

然后我们需要设置User模型来创建随机邀请令牌。

require 'securerandom'
class User < ApplicationRecord

  # @todo skip password validation if user has invitation_token

  def set_invitation_token!
    self.invitation_token = generate_invitation_token
  end

  private 

    def generate_invitation_token
      # this ensures that the token is unique
      begin
        token = SecureRandom.urlsafe_base64
      end while User.where(invitation_token: token).any?
      token
    end
end

为邀请设置控制器:

class InvitationsController < ApplicationController

  before_action :authenticate!, only: [:new, :create]
  before_action :authorize!, only: [:new, :create]

  prepend_before_action :authenticate_user_from_token!, only: [:edit, :update]
  skip_before_action :authenticate!, :authorize!, only: [:edit, :update]

  def new
    @user = User.new
  end

  def create
    @user = User.new(create_params) do |u|
      u.set_invitation_token!
    end
    if @user.save
      # @todo email user invitation email
      redirect_to '/somewhere'
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @user.update(update_params)
      @user.update_attibute(:invitation_token, nil)
      redirect_to new_session_path, notice: 'Please sign in.'
    else
      render :edit
    end
  end

  private

    def authenticate_user_from_token!
      unless params[:invitation_token].present?
        raise ActiveRecord::RecordNotFound and return 
      end 
      @user = User.find_by!(invitation_token: params[:invitation_token])
    end

    def create_params
      require(:user).permit(:email)
    end

    def update_params
      require(:user).permit(:password, :password_confirmation)
    end
end

为简洁起见,此处省略了几个步骤,例如跳过密码验证。

我建议您查看DeviseInvitable以获取此模式的更完整示例。