当前位置: 首页 > news >正文

ABP - 接口授权 [Authorize、AllowAnonymous、IPermissionChecker]

接口授权(Authorization)

核心辅助类

  • [Authorize]:标记需要授权的接口。
  • [AllowAnonymous]:允许匿名访问。
  • IPermissionChecker:手动检查权限。

接口授权(Authorization)核心类示例与讲解

接口授权是在“身份认证(如JWT)”基础上,进一步控制“谁能访问哪些接口”的机制(比如“普通用户只能查看自己的订单,管理员能查看所有订单”)。ABP通过[Authorize][AllowAnonymous]IPermissionChecker实现灵活的授权控制,以下结合实例详解。

一、核心概念:授权的3种常见场景

  1. 身份授权:只有登录用户才能访问(排除匿名用户);
  2. 角色授权:只有特定角色(如Admin)的用户才能访问;
  3. 权限授权:只有拥有特定权限(如Order.Delete)的用户才能访问(ABP推荐,更灵活)。

二、核心类/特性说明

类/特性 作用 适用场景
[Authorize] 标记接口需要授权才能访问 限制匿名访问,或结合角色/权限控制
[AllowAnonymous] 允许匿名访问(忽略[Authorize] 公开接口(如登录、注册)
IPermissionChecker 手动检查权限(代码中动态判断) 复杂授权逻辑(如“只能修改自己创建的数据”)

三、实操示例:从基础到进阶

1. 基础授权:禁止匿名访问([Authorize])

最简单的授权是“只有登录用户能访问”,用[Authorize]标记接口即可,未登录用户会被拒绝(返回401错误)。

示例:登录用户才能访问个人中心

using Microsoft.AspNetCore.Authorization;
using Volo.Abp.Application.Services;// 整个服务类的所有方法都需要授权(登录才能访问)
[Authorize]
public class UserProfileAppService : ApplicationService
{// 1. 查看个人信息(继承类的[Authorize],无需重复标记)public async Task<ProfileDto> GetMyProfileAsync(){// 通过CurrentUser获取当前登录用户IDvar userId = CurrentUser.Id;// 查询用户信息并返回...}// 2. 编辑个人信息(同样需要登录)public async Task UpdateMyProfileAsync(UpdateProfileInput input){var userId = CurrentUser.Id;// 编辑逻辑...}
}// 对比:公开接口(允许匿名访问)
public class PublicAppService : ApplicationService
{// 登录接口必须允许匿名访问,否则用户无法登录[AllowAnonymous]public async Task<LoginResultDto> LoginAsync(LoginInput input){// 登录逻辑...}
}

2. 角色授权:限制特定角色访问

通过[Authorize(Roles = "角色名")]限制只有指定角色的用户才能访问(如Admin角色)。

示例:只有管理员能访问用户管理接口

// 只有Admin角色能访问这个服务的所有方法
[Authorize(Roles = "Admin")]
public class UserManagementAppService : ApplicationService
{// 1. 查看所有用户(仅Admin可访问)public async Task<List<UserDto>> GetAllUsersAsync(){// 查询所有用户逻辑...}// 2. 删除用户(仅Admin可访问)public async Task DeleteUserAsync(Guid userId){// 删除逻辑...}
}// 进阶:多角色授权(Admin或Manager均可访问)
[Authorize(Roles = "Admin,Manager")]
public class OrderManagementAppService : ApplicationService
{// 查看所有订单(Admin或Manager角色可访问)public async Task<List<OrderDto>> GetAllOrdersAsync(){// 逻辑...}
}

3. 权限授权:ABP推荐的灵活方式(重点)

ABP的权限系统比角色更灵活(一个角色可包含多个权限,一个用户可拥有多个角色),通过[Authorize(Policy = "权限名")]控制访问。

步骤1:定义权限(在模块中)

首先在领域模块(如MyAppDomainModule)中定义权限:

using Volo.Abp.Authorization.Permissions;
using Volo.Abp.Modularity;public class MyAppDomainModule : AbpModule
{public override void ConfigureServices(ServiceConfigurationContext context){// 配置权限Configure<AbpPermissionOptions>(options =>{// 1. 定义权限组(如“订单管理”)options.DefinePermissionGroup("OrderManagement");// 2. 在组内定义具体权限options.Define("Order.Create", // 权限名(唯一标识)displayName: "创建订单", // 显示名(UI中展示)description: "允许创建新订单", // 描述groupName: "OrderManagement" // 所属组);options.Define("Order.Delete", displayName: "删除订单", description: "允许删除订单", groupName: "OrderManagement");});}
}

步骤2:给角色分配权限(种子数据中)

在种子数据中给Admin角色分配Order.Delete权限(普通用户不给):

[Dependency(ServiceLifetime.Transient)]
public class PermissionSeedData : IDataSeeder
{private readonly IPermissionManager _permissionManager;private readonly IRepository<IdentityRole, Guid> _roleRepo;private readonly IIdentityRoleManager _roleManager;public PermissionSeedData(IPermissionManager permissionManager,IRepository<IdentityRole, Guid> roleRepo,IIdentityRoleManager roleManager){_permissionManager = permissionManager;_roleRepo = roleRepo;_roleManager = roleManager;}public async Task SeedAsync(DataSeedContext context){// 给Admin角色分配Order.Delete权限var adminRole = await _roleRepo.FirstOrDefaultAsync(r => r.Name == "Admin");if (adminRole != null){await _roleManager.AddPermissionAsync(adminRole, "Order.Delete");}}
}

步骤3:用权限控制接口访问

public class OrderAppService : ApplicationService
{// 1. 创建订单:所有登录用户都能访问(需要Order.Create权限)[Authorize(Policy = "Order.Create")]public async Task<OrderDto> CreateOrderAsync(CreateOrderInput input){// 创建逻辑...}// 2. 删除订单:只有拥有Order.Delete权限的用户能访问(如Admin)[Authorize(Policy = "Order.Delete")]public async Task DeleteOrderAsync(Guid orderId){// 删除逻辑...}// 3. 查看自己的订单:登录用户即可(无需特定权限,但需过滤数据)[Authorize]public async Task<List<OrderDto>> GetMyOrdersAsync(){var userId = CurrentUser.Id;// 只查询当前用户的订单var orders = await _orderRepo.GetListAsync(o => o.CreatorId == userId);return ObjectMapper.Map<List<Order>, List<OrderDto>>(orders);}
}

4. 手动检查权限(IPermissionChecker)

复杂场景下(如“根据订单金额动态判断是否有权限删除”),需在代码中手动检查权限,使用IPermissionChecker

示例:订单金额大于1000时,需要特殊权限才能删除

public class OrderAppService : ApplicationService
{private readonly IPermissionChecker _permissionChecker; // 手动权限检查工具private readonly IRepository<Order, Guid> _orderRepo;public OrderAppService(IPermissionChecker permissionChecker,IRepository<Order, Guid> orderRepo){_permissionChecker = permissionChecker;_orderRepo = orderRepo;}[Authorize] // 至少需要登录public async Task DeleteOrderAsync(Guid orderId){var order = await _orderRepo.GetAsync(orderId);// 1. 基础检查:是否是自己的订单(数据隔离)if (order.CreatorId != CurrentUser.Id){throw new UserFriendlyException("不能删除他人的订单!");}// 2. 动态权限检查:金额>1000需要Order.Delete.High权限if (order.TotalAmount > 1000){// 手动检查是否有Order.Delete.High权限var hasHighPermission = await _permissionChecker.IsGrantedAsync("Order.Delete.High");if (!hasHighPermission){throw new UserFriendlyException("您没有权限删除金额大于1000的订单!");}}// 3. 执行删除await _orderRepo.DeleteAsync(order);}
}

5. 全局授权与局部匿名([AllowAnonymous]

如果整个服务类需要授权,但个别方法允许匿名访问(如“用户服务”中登录方法允许匿名),可用[AllowAnonymous]覆盖。

// 全局:整个服务需要授权
[Authorize]
public class UserAppService : ApplicationService
{// 例外:登录方法允许匿名访问[AllowAnonymous]public async Task<LoginResultDto> LoginAsync(LoginInput input){// 登录逻辑...}// 其他方法:需要授权(继承类的[Authorize])public async Task<UserDto> GetProfileAsync(){// 逻辑...}
}

四、权限检查的核心原理

  1. 权限存储:ABP将权限信息存在数据库(AbpPermissions表),记录“哪个角色/用户拥有哪个权限”;
  2. 验证时机:当访问[Authorize(Policy = "权限名")]标记的接口时,ABP会自动查询当前用户的权限列表,检查是否包含所需权限;
  3. 未授权处理:若未授权,自动返回403 Forbidden错误,前端可捕获并提示“没有权限”。

五、新手避坑指南

  1. [Authorize][AllowAnonymous]的优先级:方法上的特性优先于类上的(如类标记[Authorize],方法标记[AllowAnonymous],则方法允许匿名);
  2. 权限名拼写错误[Authorize(Policy = "Order.Delete")]中的权限名必须和Define时的完全一致(大小写敏感),否则会一直提示“无权限”;
  3. 角色与权限的选择:优先用权限(更灵活),角色适合简单场景(如“管理员”“普通用户”);
  4. 数据隔离与授权结合:授权控制“能否访问接口”,但接口内部仍需判断“能否操作特定数据”(如“只能修改自己的订单”),避免越权操作。

总结

  • [Authorize]:基础授权,控制“是否需要登录”或“需要特定角色/权限”;
  • [AllowAnonymous]:例外处理,允许公开访问(如登录接口);
  • IPermissionChecker:复杂场景下手动检查权限,支持动态逻辑。

通过这三个工具,可实现从简单到复杂的接口授权控制,确保系统数据安全。需要“前端如何根据权限动态显示按钮”的示例可以告诉我,我会补充前后端联动的实现。

http://www.hskmm.com/?act=detail&tid=38408

相关文章:

  • 日总结 17
  • Luogu P5479 [BJOI2015] 隐身术 题解 [ 紫 ] [ 多维 DP ] [ 交换维度 ] [ 后缀数组 ] [ 哈希 ]
  • 2025年10月23日
  • 杂题选做-3
  • 10.24每日总结
  • 利用Eval Villain挖掘CSPT漏洞的完整指南
  • Button按钮插入图片后仍有白色边框的解决办法
  • Hugo主题的修改和配置
  • 多元生成函数+多项式方程组——[AGC058D] Yet Another ABC String
  • ABP - JWT 鉴权(JWT Authentication)[AbpJwtBearerModule、JwtBearerOptions]
  • 最小生成树 kruskal算法
  • 【Java】Synchronized-你知道Java是如何上锁的吗?
  • Java中的字符串及相关类的介绍
  • ABP - 工作单元(Unit of Work)[UnitOfWorkAttribute、IUnitOfWorkManager、UnitOfWorkOptions]
  • LeetCode刷题笔记
  • [NOIP2023] 双序列拓展 题解
  • 洛谷 P9530 Fish 2
  • 洛谷 P7011 Escape
  • 你可以把它喂给AI让AI猜猜我在干什么
  • 【深入浅出Nodejs】异步非阻塞IO
  • 135. 分发糖果
  • 【Java-JMM】Happens-before原则
  • P6072 『MdOI R1』Path
  • P1601题解
  • 10-23 好题选讲总结
  • 关于驻马店市 2025 中小学信息学竞赛的记录(入门级)(未完)
  • 关于Markdown的使用
  • 自定义Spring Cloud LoadBalancer实践
  • 游记——驻马店市2025中小学信息学竞赛(未完)
  • 线段树上二分