访问rails api设计中的经过身份验证的路由

时间:2015-03-11 03:51:43

标签: ruby-on-rails curl devise

有人可以帮我弄清楚如何使用rails中的设计正确访问经过身份验证的路由吗?我已经弄清楚如何验证会话并获取令牌,但是当我在经过身份验证的路由中传递该令牌时,我收到有关需要登录的错误。这可能是一个卷曲格式问题,但我是rails的新手,我不太清楚该怎么做。

我可以传递curl命令并获取正确的令牌:

curl -X POST 'http://localhost:3000/users/sign_in.json' -d 'user[email]=user@name.com&user[password]=password'

我回来了:

{"token":"at6aig30jzulnnyomrm4c5","user_email":"user@name.com"}

问题在于,当我尝试访问用户的路由时,我收到了一个拒绝权限错误:

curl -L 'http://localhost:3000/users/me.json?token=at6aig30jzulnnyomrm4c5'
{"error":"You need to sign in or sign up before continuing."}

我的路线看起来像这样:

  devise_for :users, controllers: { sessions: 'sessions' }, :skip => [:passwords]
  resources :users, only: [:create, :update] do 
    get 'me' => 'users#me', on: :collection
  end

相应的路线如下所示:

      new_user_session GET        /users/sign_in(.:format)                  sessions#new
          user_session POST       /users/sign_in(.:format)                  sessions#create
  destroy_user_session DELETE     /users/sign_out(.:format)                 sessions#destroy
              me_users GET        /users/me(.:format)                       users#me
                 users POST       /users(.:format)                          users#create
                  user PATCH      /users/:id(.:format)                      users#update
                       PUT        /users/:id(.:format)                      users#update

我的用户控制器如下所示:

class UsersController < ApplicationController
  before_action :authenticate_user!, except: [:create, :start_password_reset, :finish_password_reset]
  before_action :assert_reset_token_passed, only: [:finish_password_reset]

  def create
    user = User.new(register_params)

    if user.save
      render json: user, status: :created
    else
      render json: { errors: user.errors.full_messages }, status: :unprocessable_entity
    end
  end

  def update
    if current_user.update(user_params)
      render json: current_user
    else
      render json: { errors: current_user.errors.full_messages }, status: :unprocessable_entity
    end
  end

  def me
    if current_user
      render json: current_user, status: 200
    else
      render json: {}, status: 400
    end
  end

  def start_password_reset
    user = User.where(email: params[:email]).first
    user.send_reset_password_instructions if user
    render json: {}
  end

  def finish_password_reset
    user = User.with_reset_password_token(params[:reset_password_token])
    if user
      if user.reset_password!(reset_params[:password], reset_params[:password_confirmation])
        render json: {}
      else
        render json: { errors: user.errors.full_messages }, status: 400
      end
    else
      render json: { errors: ['Invalid password reset request.'] }, status: 403
    end
  end

  private

  def register_params
    params.require(:user).permit(:email, :password, :time_zone)
  end

  def user_params
    params.require(:user).permit(:include_email_memory, :time_zone, email_times: [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday])
  end

  def reset_params
    params.permit(:password, :password_confirmation)
  end

  # Check if a reset_password_token is provided in the request
  def assert_reset_token_passed
    render(json: { errors: ['Invalid password reset request.'] }, status: 403) if params[:reset_password_token].blank?
  end

end

对于它的价值,我正在尝试使用Ember simple-auth,这样我就可以正确加载用户的个人资料。谢谢您的帮助!

编辑:根据要求,这是我的应用程序控制器:

class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :null_session
  skip_before_filter :verify_authenticity_token

  before_filter :authenticate_user_from_token!
  #before_filter :authenticate_user!

  around_action :user_time_zone, if: :current_user

  def index
    render file: 'public/index.html'
  end

  protected

  # def authenticate_user!
  #   render(json: {}, status: 401) unless current_user
  # end

  private

  def authenticate_user_from_token!
    authenticate_with_http_token do |token, options|
        user_email = options[:user_email].presence
        user       = user_email && User.find_by_email(user_email)

        if user && Devise.secure_compare(user.authentication_token, token)
          sign_in user, store: false
        end
      end
  end

  def user_time_zone(&block)
    Time.use_zone(current_user.time_zone, &block)
  end

  # If this is a get request for HTML, just render the ember app.
  def handle_html
    render 'public/index.html' if request.method == 'GET' && request.headers['Accept'].match(/html/)
  end
end

1 个答案:

答案 0 :(得分:1)

您只在请求中包含token

curl -L 'http://localhost:3000/users/me.json?token=at6aig30jzulnnyomrm4c5'

但您的服务器也希望传递电子邮件:

authenticate_with_http_token do |token, options|
  user_email = options[:user_email].presence
  user       = user_email && User.find_by_email(user_email)
  …