ASP.NET (OWIN) Identity:如何从 Web API 控制器获取 UserID?

Posted

技术标签:

【中文标题】ASP.NET (OWIN) Identity:如何从 Web API 控制器获取 UserID?【英文标题】:ASP.NET (OWIN) Identity: How to get UserID from a Web API controller? 【发布时间】:2013-10-30 14:16:30 【问题描述】:

(使用VS2013 RTW,ASP.NET MVC5)

我看过很多关于如何在使用 ASP.NET 标识时向 ApplicationUser 类(和表)添加属性的文档。但是我还没有看到任何关于如何拥有一个单独的表的文档,该表的内容通过外键映射到 ApplicationUser 表。

我已经成功地派生了我自己的 Microsoft.AspNet.Identity.EntityFramework.IdentityDbContext,现在我自己的“UserPreferences”表与我的 SQL Server 数据库中的各种“AspNet*”表和谐共存。但我不清楚获取当前用户 ID 以便将新行写入“UserPreferences”表的最佳方法。请注意,该项目是 ASP.NET MVC,但我已经添加(并且正在其中工作)一个 Web API 控制器。

我有一个可行的解决方案,即:

            var uman = new Microsoft.AspNet.Identity.UserManager<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new Microsoft.AspNet.Identity.EntityFramework.UserStore<Microsoft.AspNet.Identity.EntityFramework.IdentityUser>(new App1.Data.App1DbContext()));

            var uident = User.Identity;

            var userobject = uman.FindByNameAsync(uident.Name);

            var userid = userobject.Result.Id;
            // (Perform new row creation including the userid we just looked up

考虑 AspNetUsers 表(由 Identity 框架定义)由以下字段组成:

-id (PK, nvarchar(128) - seems to contain a GUID, not sure why not an autoincrement integer, but I assume there are reasons for this)
-Username (nvarchar(max))
-PasswordHash (nvarchar(max))
-SecurityStamp (nvarchar(max))

我认为 id 字段(不是用户名)是此表中要引用的正确字段。 (我在想一个用户可能会更改他/她的用户名,然后其他人可以假设另一个用户的用户名,这就是为什么两个字段都可能存在的原因。)那么,我需要获取当前用户的 ID 以存储在“UserPreferences”表,这就是上面的代码所做的。但是必须进行此查找似乎效率低下。

重要的一点是,在 System.Web.Mvc.Controller 的上下文中,我可以这样做:

User.Identity.GetUserId()
(Runtime type of User.Identity: System.Security.Principal.GenericIdentity)

但是在 System.Web.Http.ApiController (Web API) 的上下文中,我不能,因为该方法不存在(User.Identity 的运行时类型:System.Security.Claims.ClaimsIdentity),这就是为什么我必须而是依靠:

User.Identity.Name

并进行额外的查找以将名称转换为 ID。有人对如何改进有任何建议吗?我是否正在以正确的方式将用户数据写入单独的表?

【问题讨论】:

注意:根据这篇文章:***.com/questions/9768872/…“ApiController 有一个 System.Net.Http.HttpRequestMessage 类型的 Request 属性;这自然包含有关当前请求的详细信息(它还有一个 setter for unit测试目的)。HttpRequestMessage 有一个 Properties 字典;你会发现键 MS_UserPrincipal 的值保存了你的 IPrincipal 对象。但是“MS_UserPrincipal”不存在。我可以在字典的其他地方找到主体,但它返回与上面相同的对象,但不包含 ID... 【参考方案1】:

尝试了@Mastenka 的答案,但它什么也没给我。我检查了 ClaimsIdentity 并且有 声明类型“用户名”,因此,我通过使用“用户名”作为声明类型来获取用户名。 希望有人能提供更多有关它的信息。 “ClaimTypes.NameIdentifier”没有效果看起来很奇怪。 (ApiController, ASP MVC API)

var userName = ((ClaimsIdentity)RequestContext.Principal.Identity).Claims.FirstOrDefault(cl => cl.Type == "UserName")?.Value;

【讨论】:

【参考方案2】:
ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Name, userName));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, UserID));

ClaimTypes.NameIdentifier 是函数 User.Identity.GetUserId() 的声明

【讨论】:

在授权用户时添加此声明可以使用 User.Identity.GetUserId()。这是最简单的解决方案。 问题是如何检索您在案例中使用的用户 ID? @ShA.t:有什么想法吗?【参考方案3】:

最佳答案的简短描述:

    Install-Package Microsoft.AspNet.Identity.Core -Version 2.2.1 var userId = User.Identity.GetUserId();

【讨论】:

【参考方案4】:

我正在使用基于声明的方法:

private ApplicationUser GetCurrentUser(ApplicationDbContext context)

  var identity = User.Identity as ClaimsIdentity;
  Claim identityClaim = identity.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier);

  return context.Users.FirstOrDefault(u => u.Id == identityClaim.Value);

【讨论】:

【参考方案5】:

您应该能够通过identity 1.0 RTW package 中的相同扩展方法在 MVC 控制器和 Web api 控制器上获取用户 ID。

这是来自身份包的扩展:

namespace Microsoft.AspNet.Identity

    public static class IdentityExtensions
    
        public static string FindFirstValue(this ClaimsIdentity identity, string claimType);
        public static string GetUserId(this IIdentity identity);
        public static string GetUserName(this IIdentity identity);
    

IIdentity 是所有身份类型的基本接口。您可能需要添加“使用 Microsoft.AspNet.Identity”才能看到扩展方法。

顺便说一句:关于为用户添加外部表,为什么不使用 ApplicationUser 并将导航属性添加到 UserPreference 以让 EF 处理它们的关系?这样会更容易。

【讨论】:

感谢宏业,那个扩展方法正是我所需要的! > 为什么不使用 ApplicationUser 并将导航属性添加到 UserPreference 以让 EF 处理它们的关系?那就是能够从用户导航到用户偏好,对吧?这是个好主意。我会去做。另外,我将 GUID(很长)存储为外键值是不好的做法吗?示例:307b5c04-254a-4c56-b2bb-a87185883ae7。我习惯只存储一个整数值。这将在数​​据库中占用更多空间。 请注意,您可能需要强制转换才能使用 FindFirstValue:例如 ((ClaimsIdentity)User.Identity).FindFirstValue("FirstName")

以上是关于ASP.NET (OWIN) Identity:如何从 Web API 控制器获取 UserID?的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Identity 2.0 解密 Owin cookie

MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN

如何更新 ASP.NET Identity 中的声明?

OWIN产生的背景以及简单介绍

使用 OWIN 在 ASP.NET MVC 5 应用程序中存储和检索 facebook 访问令牌

使用asp.net 5时如何更改登录网址