ABP - 当前用户 [ICurrentUser、CurrentUser]

当前用户(Current User)

核心辅助类

  • ICurrentUser:获取当前登录用户信息(ID、用户名、角色等)。
  • CurrentUser:静态快捷访问(需在请求上下文内)。

在ABP框架中,ICurrentUserCurrentUser用于获取当前登录用户的信息(如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;

    // 构造函数注入ICurrentUser
    public 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:静态快捷访问器

CurrentUserICurrentUser的静态封装,提供更简洁的语法(无需注入),但仅能在请求上下文内使用(如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.IdCurrentUser.UserName等访问,代码更简洁。

  • 使用限制:

    • 仅能在有用户上下文的场景中使用(如HTTP请求、已认证的后台作业)。
    • 非请求上下文(如应用启动时、无用户的后台任务)中使用会抛异常(CurrentUser内部会检查上下文是否存在)。
  • 本质CurrentUser内部通过IHttpContextAccessorICurrentUser获取用户信息,是对ICurrentUser的静态代理,功能完全一致。

关键区别与使用建议

特性 ICurrentUser(接口) CurrentUser(静态类)
使用方式 需通过依赖注入(构造函数参数) 直接静态访问(CurrentUser.XXX
适用场景 所有场景(包括无HTTP上下文的后台任务) 仅请求上下文内(如Controller、ApplicationService)
灵活性 高(支持单元测试时Mock) 低(静态方法难以Mock,测试复杂度高)
代码可读性 依赖关系明确(构造函数可见) 依赖关系隐藏(静态调用不直观)

最佳实践

  1. 优先使用ICurrentUser:尤其是在服务层(ApplicationService)、领域层,通过依赖注入使用,便于单元测试(可通过Mock<ICurrentUser>模拟用户上下文)。
  2. 有限使用CurrentUser:仅在Controller等请求上下文明确的场景中使用,简化代码(如快速获取用户ID用于日志记录)。
  3. 多租户场景注意ICurrentUser.TenantId可直接获取当前租户ID,结合多租户过滤器实现数据隔离(如查询时自动过滤当前租户的数据)。
  4. 未登录处理:使用前需检查IsAuthenticated,避免未登录时访问Id等属性导致NullReferenceException

通过ICurrentUserCurrentUser,ABP框架为开发者提供了统一的用户上下文访问方式,无需关心底层认证机制(如JWT、Cookie),大幅简化了与用户相关的业务逻辑实现。

posted @ 2025-10-24 20:36  【唐】三三  阅读(39)  评论(0)    收藏  举报