如何在.NET Core 3.1 Web API控制器中获取Claims声明
ASP.NET Core 3.1 Web API 提取Token中Claims的实现方式及最佳实践
控制器内直接读取的实现方法
你已经在全局配置了要求用户认证、必须携带email声明的授权策略,所有能进入接口方法的请求,都已经过身份校验且必然包含合法的邮箱声明,直接通过控制器基类自带的User属性(类型为ClaimsPrincipal)就能读取声明值:
[Route("[controller]")] public class UserController : ControllerBase { [HttpGet] public IActionResult Get() { // 读取email声明值 var userEmail = User.FindFirstValue("email"); // 如果遇到声明名映射导致读不到值的情况,可以替换为以下两种写法兼容: // var userEmail = User.FindFirstValue(ClaimTypes.Email); // var userEmail = User.FindFirstValue("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"); // 用拿到的邮箱查数据库、返回用户信息 // var userInfo = _userRepository.GetByEmail(userEmail); return Ok(/* 用户信息返回结果 */); } }
FindFirstValue是身份组件提供的扩展方法,可以直接获取对应声明的Value,比手动写FindFirst(xxx)?.Value更简洁。
实践建议
- 抽离公共声明读取逻辑,不要在每个接口重复写读取代码
可以写一个ClaimsPrincipal的扩展类统一封装声明读取逻辑,避免魔法字符串散落在项目各处,后续如果声明规则调整,只需要改这一处代码:
后续在控制器里直接调用public static class ClaimsPrincipalExtensions { public static string GetCurrentUserEmail(this ClaimsPrincipal user) { if (user == null) throw new ArgumentNullException(nameof(user)); // 兼容不同身份提供商的声明格式,依次匹配 return user.FindFirstValue("email") ?? user.FindFirstValue(ClaimTypes.Email) ?? throw new UnauthorizedAccessException("当前身份缺少邮箱声明"); } }User.GetCurrentUserEmail()就能拿到邮箱,非常方便。 - 非控制器层获取声明统一用
IHttpContextAccessor
如果需要在服务层、仓储层等非控制器类里读取用户声明,不要把控制器的User对象往下传,先在服务注册时添加services.AddHttpContextAccessor();,之后在自定义服务里注入IHttpContextAccessor就能拿到HttpContext和对应的用户声明:public class UserBusinessService { private readonly IHttpContextAccessor _contextAccessor; public UserBusinessService(IHttpContextAccessor contextAccessor) { _contextAccessor = contextAccessor; } public UserInfo GetCurrentUser() { var currentUser = _contextAccessor.HttpContext?.User; var email = currentUser?.GetCurrentUserEmail(); // 后续查库逻辑 } } - 所有用户身份标识一律以服务端解析的Claims为准
绝对不要使用前端(你的Angular客户端)通过请求参数、自定义Header传递的用户ID、邮箱作为查询依据,哪怕前端传了对应值也要忽略,完全以服务端从AuthToken解析出来的Claims值为准,避免恶意用户伪造参数越权访问他人数据。 - 授权校验前置,不要在业务层重复做声明存在性判断
你现在全局配置的RequireAuthenticatedUser()+RequireClaim("email")的策略是合理的,没有合法Token、缺少email声明的请求会直接被授权中间件拦截返回401/403,根本进不到业务逻辑,不需要在每个接口里重复判断用户是否认证、有没有email声明。 - 注意声明名映射的兼容问题
微软身份组件默认会对部分身份提供商(比如AAD)返回的声明做名称映射,有时候你在JWT解析工具里看到的声明短名,和服务端User.Claims集合里的实际ClaimType不一致,如果遇到读不到值的情况,先打个断点遍历User.Claims看实际的声明类型和值,再调整读取逻辑即可。 - 不要在Token里存敏感业务数据
Token本身是经过编码但可被解码读取的,只适合存用户ID、邮箱、角色这类用于鉴权的非敏感标识,用户的隐私信息、业务状态数据一律存在数据库,拿到Claims里的用户标识后查库获取即可。
内容的提问来源于stack exchange,提问作者One Developer
相关产品推荐
相关产品推荐

