私は2つのアプリに分割されたプロジェクトに取り組んでいます:-データベースを処理し、データをJSONとしてレンダリングする1つのレールJSON API-必要なときにAPIにリクエストを送信する1つの「フロントエンド」レールアプリjsonデータを素敵な方法で表示します。
API の認証はトークン ベースですgem'simple_token_authentication'
。つまり、API に送信されるほとんどのリクエストでは、リクエストを承認するためにヘッダーでユーザー トークンとその電子メールを送信する必要があります。
私の前にプロジェクトに携わった人は、API 側に Devise 認証システムをインストールして、メールとパスワードでログインに成功した後、ナビゲーターから API メソッドに直接アクセスできるようにしました。
API を要求する「フロントエンド アプリ」でコーディングを開始したばかりで、特に認証システムに問題があります。
Devise は既に API にインストールされているので、ユーザーをフロントエンド アプリにログインさせ、ユーザーの作成、認証、パスワードのリセットのために API に存在するデバイスのメソッドを要求することをお勧めします...
問題は、デバイスのメソッドが JSON ではなく html をレンダリングしているため、デバイスのコントローラのほとんどを実際にオーバーライドする必要があったことです。それがどのように機能するかを簡単に理解するには: フロントエンド アプリでサインアップ フォームに入力すると、パラメーターがフロントエンド アプリ コントローラーに送信され、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 メソッド) を呼び出します。
# 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)
この最後のリクエストが無許可である理由がわかりません。