如何使用rswag测试带JWT认证与不带认证的API请求
如何使用rswag测试带JWT认证与不带认证的API请求
我太懂这种折腾的感觉了!之前用rswag测试API认证的时候,也卡在过“怎么同时测带token和不带token的场景”这个问题上,尤其是不带token的401情况,试了好几种方法都踩坑。别急,我来给你捋清楚怎么解决。
核心问题分析
你当前的全局Swagger配置里默认开启了security: [ { AuthToken: [] } ],这意味着所有请求都会默认要求带上JWT头。要测试不带token的场景,关键是在对应的response块里覆盖这个全局security设置,同时不要定义Authorization变量——这样rswag就不会自动添加这个请求头了。
具体解决方案
咱们直接修改你的测试代码,看关键改动:
首先,把请求块里的全局security配置去掉(因为每个response的认证需求不一样):
get 'retrieves a list of accessible unicorns' do tags 'unicorns' produces 'application/vnd.api+json' # 删掉原来的 security [ {AuthToken: [], NoAuth: []} ],改成在每个response里单独设置
然后针对每个response分别配置:
- 200 正常认证场景
保持原来的逻辑,指定需要AuthToken,同时生成有效的JWT:
response '200', 'properly authenticated request' do security [ { AuthToken: [] } ] # 明确要求带认证头 let(:Authorization) { JWT.encode({ auth: { user_id: user.pyx_user_id } }, nil, 'none') } run_test! end
- 400 无效token场景
同样需要带AuthToken,但传入错误的token值:
response '400', 'malformatted auth token' do security [ { AuthToken: [] } ] let(:Authorization) { 'AAABBBCCCDDDDEEE-invalid' } run_test! end
- 401 无认证场景
这里是关键:把security设为空数组,并且不定义Authorization变量,这样就不会发送认证头了:
response '401', 'no authentication' do security [] # 告诉rswag不需要任何认证头 # 不要定义let(:Authorization),这样请求里就不会有这个头 run_test! end
- 401 有效但无权限场景
如果还要测“有token但权限不够”的情况,同样指定AuthToken,生成一个合法但无权限的JWT即可:
response '401', 'valid but unauthorized' do security [ { AuthToken: [] } ] # 生成一个有权限问题的token,比如用无权限用户的id let(:unauthorized_user) { create(:user, account: account, role: :viewer) } let(:Authorization) { JWT.encode({ auth: { user_id: unauthorized_user.pyx_user_id } }, nil, 'none') } run_test! end
为什么之前的方法不行?
- 你尝试设置
let(:Authorization) { nil }:这会发送一个Authorization: Bearer的空值头,和“完全不发送头”是两种不同的请求,后端的认证逻辑可能会区别处理。 - 你尝试在请求块里加多个securityScheme:rswag的请求块级security会应用到所有子response,没法单独控制,所以必须在每个response里单独配置security。
完整修改后的测试代码
RSpec.describe 'api/v1/unicorns', type: :request do path '/unicorns.json' do let(:user) { create(:perceptyx_owner) } let(:account) { create(:account, owners: [user]) } get 'retrieves a list of accessible unicorns' do tags 'unicorns' produces 'application/vnd.api+json' response '200', 'properly authenticated request' do security [ { AuthToken: [] } ] let(:Authorization) { JWT.encode({ auth: { user_id: user.pyx_user_id } }, nil, 'none') } run_test! end response '400', 'malformatted auth token' do security [ { AuthToken: [] } ] let(:Authorization) { 'AAABBBCCCDDDDEEE-invalid' } run_test! end response '401', 'no authentication' do security [] run_test! end response '401', 'valid but unauthorized' do security [ { AuthToken: [] } ] let(:unauthorized_user) { create(:user, account: account, role: :viewer) } let(:Authorization) { JWT.encode({ auth: { user_id: unauthorized_user.pyx_user_id } }, nil, 'none') } run_test! end end end end
这样修改后,每个场景都会按照预期发送对应的请求头,完美覆盖你需要的四种测试情况啦!
备注:内容来源于stack exchange,提问作者MustModify
相关产品推荐
相关产品推荐

