设计(通过 API)可恢复:reset_password_token不能为空



我发现了一些关于可恢复功能的讨论和主题,但无法解决我遇到的问题。

我有一个前端API,它使用rails 3.2后端(使用Devise 2.2.4)所有路由都运行良好,但当我尝试更新密码时,它会发送一个json响应(在Postman中):

"reset_password_token" : "can't be blank"

如果我了解功能:

1-POST#POST/resource/password将重置密码发送到电子邮件(用作参数)2-然后我执行获取/资源/密码/编辑?reset_password_token=abcdef,它通过密码输入进入我的前端页面。3-当密码更改时,我启动#PUT/resource/password

这就是错误发生的地方。

这是password_controller.rb文件:

class Devise::PasswordsController < DeviseController
  prepend_before_filter :require_no_authentication
  # Render the #edit only if coming from a reset password email link
  append_before_filter :assert_reset_token_passed, :only => [:edit, :update]
# GET /resource/password/new
def new
  build_resource({})
end
# POST /resource/password
def create
  self.resource = resource_class.send_reset_password_instructions(resource_params)
  if successfully_sent?(resource)
    #respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
    render json: { message: "mail sent"}, status: 200
  else
    #respond_with(resource)
    render json: { :status }
  end
 end
 # GET /resource/password/edit?reset_password_token=abcdef
 def edit
  self.resource = resource_class.new
  resource.reset_password_token = params[:reset_password_token]
 end
 # PUT /resource/password
 def update
  self.resource = resource_class.reset_password_by_token(params[:reset_password_token])
  if resource.errors.empty?
  resource.unlock_access! if unlockable?(resource)
  flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
  set_flash_message(:notice, flash_message) if is_navigational_format?
  #sign_in(resource_name, resource)
  #respond_with resource, :location => after_resetting_password_path_for(resource)
  render json: { message: "password updated"}, status: 200
 else
  respond_with resource
 end
end
protected
 def after_resetting_password_path_for(resource)
  after_sign_in_path_for(resource)
 end
# The path used after sending reset password instructions
def after_sending_reset_password_instructions_path_for(resource_name)
  new_session_path(resource_name) if is_navigational_format?
end
# Check if a reset_password_token is provided in the request
def assert_reset_token_passed
  if params[:reset_password_token].blank?
    #set_flash_message(:error, :no_token)
    #redirect_to new_session_path(resource_name)
    render json: { message: "reset password is not blank"}, status: 200
  end
end
# Check if proper Lockable module methods are present & unlock strategy
# allows to unlock resource on password reset
def unlockable?(resource)
  resource.respond_to?(:unlock_access!) &&
    resource.respond_to?(:unlock_strategy_enabled?) &&
    resource.unlock_strategy_enabled?(:email)
end
end

recoverable.rb方法reset_password_by_token:

   def reset_password_by_token(attributes={})
      recoverable = find_or_initialize_with_error_by(:reset_password_token, attributes[:reset_password_token])
      if recoverable.persisted?
        if recoverable.reset_password_period_valid?
          recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
      else
        recoverable.errors.add(:reset_password_token, :expired)
      end
    end
    recoverable
  end
  Devise::Models.config(self, :reset_password_keys, :reset_password_within)

我试着在方法上添加一些put,但它们没有被抛出到积压工作中。这是我的铁路日志:

Started PUT "/users/password" for 192.168.0.18 at 2016-04-06 09:35:11 +0200
Processing by Devise::PasswordsController#update as JSON
Parameters: {"reset_password_token"=>"[FILTERED]", "password"=>"[FILTERED]"}
, :options=>{:count=>1, :default=>["User"]}, :description=>"User"}, {:key=>"activerecord.attributes.user.confirmation_token", :locale=>:en, :options=>{:count=>1, :default=>[:"attributes.confirmation_token", "Confirmation token"]}, :description=>"Confirmation token"}, {:key=>"activerecord.attributes.user.unconfirmed_email", :locale=>:en, :options=>{:count=>1, :default=>[:"attributes.unconfirmed_email", "Unconfirmed email"]}, :description=>"Unconfirmed email"}, {:key=>"activerecord.attributes.user.email", :locale=>:en, :options=>{:count=>1, :default=>[:"attributes.email", "Email"]}, :description=>"Email"}, {:key=>"activerecord.attributes.user.reset_password_token", :locale=>:en, :options=>{:count=>1, :default=>[:"attributes.reset_password_token", "Reset password token"]}, :description=>"Reset password token"}]}
Completed 422 Unprocessable Entity in 2174ms (Views: 0.4ms | ActiveRecord: 1.6ms)

===================

编辑

===================

为了理解请求的来源,我在下面添加了关于Angular/FrontEnd部分的PUT请求:

  users.newPassword = function (token, password) {
    var putData = {
     user:{
       reset_password_token: token,
       password: password
     }
  };
  return Restangular.withConfig(function(RestangularConfigurer) {
    RestangularConfigurer.setFullResponse(true);
    }).one('/users/password').customPUT(putData);
  };

您正在将reset_password_by_token声明为类方法。那很好。但您没有将资源对象或reset_password_token作为参数传递给方法。这意味着不要设置怨恨。

您可以调试并检查资源是否正在设置reset_password_token。如果是,则按照

self.resource = resource_class.reset_password_by_token(params[:confirmation_token])

所以,要么使用

resource.reset_password_by_token(params[:password])

resource_class.reset_password_by_token(params[:password], params[:reset_password_token])

我终于找到了修复方法。事实上,Devise正在以用户Array的身份等待参数。我直接发送reset_password_token,但Devise正在等待user[reset_password_token]。。。。。

生成的令牌也不是好的令牌。在我的邮件模板中,我有:

You asked to <%= link_to 'reset your password', edit_password_url(@resource, reset_password_token: @resource.reset_password_token %>.

我把它修改成

You asked to <%= link_to 'reset your password', edit_password_url(@resource, reset_password_token: @token %>.

相关内容

最新更新