我正在开发一个项目,该项目分为两个应用程序: - 一个处理数据库并将数据呈现为 JSON 的 rails JSON API - 一个“前端” rails 应用程序在需要时向 API 发送请求,并且以一种很好的方式显示 json 数据。
API 的身份验证是基于令牌的,gem'simple_token_authentication'
这意味着对于发送到 API 的大多数请求,您必须在请求头中发送用户令牌和他的电子邮件才能获得授权。
在我之前从事该项目的人还在 API 端安装了 Devise 身份验证系统,以允许在使用电子邮件和密码成功登录后从导航器直接访问 API 方法。
我刚刚开始在应该请求 API 的“前端应用程序”上进行编码,但我遇到了麻烦,尤其是在身份验证系统方面。
由于 Devise 已经安装在 API 上,我认为让用户登录前端应用程序是一个好主意,然后请求 API 上的设计方法用于创建用户、身份验证、重置密码......
问题是 devise 的方法是渲染 html 而不是 JSON,所以我实际上不得不覆盖大多数 devise 的控制器。让您快速了解它的工作原理:您在前端应用程序上填写注册表单,然后将参数发送到前端应用程序控制器,然后在 API 上请求设计的注册用户方法:
1)前端应用控制器:
def create
# Post on API to create USER
@response = HTTParty.post(ENV['API_ADDRESS']+'users',
:body => { :password => params[:user][:password],
:password_confirmation => params[:user][:password_confirmation],
:email => params[:user][:email]
}.to_json,
:headers => { 'Content-Type' => 'application/json' })
# si le User est bien crée je récupère son email et son token, je les store en session et je redirige vers Account#new
if user_id = @response["id"]
session[:user_email] = @response["email"]
session[:user_token] = @response["authentication_token"]
redirect_to new_account_path
else
puts @response
@errors = @response["errors"]
puts @errors
render :new
end
end
2)API覆盖的设计控制器:
class RegistrationsController < Devise::RegistrationsController
def new
super
end
def create
@user = User.new(user_params)
if @user.save
render :json => @user
else
render_error
end
end
def update
super
end
private
def user_params
params.require(:registration).permit(:password, :email)
end
def render_error
render json: { errors: @user.errors.full_messages }, status: :unprocessable_entity
end
end
这工作正常。在这里,我将刚刚在 API 上创建的用户作为 JSON 发回,我将身份验证令牌和他的电子邮件存储在会话哈希中。
我的问题是我试图重用一些设计代码的 reset_password 方法。首先,我要求重置密码,这将为请求更改的用户生成重置密码令牌。这还会向用户生成一封电子邮件,其中包含指向特定用户的重置密码表单的链接(内部带有令牌)。这运作良好。我收到电子邮件中的链接,然后转到我的前端应用程序上的 edit_password 表单:
更改您的密码
<form action="/users/password" method='post'>
<input name="authenticity_token" value="<%= form_authenticity_token %>" type="hidden">
<%= hidden_field_tag "[user][reset_password_token]", params[:reset_password_token] %>
<%=label_tag "Password" %>
<input type="text" name="[user][password">
<%=label_tag "Password Confirmation" %>
<input type="text" name="[user][password_confirmation]">
<input type="Submit" value="change my password">
</form>
提交表单后,它会通过我的前端应用程序控制器:
def update_password
@response = HTTParty.patch(ENV['API_ADDRESS']+'users/password',
:body => {
:user => {
:password => params[:user][:password],
:password_confirmation => params[:user][:password_confirmation],
:reset_password_token => params[:user][:reset_password_token]
}
}.to_json,
:headers => { 'Content-Type' => 'application/json' })
end
然后调用我重写的 Devise::PasswordController (update method) :
# app/controllers/registrations_controller.rb
class PasswordsController < Devise::RegistrationsController
# POST /resource/password
def create
if resource_params[:email].blank?
render_error_empty_field and return
end
self.resource = resource_class.send_reset_password_instructions(resource_params)
yield resource if block_given?
if successfully_sent?(resource)
render_success
else
render_error
end
end
def update
self.resource = resource_class.reset_password_by_token(resource_params)
yield resource if block_given?
if resource.errors.empty?
resource.unlock_access! if unlockable?(resource)
render_success
else
render_error
end
end
private
# TODO change just one big method render_error with different cases
def render_success
render json: { success: "You will receive an email with instructions on how to reset your password in a few minutes." }
end
def render_error
render json: { error: "Ce compte n'existe pas." }
end
def render_error_empty_field
render json: { error: "Merci d'entrer un email" }
end
end
但是该请求始终是 Unauthorized :
Started PATCH "/users/password" for ::1 at 2016-02-05 11:28:30 +0100
Processing by PasswordsController#update as HTML
Parameters: {"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "reset_password_token"=>"[FILTERED]"}, "password"=>{"user"=>{"password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "reset_password_token"=>"[FILTERED]"}}}
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms)
我不明白为什么最后一个请求未经授权?