ASP.NET(OWIN)身份验证:如何从Web API控制器获取UserID?

48

(使用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。是否有任何建议可以改进这种情况?我是否以正确的方式处理将用户数据写入单独的表的任务?


1
注意:根据此帖子:https://dev59.com/jmkw5IYBdhLWcg3wm70h"ApiController具有类型为System.Net.Http.HttpRequestMessage的Request属性;这自然保存了有关当前请求的详细信息(它还具有用于单元测试目的的setter)。HttpRequestMessage具有Properties字典;您将发现键MS_UserPrincipal的值保存了您的IPrincipal对象。"但是,“MS_UserPrincipal”不存在。我可以在字典的其他地方找到主体,但它返回与上面相同的对象,其中不包括ID... - BenjiFB
5个回答

59

您应该能够通过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是所有身份类型的基本接口。您可能需要添加"use Microsoft.AspNet.Identity"才能查看扩展方法。
顺便说一下:关于为用户添加外部表,为什么不使用ApplicationUser并添加导航属性到UserPreference,让EF处理它们的关系?那会更容易。

1
谢谢Hongye,那个扩展方法正是我所需要的!为什么不使用ApplicationUser并添加导航属性到UserPreference,让EF来处理它们的关系呢?这样就可以从Users导航到UserPreferences了,对吧?这是个好主意。我会这么做的。另外,我将GUID(长字符串)作为外键值存储,这是不是一个不好的实践?例如:307b5c04-254a-4c56-b2bb-a87185883ae7。我习惯只存储整数值。这将占用更多的数据库空间。 - BenjiFB
2
请注意,您可能需要进行强制类型转换才能使用FindFirstValue: 例如((ClaimsIdentity)User.Identity).FindFirstValue("FirstName") - Chris

47
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()的声明。


4
在授权用户时添加此声明可启用使用User.Identity.GetUserId()。这是最简单的解决方案。 - erlando
问题是,如何检索您在案例中使用的UserID? - afaaqa dabookick
@ShA.t:有什么想法吗? - afaaqa dabookick

16

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

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);
}

3

最佳答案的简短描述:

  1. 安装包Microsoft.AspNet.Identity.Core - 版本2.2.1
  2. var userId = User.Identity.GetUserId();

0
尝试了@Mastenka的答案,但没有得到任何结果。我检查了ClaimsIdentity并发现有“UserName”这种声明类型,因此,我使用“UserName”作为ClaimsType来获取用户名。 希望有人能提供更多信息。看起来很奇怪,“ClaimTypes.NameIdentifier”没有效果。(ApiController,ASP MVC API)
var userName = ((ClaimsIdentity)RequestContext.Principal.Identity).Claims.FirstOrDefault(cl => cl.Type == "UserName")?.Value;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接