MVC 5访问声明身份用户数据


119

我正在使用Entity Framework 5 Database First方法开发MVC 5 Web应用程序。我正在使用OWIN进行用户身份验证。下面显示了我的帐户控制器中的登录方法。

public ActionResult Login(LoginViewModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        var user = _AccountService.VerifyPassword(model.UserName, model.Password, false);
        if (user != null)
        {
            var identity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, model.UserName), }, DefaultAuthenticationTypes.ApplicationCookie, ClaimTypes.Name, ClaimTypes.Role);

            identity.AddClaim(new Claim(ClaimTypes.Role, "guest"));
            identity.AddClaim(new Claim(ClaimTypes.GivenName, "A Person"));
            identity.AddClaim(new Claim(ClaimTypes.Sid, user.userID)); //OK to store userID here?

            AuthenticationManager.SignIn(new AuthenticationProperties
            {
                IsPersistent = model.RememberMe
            }, identity);

            return RedirectToAction("Index", "MyDashboard");
        }
        else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
    // If we got this far, something failed, redisplay form
    return View(model);
}

如您所见,我正在创建ClaimsIdentity并向其中添加多个声明,然后使用AuthenticationManager将其传递给OWIN来执行登录。

我遇到的问题是我不确定如何在控制器或Razor视图中的其余应用程序中访问声明。

我尝试了本教程中列出的方法

http://brockallen.com/2013/10/24/a-primer-on-owin-cookie-authentication-middleware-for-the-asp-net-developer/

例如,我在我的Controller代码中尝试过此操作,以尝试访问传递到Claims中的值,但是user.Claims等于null

var ctx = HttpContext.GetOwinContext();
ClaimsPrincipal user = ctx.Authentication.User;
IEnumerable<Claim> claims = user.Claims;

也许我在这里错过了一些东西。

更新

根据达林的回答,我添加了他的代码,但是仍然看不到对索赔的访问。请查看下面的屏幕截图,显示将鼠标悬停在identity.Claims上时看到的内容。

在此处输入图片说明


您可以确认Cookie是由浏览器发回的吗?也许您的安全设置需要SSL?
minimumprivilege 2014年

@leastprivilege谢谢,我现在开始调查。我在Stackoverflow上找到了这个问题,stackoverflow.com/ questions/20319118/… 这是我遇到的完全相同的问题,但不幸的是没有答案:(
tcode 2014年

您的OWIN组件如何初始化?
Derek Van Cuyk 2014年

我最近遇到这样的问题;我希望这个解决方案可帮助:stackoverflow.com/questions/34537475/...
亚历山德鲁·

Answers:


172

试试这个:

[Authorize]
public ActionResult SomeAction()
{
    var identity = (ClaimsIdentity)User.Identity;
    IEnumerable<Claim> claims = identity.Claims;
    ...
}

谢谢你的帮助。我在控制器中的操作中使用了您建议的答案来尝试访问Claims值,但是,我的身份。Claims仍然为NULL(请参见带有屏幕截图的更新问题)。还有其他想法吗?我感谢您的帮助。
tcode

不,对不起,我没有其他想法。这一直对我有用。
Darin Dimitrov 2014年

抱歉,最后一个问题。我需要像上述dotnetcodr.com/2013/02/25/…一样在Global.asax中创建自己的自定义ClaimsAuthenticationManager类和Application_PostAuthenticateRequest(),然后上面的代码才能正常工作吗?再次感谢。
tcode 2014年

7
在您首次获得授权之前,您将无法使用该方法,除非您使用了登录方法,这就是为什么OP当时看不到它的原因。如果您希望在Login方法中进行加载,则此时必须手动加载。
Adam Tuliper-MSFT 2014年

我正在使用asp.net core,正在寻找在2个多小时内获取LinkedIn个人资料图片的方法。我被困住了,我很累,我想放弃,直到看到你的答案。我想说谢谢百万次... +1
Vayne 17'Jul 21'19

36

您也可以这样做:

//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
var claims = identity.Claims;

更新资料

根据评论提供进一步的解释。

如果要在系统中创建用户,如下所示:

UserManager<applicationuser> userManager = new UserManager<applicationuser>(new UserStore<applicationuser>(new SecurityContext()));
ClaimsIdentity identity = userManager.CreateIdentity(user, DefaultAuthenticationTypes.ApplicationCookie);

您应该自动填充一些与您的身份有关的声明。

要在用户验证后添加自定义声明,可以执行以下操作:

var user = userManager.Find(userName, password);
identity.AddClaim(new Claim(ClaimTypes.Email, user.Email));

可以按照达林(Darin)的上述回答或我的回答读出要求。

当您在下面致电时传递身份信息时,声明仍然存在:

AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = persistCookie }, identity);

