0

私は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)

この最後のリクエストが無許可である理由がわかりません。

4

1 に答える 1