当前用户(Current User)
核心辅助类:
ICurrentUser:获取当前登录用户信息(ID、用户名、角色等)。CurrentUser:静态快捷访问(需在请求上下文内)。
在ABP框架中,ICurrentUser和CurrentUser用于获取当前登录用户的信息(如ID、用户名、角色、权限等),是处理用户上下文的核心工具。它们在业务逻辑中频繁用于权限验证、数据隔离(如多租户场景)、操作审计等场景。
1. ICurrentUser:接口形式的当前用户访问器
ICurrentUser是一个接口,定义了获取当前用户信息的方法和属性,需通过依赖注入使用。它提供了灵活的用户信息访问能力,支持在各种服务中获取当前登录用户的上下文。
示例:通过ICurrentUser获取用户信息
using Volo.Abp.AspNetCore.Mvc;
using Volo.Abp.Identity;public class BookAppService : ApplicationService
{private readonly ICurrentUser _currentUser;private readonly IRepository<Book, Guid> _bookRepository;// 构造函数注入ICurrentUserpublic BookAppService(ICurrentUser currentUser, IRepository<Book, Guid> bookRepository){_currentUser = currentUser;_bookRepository = bookRepository;}public async Task<List<BookDto>> GetMyBooksAsync(){// 检查用户是否已登录if (!_currentUser.IsAuthenticated){throw new UserFriendlyException("请先登录!");}// 获取当前用户ID(Guid类型,多租户场景下自动关联租户)var userId = _currentUser.Id;// 获取当前用户名var userName = _currentUser.UserName;// 检查用户是否属于某个角色(如"Admin")var isAdmin = _currentUser.IsInRole("Admin");// 查询当前用户创建的书籍(数据隔离)var myBooks = await _bookRepository.GetListAsync(book => book.CreatorId == userId);return ObjectMapper.Map<List<Book>, List<BookDto>>(myBooks);}
}
讲解:
-
核心属性:
IsAuthenticated:是否已登录(true表示用户已认证)。Id:当前用户的唯一标识(Guid?类型,未登录时为null)。UserName:用户名(未登录时为null)。Email/PhoneNumber:用户的邮箱、手机号等基础信息。Roles:用户所属的角色集合(IReadOnlyList<string>)。TenantId:多租户场景下的当前租户ID(与用户关联)。
-
核心方法:
IsInRole(string roleName):检查用户是否属于指定角色。FindClaim(string claimType):获取用户的指定声明(如自定义权限声明)。
-
依赖注入:
ICurrentUser需通过构造函数注入使用,框架会自动提供当前请求的用户上下文(HTTP请求、后台任务等场景均支持)。
2. CurrentUser:静态快捷访问器
CurrentUser是ICurrentUser的静态封装,提供更简洁的语法(无需注入),但仅能在请求上下文内使用(如HTTP请求处理过程中)。
示例:通过CurrentUser静态类获取用户信息
public class BookController : AbpController
{private readonly IRepository<Book, Guid> _bookRepository;public BookController(IRepository<Book, Guid> bookRepository){_bookRepository = bookRepository;}[HttpPost]public async Task<IActionResult> Create(CreateBookDto input){// 静态访问当前用户ID(等价于注入ICurrentUser后访问其Id)var creatorId = CurrentUser.Id;// 静态检查是否为管理员if (!CurrentUser.IsInRole("Admin") && input.Price > 1000){return BadRequest("普通用户无法创建价格超过1000的书籍!");}var book = new Book{Name = input.Name,Price = input.Price,CreatorId = creatorId // 记录创建人};await _bookRepository.InsertAsync(book);return Ok(book.Id);}
}
讲解:
-
语法简化:
CurrentUser是静态类,无需在构造函数中注入,直接通过CurrentUser.Id、CurrentUser.UserName等访问,代码更简洁。 -
使用限制:
- 仅能在有用户上下文的场景中使用(如HTTP请求、已认证的后台作业)。
- 非请求上下文(如应用启动时、无用户的后台任务)中使用会抛异常(
CurrentUser内部会检查上下文是否存在)。
-
本质:
CurrentUser内部通过IHttpContextAccessor或ICurrentUser获取用户信息,是对ICurrentUser的静态代理,功能完全一致。
关键区别与使用建议
| 特性 | ICurrentUser(接口) |
CurrentUser(静态类) |
|---|---|---|
| 使用方式 | 需通过依赖注入(构造函数参数) | 直接静态访问(CurrentUser.XXX) |
| 适用场景 | 所有场景(包括无HTTP上下文的后台任务) | 仅请求上下文内(如Controller、ApplicationService) |
| 灵活性 | 高(支持单元测试时Mock) | 低(静态方法难以Mock,测试复杂度高) |
| 代码可读性 | 依赖关系明确(构造函数可见) | 依赖关系隐藏(静态调用不直观) |
最佳实践
- 优先使用
ICurrentUser:尤其是在服务层(ApplicationService)、领域层,通过依赖注入使用,便于单元测试(可通过Mock<ICurrentUser>模拟用户上下文)。 - 有限使用
CurrentUser:仅在Controller等请求上下文明确的场景中使用,简化代码(如快速获取用户ID用于日志记录)。 - 多租户场景注意:
ICurrentUser.TenantId可直接获取当前租户ID,结合多租户过滤器实现数据隔离(如查询时自动过滤当前租户的数据)。 - 未登录处理:使用前需检查
IsAuthenticated,避免未登录时访问Id等属性导致NullReferenceException。
通过ICurrentUser和CurrentUser,ABP框架为开发者提供了统一的用户上下文访问方式,无需关心底层认证机制(如JWT、Cookie),大幅简化了与用户相关的业务逻辑实现。
