ruby 如何将auth token添加到每个http RSpec测试标头

aelbi1ox  于 12个月前  发布在  Ruby
关注(0)|答案(1)|浏览(85)

我在验证一个请求规范时遇到了问题。如何在每个http请求的头中传递有效的auth令牌?我下面的方法是正确的吗?
tweets_request_spec.rb

require 'rails_helper'

RSpec.describe 'Tweets API', type: :request do
  before do
    @tweets = create_list(:tweet, 10)
    @tweet = @tweets.first
  end

  describe 'GET /tweets' do
    before { get '/tweets', { "Authorization": *some sort of token*} }

    it "returns tweets" do
      expect(json).to_not be_empty
      expect(json).to eq(10)
    end

    it "is a successful http request" do
      expect(response).to have_http_response(200)
    end
  end
end

下面是我的身份验证控制器代码,以及帮助生成和解码在http头中传递的auth令牌的模块。
authentication_controller.rb

class AuthenticationController < ApplicationController
  skip_before_action :authenticate_request

  def authenticate
    command = AuthenticateUser.call(params[:email], params[:password])

    if command.success?
      render json: { auth_token: command.result }
    else
      render json: { error: command.errors }, status: :authorized
    end
  end
end

authorize_API_request.rb

class AuthorizeApiRequest
  prepend SimpleCommand

  def initialize(headers = {})
    @headers = headers
  end

  def call
    user
  end

  private

  attr_reader :headers

  def user
    @user ||= User.find(decoded_auth_token[:user_id]) if decoded_auth_token
    @user ||= errors.add(:token, 'Invalid token') && nil
  end

  #decode the auth token and retrieve the user id
  def decoded_auth_token
    @decoded_auth_token ||= JSONWebToken.decode(http_auth_header)
  end

  #retrieve auth token from header
  def http_auth_header
    if headers['Authorization'].present? 
      return headers['Authorization'].split(' ').last
    else
      errors.add(:token, 'Missing token')
    end
  end
end
elcex8rz

elcex8rz1#

从官方pluralsight页面复制的一些代码摘录
要验证的端点位于config/routes.rb

post 'authenticate', to: 'authentication#authenticate'

它执行这个动作。如果您正确地进行了身份验证,该操作将返回令牌。

def authenticate 
   command = AuthenticateUser.call(params[:email], params[:password]) 
   if command.success? 
      render json: { auth_token: command.result } 
   else 
      render json: { error: command.errors }, status: :unauthorized 
   end 
end

在rspec中,你有两个选择,你可以模仿这个方法或者创建一个工厂。
token based身份验证的概念是,一旦通过身份验证,用户将拥有一个令牌,通过提供此令牌,他将能够访问仅保留给用户的功能
请求

$ curl -H "Content-Type: application/json" -X POST -d '{"email":"[email protected]","password":"123123123"}' http://localhost:3000/authenticate

作为响应,

{"auth_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE0NjA2NTgxODZ9.xsSwcPC22IR71OBv6bU_OGCSyfE89DvEzWfDU0iybMA"}

如果在标头中包含令牌,请求将不会触发授权错误

$ curl -H "Authorization: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJleHAiOjE0NjA2NTgxODZ9.xsSwcPC22IR71OBv6bU_OGCSyfE89DvEzWfDU0iybMA" http://localhost:3000/items []

因此,在执行get请求之前,请在请求头中包含令牌

request.headers['Authorization'] = auth_token
get :your_action

如何计算auth_token的正确值?
您将需要在ApplicationControllermock方法authenticate_request,因为它被称为beforeaction

#app/controllers/application_controller.rb
class ApplicationController < ActionController::API
 before_action :authenticate_request
  attr_reader :current_user

  private

  def authenticate_request
    @current_user = AuthorizeApiRequest.call(request.headers).result
    render json: { error: 'Not Authorized' }, status: 401 unless @current_user
  end
end

我认为您应该模仿这行代码,以避免收到身份验证错误。

@current_user = AuthorizeApiRequest.call(request.headers).result

所以我会写这样的说明书

user = FactoryBot.create(:user)
allow(AuthorizeApiRequest).to receive(:call).and_return(user)
# request.headers['Authorization'] = auth_token # this is not required anymore the authentication is skipped
get :your_action

我引用了pluralsight
通过使用before_action,服务器在用户每次发出请求时都将request headers(使用内置对象属性request.headers)传递给AuthorizeApiRequest。在AuthorizeApiRequest.call(request.headers)上调用result来自SimpleCommand模块,其中它被定义为attr_reader :result。请求结果返回到@current_user,从而可用于从ApplicationController继承的所有控制器。
你可以阅读更多关于嘲笑
https://github.com/rspec/rspec-mocks

相关问题