项目

当前用户

在Web应用程序中获取已登录用户信息是非常常见的需求。当前用户指的是Web应用中与当前请求相关联的活跃用户。

ICurrentUser服务

ICurrentUser是获取当前活跃用户信息的主要服务。

示例:将ICurrentUser注入到服务中:

using System;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Users;

namespace AbpDemo
{
    public class MyService : ITransientDependency
    {
        private readonly ICurrentUser _currentUser;

        public MyService(ICurrentUser currentUser)
        {
            _currentUser = currentUser;
        }
        
        public void Foo()
        {
            Guid? userId = _currentUser.Id;
        }
    }
}

常用基类已经将该服务作为基础属性注入。例如,您可以在应用服务中直接使用CurrentUser属性:

using System;
using Volo.Abp.Application.Services;

namespace AbpDemo
{
    public class MyAppService : ApplicationService
    {
        public void Foo()
        {
            Guid? userId = CurrentUser.Id;
        }
    }
}

属性

以下是ICurrentUser接口的基础属性:

  • IsAuthenticated (bool): 如果当前用户已登录(已认证)则返回true。如果用户未登录,则IdUserName将返回null
  • Id (Guid?): 当前用户的ID。如果用户未登录则返回null
  • UserName (string): 当前用户的用户名。如果用户未登录则返回null
  • TenantId (Guid?): 当前用户的租户ID,这对于 多租户 应用很有用。如果用户未分配租户则返回null
  • Email (string): 当前用户的邮箱地址。如果用户未登录或未设置邮箱则返回null
  • EmailVerified (bool): 如果当前用户的邮箱地址已验证则返回true
  • PhoneNumber (string): 当前用户的电话号码。如果用户未登录或未设置电话号码则返回null
  • PhoneNumberVerified (bool): 如果当前用户的电话号码已验证则返回true
  • Roles (string[]): 当前用户的角色。返回当前用户角色名称的字符串数组

方法

ICurrentUser基于ICurrentPrincipalAccessor实现(参见下文),并通过声明(claims)工作。因此,上述所有属性实际上都是从当前认证用户的声明中获取的。

如果您有自定义声明或需要获取其他非标准声明类型,ICurrentUser提供了一些直接操作声明的方法:

  • FindClaim: 获取指定名称的声明。如果未找到则返回null
  • FindClaims: 获取所有指定名称的声明(允许存在多个同名声明值)
  • GetAllClaims: 获取所有声明
  • IsInRole: 检查当前用户是否属于指定角色的快捷方法

除了这些标准方法外,还有一些扩展方法:

  • FindClaimValue: 获取指定名称声明的值,如果未找到则返回null。它还有一个泛型重载,可以将值转换为特定类型
  • GetId: 返回当前用户的ID。如果用户未登录,该方法会抛出异常(而不是返回null)。仅在确定用户已认证的情况下使用此方法

认证与授权

ICurrentUser的工作方式与用户认证或授权方式无关。它可以与任何基于当前主体(principal)工作的认证系统无缝协作(参见下文)。

ICurrentPrincipalAccessor

ICurrentPrincipalAccessor是当需要获取当前用户主体时应由ABP框架和应用程序代码使用的服务。

对于Web应用程序,它获取当前HttpContextUser属性。对于非Web应用程序,它返回Thread.CurrentPrincipal

通常您不需要使用这个底层的ICurrentPrincipalAccessor服务,直接使用上文介绍的ICurrentUser即可。

基本用法

您可以注入ICurrentPrincipalAccessor并使用Principal属性获取当前主体:

public class MyService : ITransientDependency
{
    private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;

    public MyService(ICurrentPrincipalAccessor currentPrincipalAccessor)
    {
        _currentPrincipalAccessor = currentPrincipalAccessor;
    }
    
    public void Foo()
    {
        var allClaims = _currentPrincipalAccessor.Principal.Claims.ToList();
        //...
    }
}

更改当前主体

除非在高级场景中,否则通常不需要设置或更改当前主体。如果需要,可以使用ICurrentPrincipalAccessorChange方法。该方法接受一个ClaimsPrincipal对象,并在某个范围内将其设置为"当前"主体。

示例:

public class MyAppService : ApplicationService
{
    private readonly ICurrentPrincipalAccessor _currentPrincipalAccessor;

    public MyAppService(ICurrentPrincipalAccessor currentPrincipalAccessor)
    {
        _currentPrincipalAccessor = currentPrincipalAccessor;
    }

    public void Foo()
    {
        var newPrincipal = new ClaimsPrincipal(
            new ClaimsIdentity(
                new Claim[]
                {
                    new Claim(AbpClaimTypes.UserId, Guid.NewGuid().ToString()),
                    new Claim(AbpClaimTypes.UserName, "john"),
                    new Claim("Claim", "42")
                }
            )
        );

        using (_currentPrincipalAccessor.Change(newPrincipal))
        {
            var userName = CurrentUser.UserName; //返回"john"
            //...
        }
    }
}

请始终在using语句中使用Change方法,这样在using作用域结束后会自动恢复原始值。

这可以作为一种在应用程序代码范围内模拟用户登录的方法,但请谨慎使用。

AbpClaimTypes

AbpClaimTypes是一个静态类,定义了ABP框架使用的标准声明名称:

  • UserNameUserIdRoleEmail属性的默认值来自System.Security.Claims.ClaimTypes类,但您可以更改它们
  • 其他属性,如EmailVerifiedPhoneNumberTenantId等,由ABP框架定义,尽可能遵循标准命名规范

建议使用此类的属性而不是魔术字符串来表示声明名称。

在本文档中