从 HttpContext.User.Claims 中提取值

Posted

技术标签:

【中文标题】从 HttpContext.User.Claims 中提取值【英文标题】:Extract values from HttpContext.User.Claims 【发布时间】:2018-10-11 18:09:05 【问题描述】:

我正在尝试从 HttpContext.User.Claims 中提取电子邮件地址,我想寻求帮助以找到更好的编码方式(也许使用 LINQ?)

我现在的做法似乎很老套。

var userClaimsList = HttpContext.User.Claims.ToList();

// List is of varying length but email is always 3rd from the bottom.
int emailPosition = userClaimsList.Count()-3; 
string searchString = "preferred_username: "; 

// dirtyEmail = "preferred_username: xyz@emailcom"
string dirtyEmail = userClaimsList[emailPosition].ToString();
string cleanEmail = dirtyEmail.Replace(searchString, "").ToLower().Trim();

我已尝试推荐的 LINQ 解决方案 in another post,但收到错误 Operator == cannot be applied to operands of type 'Claim' and 'string'

【问题讨论】:

“但电子邮件总是倒数第三”——这是一个非常危险的假设。声明由声明类型标识,因此如果您正在查找电子邮件地址,则该声明很可能具有您应该查询的特定声明类型。所以用它来获得价值,例如使用HttpContext.User.FindFirstValue(emailClaimType) 另请注意,声明列表是Claim 对象的列表,而不是字符串。因此,您执行ToString() 会将它们转换为可能包含较少信息的字符串。您应该直接使用实际的声明对象。 是的,我知道。我讨厌做出这样的假设,这也是我发布这个问题的部分原因。 【参考方案1】:

Claim 对象不仅仅是一个简单的字符串,您在userClaimsList 中看到的是这些声明对象的列表。

声明主要是 claim type 和 claim value 的对,当您查找有关用户的某些信息时,您应该使用声明类型来标识您正在查找的用户属性。

您在代码中所做的是假设您正在寻找的声明是倒数第三个,这本身就已经是一个危险的假设,因为您无法确定这将是始终案例:索赔通常被认为是无序的,您应该按类型查找它们。一旦你得到了类型,你就可以.ToString() 它,这基本上将Claim 类型的所有信息缩减为claimType: claimValue 格式的单个字符串。您可以使用它,但是当对象本身作为访问声明值的更好方式时,它确实效率低下。

由于您正在寻找前缀"preferred_username: ",我假设preferred_username 是您正在寻找的声明类型。在这种情况下,您可以像这样查找该声明:

var claim = HttpContext.User.Claims.First(c => c.Type == "preferred_username");
var emailAddress = claim.Value;

如果未找到具有该类型的声明,则使用 First 将引发异常。如果你不想这样,你可以使用FirstOrDefault,然后检查claim是否是null

还有一些帮助扩展可以让您直接提取声明。在这种情况下,您可以在用户上使用FindFirstValue 直接获取声明值:

var emailAddress = HttpContext.User.FindFirstValue("preferred_username");

如果找不到该类型的声明,FindFirstValue 将返回 null,因此在这种情况下 emailAddress 可能是 null

【讨论】:

感谢您的教育和示例。 @CamiloTerevinto 我假设这样的声明始终存在(因此使用 First 否则会抛出)。我现在编辑了一些更多的细节。谢谢! AFAIK,没有“必需”声明,“preferred_username”当然不是其中之一。不仅如此,类型的格式也因创建它们而异(例如,ASP.NET 使用 System.Security.Claims.ClaimTypes 类创建它们)。 @CamiloTerevinto 当然,只有将声明添加到身份中时,声明才存在。但是如何处理他们的缺席取决于取决于他们的调用代码。如果 OP 处于必须存在该类型声明才能继续的环境中,则在不存在异常时抛出异常将是可接受的反应。但这不是我们的决定:)【参考方案2】:

您所做的不仅是假设您无法确保的事情,而且比需要的要困难得多:

// note: HttpContext.User == User
var cleanEmail = User.FindFirst(ClaimTypes.Email)?.Value;

如果数据不在email 声明类型上,请检查相应的类型并改用它。在你的情况下,它似乎应该是preferred_username:

var cleanEmail = User.FindFirst("preferred_username")?.Value;

【讨论】:

以上是关于从 HttpContext.User.Claims 中提取值的主要内容,如果未能解决你的问题,请参考以下文章

代码记录

如何从 jwt 令牌中获取用户 ID?

从 NIB 与从代码加载自定义滑块:从代码加载时不存在子视图

如何从其他面板从 JTextField 获取输入

从PRISM开始学WPFMVVMViewModel?

在 python 中,为啥从数组读取比从列表读取慢?