谢谢,但这仍然对我不起作用。你能看到我更新的问题吗?还有,最后一个问题。我需要像上述dotnetcodr.com/2013/02/25/…一样在Global.asax中创建自己的自定义ClaimsAuthenticationManager类和Application_PostAuthenticateRequest(),然后上面的代码才能正常工作吗?再次感谢您的帮助。
tcode 2014年

嗨,我将在返回PC时进行查看。
hutchonoid

谢谢,非常感谢。在一个开始让我
抓狂

@tgriffiths嗨,我为您添加了一个更新。希望能提供更多信息。祝好运。:)
hutchonoid 2014年

不幸的是,我没有使用内置的Entity Framework Code First,例如UserManager等。但是感谢您的输入。干杯。
tcode 2014年

30

我制作了自己的扩展类来查看所需内容,因此当需要将其用于控制​​器或View时,仅将using添加到我的命名空间中,如下所示:

public static class UserExtended
{
    public static string GetFullName(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.Name);
        return claim == null ? null : claim.Value;
    }
    public static string GetAddress(this IPrincipal user)
    {
        var claim = ((ClaimsIdentity)user.Identity).FindFirst(ClaimTypes.StreetAddress);
        return claim == null ? null : claim.Value;
    }
    public ....
    {
      .....
    }
}

在我的控制器中:

using XXX.CodeHelpers.Extended;

var claimAddress = User.GetAddress();

用我的剃刀:

@using DinexWebSeller.CodeHelpers.Extended;

@User.GetFullName()

8
return claim?.Value;因为为什么不
沃特

17

如果您不想一直使用声明,这是一种选择。看看Ben Foster的本教程

public class AppUser : ClaimsPrincipal
{
    public AppUser(ClaimsPrincipal principal)
        : base(principal)
    {
    }

    public string Name
    {
        get
        {
            return this.FindFirst(ClaimTypes.Name).Value;
        } 
    }

}

然后,您可以添加基本控制器。

public abstract class AppController : Controller
{       
    public AppUser CurrentUser
    {
        get
        {
            return new AppUser(this.User as ClaimsPrincipal);
        }
    }
}

在您的控制器中,您将执行以下操作:

public class HomeController : AppController
{
    public ActionResult Index()
    {
        ViewBag.Name = CurrentUser.Name;
        return View();
    }
}

12

要进一步解决Darin的答案,您可以使用FindFirst方法获得特定的声明:

var identity = (ClaimsIdentity)User.Identity;
var role = identity.FindFirst(ClaimTypes.Role).Value;

或者这也是一个字符串myValue = identity.FindFirstValue(“ MyClaimType”);
Juan Carlos Puerto

如果FindFirst找不到任何“角色”类型的声明,会发生什么情况?空异常?
菲尔(Phil)

10

您也可以这样做。

IEnumerable<Claim> claims = ClaimsPrincipal.Current.Claims;

8

请记住,为了查询IEnumerable,您需要引用system.linq。
它将为您提供所需的扩展对象:

CaimsList.FirstOrDefault(x=>x.Type =="variableName").toString();

6
Request.GetOwinContext().Authentication.User.Claims

但是,最好将声明添加到“ GenerateUserIdentityAsync”方法内,尤其是在Startup.Auth.cs中启用了regenerateIdentity的情况下。


GenerateUserIdentityAsync是一个很棒的建议,我完全忽略了它。非常感谢罗勒。
timmi4sa 2014年

6

@Rosdi Kasim'd答案的最短简化版本是

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("claimname").Value;

Claimname 是您要检索的声明,即,如果您正在寻找“ StreedAddress”声明,则以上答案将是这样的

string claimvalue = ((System.Security.Claims.ClaimsIdentity)User.Identity).
    FindFirst("StreedAddress").Value;

提供示例“ claimvalue”可以节省时间。谢谢
Nour Lababidi

2

根据ControllerBase类,您可以获得执行该操作的用户的声明。

在此处输入图片说明

这是您如何在1行中完成的操作。

var claims = User.Claims.ToList();


0

我在基本控制器中就这样使用它。只需共享即可使用。

    public string GetCurrentUserEmail() {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var email = claims.Where(c => c.Type == ClaimTypes.Email).ToList();
        return email[0].Value.ToString();
    }

    public string GetCurrentUserRole()
    {
        var identity = (ClaimsIdentity)User.Identity;
        IEnumerable<Claim> claims = identity.Claims;
        var role = claims.Where(c => c.Type == ClaimTypes.Role).ToList();
        return role[0].Value.ToString();
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.