如何使用RSpec为JWT验证应用程序请求规范

时间:2017-02-19 11:04:44

标签: ruby-on-rails rspec rspec-rails

我只使用Rails 5 API应用程序并使用knock进行JWT身份验证。

完成模型和模型规范后,我开始执行请求规范。

但我不知道如何以正确的方式在请求规范中完成身份验证,

我的用户控制器,

module V1
  class UsersController < ApplicationController
    before_action :authenticate_user, except: [:create]
  end
end

应用程序控制器,

class ApplicationController < ActionController::API
  include Knock::Authenticable
  include ActionController::Serialization
end

我最愚蠢的解决方案(在休息请求之前调用get令牌请求获取JWT),

context 'when the request contains an authentication header' do
  it 'should return the user info' do
    user  = create(:user)
    post '/user_token', params: {"auth": {"email": user.email, "password": user.password }}
    body = response.body
    puts body # {"jwt":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0ODgxMDgxMDYsInN1YiI6MX0.GDBHPzbivclJfwSTswXhDkV0TCFCybJFDrjBnLIfN3Q"}
    # use the retrieved JWT for future requests
  end
end

感谢任何建议。

3 个答案:

答案 0 :(得分:8)

as.numeric

答案 1 :(得分:2)

李信阳的回答大部分对我有用。我在unrecognized keyword上进行了headers:的设置get。我修改了authenticated_header方法并将其放在support/api_helper.rb中,以便可以重用它。修改是将auth令牌合并到request.headers中。

# spec/support/api_helper.rb
module ApiHelper
  def authenticated_header(request, user)
    token = Knock::AuthToken.new(payload: { sub: user.id }).token
    request.headers.merge!('Authorization': "Bearer #{token}")
  end
end

在每个测试api的规范文件中,我都包含api_helper.rb。在测试有效身份验证的情况下,我在get语句之前调用了authenticated_header ...

# spec/controllers/api/v2/search_controller_spec.rb
RSpec.describe API::V2::SearchController, type: :controller do
  include ApiHelper
...
describe '#search_by_id' do
  context 'with an unauthenticated user' do
    it 'returns unauthorized' do
      get :search_by_id, params: { "id" : "123" }
      expect(response).to be_unauthorized
    end
  end

  context 'with an authenticated user' do
    let(:user) { create(:user) }

    it 'renders json listing resource with id' do
      expected_result = { id: 123, title: 'Resource 123' }
      authenticated_header(request, user)
      get :search_by_id, params: { "id" : "123" }
      expect(response).to be_successful
      expect(JSON.parse(response.body)).to eq expected_result
    end
  end

第二项测试的重点是...

authenticated_header(request, user)
get :search_by_id, params: { "id" : "123" }

答案 2 :(得分:1)

在李信阳的回答的帮助下,我能够为我的请求规范实现类似的功能。在这里分享,供其他人查看替代实施。

# spec/requests/locations_spec.rb
require 'rails_helper'

RSpec.describe 'Locations API' do
  let!(:user) { create(:user) }
  let!(:locations) { create_list(:location, 10, user_id: user.id) }

  describe 'GET /locations' do
    it 'reponds with invalid request without JWT' do
      get '/locations'
      expect(response).to have_http_status(401)
      expect(response.body).to match(/Invalid Request/)
    end

    it 'responds with JSON with JWT' do
      jwt = confirm_and_login_user(user)
      get '/locations', headers: { "Authorization" => "Bearer #{jwt}" }
      expect(response).to have_http_status(200)
      expect(json.size).to eq(10)
    end
  end
end

confirm_and_login_user(user)在request_spec_helper中定义,该{s包含在rails_helper.rb中作为模块:

# spec/support/request_spec_helper.rb

module RequestSpecHelper
  def json
    JSON.parse(response.body)
  end

  def confirm_and_login_user(user)
    get '/users/confirm', params: {token: user.confirmation_token}
    post '/users/login', params: {email: user.email, password: 'password'}
    return json['auth_token']
  end
end

我正在使用jwt gem生成我的令牌,如本SitePoint教程(https://www.sitepoint.com/introduction-to-using-jwt-in-rails/)中所述