Rails 5 API基于Devise的Cookie认证在Cucumber中无法正常工作
嘿,我看你在给自研的Rails 5 API写Cucumber认证特性时,卡在了Devise Cookie认证的测试环节。先把你提供的authentication.feature文件按规范格式化出来,方便咱们后续排查:
Feature: Authentication As an existing user I would like to sign in the app Background: Given the following user exists: | id | email | password | | 1 | user@example.com | 12345678 | Scenario: Sign in When I perform a POST request with email "user@example.com" and password "12345678" to "/users/sign_in" Then I should receive a 200 OK response And the response should set a "session_id" cookie
接下来咱们一步步解决问题,我分享几个踩过的坑和对应的解决方案:
1. 搞定步骤定义的正确实现
在features/step_definitions/authentication_steps.rb里添加以下代码,注意Devise的参数格式和密码加密要求:
背景步骤:创建测试用户
Given("the following user exists:") do |table| table.hashes.each do |user_attrs| # Devise要求密码加密,绝对不能直接存明文! User.create!( id: user_attrs['id'].to_i, email: user_attrs['email'], password: user_attrs['password'], password_confirmation: user_attrs['password'] ) end end
登录请求步骤
When("I perform a POST request with email {string} and password {string} to {string}") do |email, password, path| # 发送POST请求时,要符合Devise的参数嵌套规则,还要设置Accept头支持JSON post path, params: { user: { email: email, password: password } }, headers: { 'Accept' => 'application/json' } end
响应验证步骤
Then("I should receive a {int} OK response") do |status_code| expect(response.status).to eq(status_code) end Then("the response should set a {string} cookie") do |cookie_name| expect(cookies[cookie_name]).to be_present end
2. 关键配置不能忘(Rails API模式的坑)
Rails 5 API模式默认不会加载Cookie和Session中间件,但Devise Cookie认证依赖它们!所以必须在config/application.rb里添加:
config.middleware.use ActionDispatch::Cookies config.middleware.use ActionDispatch::Session::CookieStore
同时调整config/initializers/devise.rb的配置,让Devise适配API场景:
# 关闭HTTP基本认证,改用Cookie认证 config.http_authenticatable = false # 让Devise识别JSON格式的请求 config.navigational_formats = ['*/*', :html] # 可选:根据你的路由设置登出方式 config.sign_out_via = :delete
3. 检查用户模型的Devise模块
确保你的User模型已经包含了:database_authenticatable模块,这是密码认证的核心:
class User < ApplicationRecord devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
常见排查点
- 如果你还是认证失败,先检查测试数据库里的用户密码是不是加密过的(直接查
encrypted_password字段,不能是明文) - 确认请求的参数是嵌套在
user键下的,Devise不接受顶级的email/password参数 - 用
puts response.body在步骤里打印响应内容,看看Devise返回的错误信息(比如密码错误、用户不存在)
内容的提问来源于stack exchange,提问作者Saad
相关产品推荐
相关产品推荐

