Rails 7:使用Devise和JWT进行身份验证的API-only应用程序

作者:API传播员 · 2026-01-07 · 阅读时间:6分钟
本文详细讲解如何在Rails 7中构建API-only应用程序,使用Devise和JWT实现用户身份验证,并结合JSON:API序列化器处理数据格式化。涵盖从安装gem、配置Devise和JWT、生成JWT密钥到使用JSON:API序列化器的完整流程,帮助开发者快速上手高效、安全的认证服务。

使用 Devise 和 JWT 构建 Rails 7 API-only 应用程序

在本文中,我们将介绍如何在 Rails 7 中使用 Devise 和 JWT 实现用户身份验证,并结合 JSON:API 序列化器来处理数据格式化。以下内容将详细讲解从安装到配置的完整流程,帮助你快速上手。


配置 Devise、JWT 和 JSON:API 序列化器

在开始之前,我们需要安装以下 gem:

  • Devise:处理用户身份验证的核心 gem,提供用户创建和会话管理功能。
  • Devise-JWT:Devise 的扩展,用于生成和验证 JWT(JSON Web Token)。
  • JSON:API Serializer:用于将 Ruby 对象序列化为符合 JSON:API 规范的格式。

Gemfile 中添加以下依赖:

gem 'devise'
gem 'devise-jwt'
gem 'jsonapi-serializer'

然后运行以下命令安装这些 gem:

bundle install

配置 Devise

安装 Devise

运行以下命令生成 Devise 的初始化文件:

rails g devise:install

编辑生成的 config/initializers/devise.rb 文件,确保以下配置:

config.navigational_formats = []

这将禁用默认的 Flash 消息功能,因为在 API-only 模式下 Flash 消息是无效的。

配置开发环境

config/environments/development.rb 文件末尾添加以下行:

config.action_mailer.default_url_options = { host: 'localhost', port: 3001 }

我们将 Rails API 服务运行在端口 3001,而前端(如 React 应用)运行在默认的 3000 端口。为此,还需要更新 config/puma.rb 文件中的端口配置:

port ENV.fetch('PORT') { 3001 }

创建用户模型

运行以下命令生成用户模型:

rails g devise User

然后执行数据库迁移:

rails db:create db:migrate

生成 Devise 控制器

为了自定义用户登录和注册逻辑,我们需要生成 Devise 的控制器:

rails g devise:controllers users -c sessions registrations

在生成的控制器中,确保它们可以响应 JSON 格式:

class Users::SessionsController < Devise::SessionsController
  respond_to :json
end

class Users::RegistrationsController < Devise::RegistrationsController
  respond_to :json
end

自定义路由

config/routes.rb 中覆盖默认路由,并添加自定义路径别名:

Rails.application.routes.draw do
  devise_for :users, path: '', path_names: {
    sign_in: 'login',
    sign_out: 'logout',
    registration: 'signup'
  },
  controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations'
  }
end

添加额外的用户字段

如果需要在用户注册时添加额外字段(如姓名和头像),可以在 ApplicationController 中配置允许的参数:

class ApplicationController < ActionController::API
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: %i[name avatar])
    devise_parameter_sanitizer.permit(:account_update, keys: %i[name avatar])
  end
end

接着创建迁移文件,为用户表添加 name 字段:

rails g migration AddNameToUsers name:string
rails db:migrate

配置 Devise-JWT

生成 JWT 密钥

JWT 需要使用私钥进行签名。运行以下命令生成密钥:

bundle exec rails secret

将生成的密钥添加到加密的凭据文件中:

EDITOR='code --wait' rails credentials:edit

在打开的文件中添加以下内容:

devise_jwt_secret_key: 

配置 JWT

编辑 config/initializers/devise.rb 文件,添加以下配置:


config.jwt do |jwt|  jwt.secret = Rails.application.credentials.devise_jwt_secret_key!
  jwt.dispatch_requests = [
    ['POST', %r{^/login$}]
  ]
  jwt.revocation_requests = [
    ['DELETE', %r{^/logout$}]
  ]
  jwt.expiration_time = 30.minutes.to_i
end

这段代码指定了 JWT 的分发和撤销规则,并将令牌的有效期设置为 30 分钟。

配置撤销策略

为了安全性,我们需要在用户模型中添加 JTI(JWT ID)字段,并使用 JTIMatcher 策略管理令牌撤销。首先,创建迁移文件:

rails g migration AddJtiToUsers jti:string:index:unique

编辑生成的迁移文件,确保字段不可为空且唯一:

class AddJtiToUsers < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :jti, :string, null: false
    add_index :users, :jti, unique: true
  end
end

运行迁移:

rails db:migrate

然后在用户模型中配置 JWT 策略:

class User < ApplicationRecord
  include Devise::JWT::RevocationStrategies::JTIMatcher

  devise :database_authenticatable, :registerable,
         :recoverable, :validatable,
         :jwt_authenticatable, jwt_revocation_strategy: self
end

使用 JSON:API Serializer

JSON:API Serializer 可以帮助我们按照 JSON:API 规范生成响应。安装 gem 后,为用户模型生成序列化器:

rails g serializer user id email name

生成的序列化器会包含指定的属性,可以通过以下方式调用:

UserSerializer.new(user).serializable_hash[:data][:attributes]

user 替换为实际的用户对象。


总结

通过本文的步骤,你已经成功配置了一个基于 Rails 7 的 API-only 应用程序,支持使用 Devise 和 JWT 进行身份验证,并使用 JSON:API Serializer 格式化数据。这种架构非常适合现代前后端分离的应用场景,能够提供高效、安全的用户认证服务。

原文链接: https://sdrmike.medium.com/rails-7-api-only-app-with-devise-and-jwt-for-authentication-1397211fb97c