从 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 中提取值的主要内容,如果未能解决你的问题,请参考以下文章