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

React前端+Rails API后端架构下如何实现权限控制?

Rails API + React 权限控制实现方案

权限控制必须前后端配合实现:前端做体验层控制(隐藏按钮、拦截路由),后端做安全层校验(拦截越权请求),二者缺一不可。以下是几种可行的落地方案:

方案一:适配 CanCanCan 到 API 模式

CanCanCan 并非只能依赖会话,只要能在后端拿到当前用户,就能正常使用。结合 JWT 身份认证即可适配 API 场景:

后端配置

  1. 定义 Ability 权限规则(和普通 Rails 项目一致):
# app/models/ability.rb
class Ability
  include CanCan::Ability

  def initialize(user)
    user ||= User.new # 匿名用户兜底

    if user.admin?
      can :manage, :all
    else
      can :read, Post
      can [:create, :update, :destroy], Post, author_id: user.id
    end
  end
end
  1. 基控制器集成权限校验逻辑:
# app/controllers/api/base_controller.rb
class Api::BaseController < ActionController::API
  include CanCan::ControllerAdditions

  # 捕获权限不足异常,返回标准 API 响应
  rescue_from CanCan::AccessDenied do |exception|
    render json: { error: exception.message }, status: :forbidden
  end

  private

  # 从 JWT 解析当前用户
  def current_user
    return @current_user if defined?(@current_user)
    auth_token = request.headers['Authorization']&.split(' ')&.last
    return nil unless auth_token

    decoded = JWT.decode(auth_token, Rails.application.credentials.jwt_secret, true, algorithm: 'HS256')[0]
    @current_user = User.find_by(id: decoded['user_id'])
  rescue JWT::DecodeError
    nil
  end
end
  1. 业务控制器中使用权限校验:
# app/controllers/api/posts_controller.rb
class Api::PostsController < Api::BaseController
  def update
    @post = Post.find(params[:id])
    authorize! :update, @post # 校验权限,不通过会抛出异常
    if @post.update(post_params)
      render json: @post
    else
      render json: @post.errors, status: :unprocessable_entity
    end
  end
end

前端配合

登录成功后,后端返回用户角色(如 admin/normal),前端将其存入状态管理工具(Redux/Zustand)或 localStorage:

  • 路由拦截:用 React Router 的导航守卫,比如非 admin 用户禁止访问 /admin 路径
  • UI 控制:编辑/删除按钮仅在用户是文章作者或 admin 时显示

方案二:自定义权限校验逻辑(无依赖 gem)

如果项目权限规则简单,无需引入 gem,直接在模型和控制器中写逻辑更灵活:

后端实现

  1. User 模型中定义权限判断方法:
# app/models/user.rb
class User < ApplicationRecord
  def can_modify_post?(post)
    admin? || post.author_id == id
  end

  def can_access_admin_panel?
    admin?
  end
end
  1. 控制器中直接调用校验:
# app/controllers/api/posts_controller.rb
def destroy
  @post = Post.find(params[:id])
  unless current_user.can_modify_post?(@post)
    render json: { error: '无权执行此操作' }, status: :forbidden
    return
  end
  @post.destroy
  head :no_content
end

前端配合

和方案一一致,通过后端返回的用户角色/标识,做路由和 UI 层面的权限控制。

方案三:RBAC 细粒度权限控制(复杂场景)

如果项目有多个角色、多类资源、多维度操作(增删改查),推荐用 RBAC(角色权限控制)模式:

后端实现

  1. 建表:roles(角色表)、permissions(权限表,如 post:create/user:edit)、role_permissions(角色-权限关联)、user_roles(用户-角色关联)
  2. 登录时返回用户的角色和权限列表:
# app/controllers/api/sessions_controller.rb
def create
  user = User.find_by(email: params[:email])
  if user&.authenticate(params[:password])
    permissions = user.roles.joins(:permissions).pluck('permissions.code')
    token = JWT.encode({ user_id: user.id }, Rails.application.credentials.jwt_secret, 'HS256')
    render json: { token: token, roles: user.roles.pluck(:name), permissions: permissions }
  else
    render json: { error: '登录失败' }, status: :unauthorized
  end
end
  1. 控制器中校验权限:
# app/controllers/api/base_controller.rb
def has_permission?(permission_code)
  current_user.permissions.exists?(code: permission_code)
end

# 业务控制器使用
def create
  unless has_permission?('post:create')
    render json: { error: '无权创建文章' }, status: :forbidden
    return
  end
  # 创建逻辑
end

前端配合

将权限列表存入状态管理,在路由和组件中做判断:

  • 路由:比如需要 admin:panel 权限的路由,无权限则跳转到 403 页面
  • 组件:比如删除按钮仅在用户拥有 post:delete 权限时渲染

核心注意事项

  • 后端校验是安全底线:前端的权限控制只是优化用户体验,所有操作必须经过后端校验,防止用户通过修改前端代码或直接发请求越权。
  • 权限同步:如果后端修改了用户权限,前端需要重新获取最新权限(比如刷新页面、后端主动推送),避免权限不一致。

内容的提问来源于stack exchange,提问作者Muhammad Ans

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 22:40:23