我有一个使用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的了解不如我所想,所以我不确定该怎么做。 >
答案 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令牌。