ChatGPT解决这个技术问题 Extra ChatGPT

我正在使用 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/

例如,我在我的控制器代码中尝试了这个,试图访问传递给声明的值,但是,user.Claims 等于 null

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

也许我在这里遗漏了一些东西。

更新

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

https://i.stack.imgur.com/Uk6RQ.jpg

你能确认cookie是由浏览器发回的吗?也许您的安全设置需要 SSL?
@leastprivilege 谢谢,我现在会调查一下。我在 Stackoverflow 上发现了这个问题,stackoverflow.com/questions/20319118/… 这与我遇到的问题完全相同,但不幸的是没有答案:(
您的 OWIN 组件是如何初始化的?
我最近遇到了这样的问题;我希望此解决方案有所帮助:stackoverflow.com/questions/34537475/…

D
Darin Dimitrov

尝试这个:

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

谢谢你的帮助。我在控制器中的操作中使用了您建议的答案来尝试访问声明值,但是,我的身份。声明仍然为 NULL(请参阅带有屏幕截图的更新问题)。还有其他想法吗?我感谢您的帮助。
不,抱歉,我没有其他想法。这一直对我有用。
对不起,最后一个问题。我是否需要像 dotnetcodr.com/2013/02/25/… 那样在 Global.asax 中创建自己的自定义 ClaimsAuthenticationManager 类和 Application_PostAuthenticateRequest() 才能使上面的代码起作用?再次感谢。
在您第一次授权之前,您必须在登录方法之后才能访问它,这就是 OP 当时看不到它的原因。如果您希望在 Login 方法中加载,此时您必须手动加载。
J
Jay Stevens

你也可以这样做:

//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() 才能使上面的代码起作用?再次感谢你的帮助。
@tgriffiths 嗨,我为您添加了更新。希望提供更多信息。祝你好运。 :)
不幸的是,我没有首先使用内置的实体框架代码,例如 UserManager 等。但感谢您的输入。干杯。
啊对。好的,您可能可以像我在 MVC 4 中那样做,但我没有在 mvc5 中尝试过。这是一篇非常好的文章,我用过...dotnetcodr.com/2013/02/25/…
关于通过 EF 种子方法创建用户时如何添加声明的任何想法?
R
Rosdi Kasim

我创建了自己的扩展类来查看我需要什么,所以当我需要进入我的控制器或视图时,我只将 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()

return claim?.Value; 因为为什么不
Q
Quentin

如果您不想一直使用声明,这是一种替代方法。看看 Ben Foster 的这个tutorial

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

P
Patrick

要进一步了解 Darin 的答案,您可以使用 FindFirst 方法获取您的具体声明:

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

或者这个也是 string myValue = identity.FindFirstValue("MyClaimType");
如果 FindFirst 没有找到任何“角色”类型的声明会怎样?空异常?
var username = identity.FindFirst(ClaimTypes.NameIdentifier).Value;
P
Patrick

你也可以这样做。

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

b
bummi

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

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

G
Gwen

@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;

B
Bassel Banbouk
Request.GetOwinContext().Authentication.User.Claims

但是,最好在“GenerateUserIdentityAsync”方法中添加声明,特别是如果启用了 Startup.Auth.cs 中的 regenerateIdentity。


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

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

https://i.stack.imgur.com/NNXKa.png

这是您可以在 1 行中完成的方法。

var claims = User.Claims.ToList();

F
Felipe Deveza
var claim = User.Claims.FirstOrDefault(c => c.Type == "claim type here");

B
B M

我在我的基本控制器中使用它。只是分享准备使用。

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

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