已集成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登出方法不匹配导致,按以下步骤修复:
- 调整中间件顺序:
在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
- 修正Devise登出请求方法:
ActiveAdmin默认用DELETE方法登出,若浏览器或前端发送GET请求会失败。可修改config/initializers/devise.rb允许GET请求登出:
config.sign_out_via = :get
- 避免路由覆盖:
调整末尾通配符路由的约束,排除admin路径,防止覆盖ActiveAdmin的登出路由:
match '*unmatched_route', via: :all, to: 'store#index', constraints: lambda { |request| request.path.exclude?('rails/active_storage') && request.path.exclude?('admin') }
验证步骤
- 重启Rails服务器
- 访问
/admin/login登录管理员账户 - 访问
/admin,确认可正常进入仪表盘 - 点击登出按钮,确认可成功跳转回
/admin/login页面
内容的提问来源于stack exchange,提问作者mutebi godfrey
相关产品推荐
相关产品推荐

