РоР, Как я могу использовать контроллеры модульного тестирования с использованием RSPEC, которые защищены системой аутентификации JWT?
Я пытаюсь выполнить модульное тестирование контроллеров API RoR, используя гем rspec-rails.
Все мои контроллеры реализованы в этом классе ProtectedController, который перехватывает все запросы и проверяет заголовок авторизации.
class V1::ProtectedController < V1::BaseController
include JsonWebTokenAuthentication
attr_reader :current_user
before_action :validate_token!
# Check if authorize has been called (Pundit gem)
after_action :verify_authorized
private
def validate_token!
authorization_header = request.headers['Authorization'] || ''
puts "header: #{request.headers['Authorization']}"
jwt = JsonWebToken.new(authorization_header.gsub('Bearer ', ''))
if payload = jwt.verify
account = Account.find_by(id: payload[:user][:id])
if account.nil? || account.token_checksum == payload[:user][:token_checksum]
# If no account found still authorize because it is likely an app token
@current_user = Account.from_jwt_data(payload[:user])
end
end
return if @current_user
raise JsonWebTokenAuthentication::Unauthorized, 'invalid token'
end
end
Чтобы смоделировать эту систему аутентификации для тестирования, я создаю этот модуль AuthHelper, который будет возвращать JWT администратора (позже я могу создать другие учетные записи для других ролей или передать учетные данные для входа в эту функцию)
module AuthHelper
include Rack::Test::Methods
def app
Rails.application # This assumes you're using a Rails application
end
def admin_login
params = {
grant_type: 'password',
email: 'admin@arime.com',
password: 'preci666'
}
post '/api/v1/auth/token', params
expect(last_response.status).to eq(200)
auth_response = JSON.parse(last_response.body)
@access_token = auth_response['access_token']
end
end
Теперь все, что мне нужно сделать, это передать JWT во все мои запросы. что я сделал, например, в своей Workers_controller_spec, как показано ниже.
require 'rails_helper'
RSpec.describe V1::WorkersController, type: :request do
include AuthHelper
before {
admin_login
auth = "Bearer #{@access_token}"
}
describe "GET #index" do
it 'assigns @workers' do
worker1 = FactoryBot.create(:worker)
worker2 = FactoryBot.create(:worker)
#request.headers['Authorization'] = auth
auth = "Bearer #{@access_token}"
#request.headers['Authorization'] = auth
get v1_workers_path , headers: {
Authorization: auth
}
expect(response).to have_http_status(200)
end
end
end
Для меня все выглядит правильно, но не для rspec, статус ответа всегда 401. И самое странное, что когда я отлаживал request.headers['Authorization'] в своем защищенном контроллере, я обнаружил, что он пуст и находится в request.headers. проверить, я вижу свой заголовок авторизации:/
Когда я попытался передать заголовок, как в комментируемой части #request.headers['Authorization'] = auth, я получаю эту ошибку
1) V1::WorkersController GET #index assigns @workers
Failure/Error: request.headers['Authorization'] = auth
ArgumentError:
wrong number of arguments (given 0, expected 1..2)
помещает "header: #{request.headers['Authorization']}" в мой защищенный контроллер, возвращает
header:
помещает "запрос: #{request.inspect}" возвращает
header: request: #<ActionDispatch::Request GET
"http://example.org/api/v1/workers?
headers[Authorization]=Bearer+eyJhbGciOiJSUzI1NiJ9.eyJp..." for
127.0.0.1>
версия Ruby: 2.7.7 версия рельсов: 7.0.4.2 версия rspec-rails: 6.0.1
Кто-нибудь может помочь мне найти решение? или есть более правильный способ смоделировать мою систему аутентификации и вернуть current_user?