You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已集成Devise的Rails 6 API添加ActiveAdmin后的登录登出问题

Rails 6 API + Devise/JWT + ActiveAdmin 登录与登出问题解决方案

问题描述

  • 访问/admin路径时,页面提示“You need to sign in or sign up before continuing.”,控制台返回401 Unauthorized
  • 访问/admin/login可正常完成登录,但无法登出并跳转回登录页面

相关配置代码

路由文件 routes.rb

# frozen_string_literal: true

Rails.application.routes.draw do
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)

  resources :categories do
    resources :products, shallow: true
  end
  resources :orders
  resources :line_items
  resources :carts
  root 'store#index', as: 'store_index'
  devise_for :users, path: 'api/auth', path_names: {
                                         sign_in: 'login',
                                         sign_out: 'logout',
                                         registration: 'signup'
                                       },
                     controllers: {
                       sessions: 'users/sessions',
                       registrations: 'users/registrations'
                     }

  get '/current_user', to: 'current_user#index'
  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
  match '*unmatched_route', via: :all, to: 'store#index', constraints: lambda { |request|
                                                                         request.path.exclude? 'rails/active_storage'
                                                                       }
end

应用配置文件 application.rb

# frozen_string_literal: true

require_relative 'boot'

require 'rails'
# Pick the frameworks you want:
require 'active_model/railtie'
require 'active_job/railtie'
require 'active_record/railtie'
require 'active_storage/engine'
require 'action_controller/railtie'
require 'action_mailer/railtie'
require 'action_mailbox/engine'
require 'action_text/engine'
require 'action_view/railtie'
require 'action_cable/engine'
require 'sprockets/railtie'
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module DepotApi
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 6.1

    # Configuration for the application, engines, and railties goes here.
    #
    # These settings can be overridden in specific environments using the files
    # in config/environments, which are processed later.
    #
    # config.time_zone = "Central Time (US & Canada)"
    config.eager_load_paths << Rails.root.join('lib')

    # Only loads a smaller set of middleware suitable for API only apps.
    # Middleware like session, flash, cookies can be added back manually.
    # Skip views, helpers and assets when generating a new resource.
    config.api_only = true
    config.app_generators.scaffold_controller = :scaffold_controller

    # Middleware for ActiveAdmin
    config.middleware.use Rack::MethodOverride
    config.middleware.use ActionDispatch::Flash
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore
  end
end

应用控制器 applicationController.rb(初始版本)

# frozen_string_literal: true

class ApplicationController < ActionController::Base
  skip_before_action :verify_authenticity_token
  before_action :configure_permitted_parameters, if: :devise_controller?

  rescue_from CanCan::AccessDenied do |_exception|
    render json: { error: 'Access denied' }, status: :forbidden
  end

  def authenticate_admin_user!
   redirect_to new_admin_user_session_path
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: %i[user_name role])
    devise_parameter_sanitizer.permit(:sign_in, keys: %i[user_name role])
  end
end

更新后的 authenticate_admin_user! 方法

def authenticate_admin_user!
  if admin_user_signed_in?
    admin_root_path
  else
    new_admin_user_session_path
  end
end

补充说明

  • 其他控制器均继承自 class ApiController < ActionController::API end
  • 未修改 config/initializer/active_admin.rb
  • 控制台日志:
Started GET "/admin" for ::1 at 2023-07-14 02:01:10 +0300
Processing by Admin::DashboardController#index as HTML
Completed 401 Unauthorized in 11ms (ActiveRecord: 0.0ms | Allocations: 282)

解决方案

问题1:访问/admin提示未登录且返回401

自定义的authenticate_admin_user!逻辑错误,ActiveAdmin依赖该方法完成鉴权,但当前实现要么强制跳转(初始版本),要么仅返回路径不执行跳转(更新版本),均未正确完成鉴权流程。

替换为正确的鉴权逻辑:

def authenticate_admin_user!
  unless admin_user_signed_in?
    redirect_to new_admin_user_session_path, alert: '请先登录管理员账户'
  end
end

同时确认config/initializers/active_admin.rb保留默认认证配置(无需修改):

config.authentication_method = :authenticate_admin_user!
config.current_user_method = :current_admin_user

问题2:登录后无法登出跳转

登出失败多由API模式下中间件顺序错误、路由覆盖或Devise登出方法不匹配导致,按以下步骤修复:

  1. 调整中间件顺序:
    在application.rb中,将Cookie和Session中间件移至Flash之前,确保会话数据正确存储:
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
config.middleware.use ActionDispatch::Flash
config.middleware.use Rack::MethodOverride
  1. 修正Devise登出请求方法:
    ActiveAdmin默认用DELETE方法登出,若浏览器或前端发送GET请求会失败。可修改config/initializers/devise.rb允许GET请求登出:
config.sign_out_via = :get
  1. 避免路由覆盖:
    调整末尾通配符路由的约束,排除admin路径,防止覆盖ActiveAdmin的登出路由:
match '*unmatched_route', via: :all, to: 'store#index', constraints: lambda { |request|
  request.path.exclude?('rails/active_storage') && request.path.exclude?('admin')
}

验证步骤

  1. 重启Rails服务器
  2. 访问/admin/login登录管理员账户
  3. 访问/admin,确认可正常进入仪表盘
  4. 点击登出按钮,确认可成功跳转回/admin/login页面

内容的提问来源于stack exchange,提问作者mutebi godfrey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:12:02