如何测试使用Rails 5创建的经过身份验证的API?

时间:2019-03-22 06:04:29

标签: ruby-on-rails testing

我有一个使用Rails 5创建的需要身份验证的API。身份验证的基本流程是,用户使用用户名/密码在Base64编码的Authorization: Basic标头中执行登录,以及一个API键。然后将其交换为授权令牌,该令牌记录在用户数据库表中,并且在一段时间内有效。随后的API调用需要在Authorization: Bearer标头中使用此令牌。

我遇到的问题是,当我尝试测试需要身份验证的控制器时,我必须经历这种登录用户的过程(以确保auth_token位于测试数据库表,因为这可能是正在运行的第一个测试,等等。)这很复杂,因为,例如,如果我正在测试名为RecipesController的控制器,并且我的身份验证位于{{ 1}},我需要切换控制器才能执行登录操作。

我过去在AuthController中成功完成了以下操作:

spec_helper.rb

但是,正如我在Why are parameters not being passed within my test in Rails 5?中所意识到的那样,我相信这会扰乱我的测试请求,结果参数会丢失。

不过,这似乎是一种非常简单的模式,因此,我想知道如何对其进行测试?实际上,我宁愿单独测试身份验证,只传递一个模拟的用户对象,但是由于我对Rails的了解不如我所想,所以我不确定该怎么做。 >

1 个答案:

答案 0 :(得分:1)

在ApplicationController中具有您的Auth验证功能(假设您的食谱继承自此)

def current_user
  return nil unless auth_token
  User.find(decoded_token['user_id'])
end

def authenticate_with_token
  head(:unauthorized) unless user_signed_in?
end

private

def user_signed_in?
  current_user.present?
end

def auth_token
  return nil unless request.headers['Authorization'].present?
  request.headers['Authorization']&.split(' ')&.last
end

def decoded_token
  JsonWebToken.decode(auth_token) #use your own decoder class
end

然后您可以在需要认证的操作上添加before_action :authenticate_with_token

对于测试,您可以添加一个帮助程序来登录用户,这样就不必在需要身份验证的所有地方重复操作。

module LoginSupport
  def login_user(user:, password:)
    valid_credentials =  { "email": user.email, password: password}
    post '/auth/sessions', params: valid_credentials

    valid_jwt_token = JSON.parse(response.body)["token"]
    { "Authorization": "Bearer #{valid_jwt_token}" }.merge(json_api_headers)
  end

  def json_api_headers
    {'Accept' => JSONAPI::MEDIA_TYPE, 'CONTENT_TYPE' => JSONAPI::MEDIA_TYPE}
  end
end

RSpec.configure do |config|
  config.include LoginSupport
end

然后在您的RecipesContoller测试或任何其他地方的请求中使用返回的Auth令牌。