ASP.NET身份验证检查用户角色无法正常工作

26

我有一个ASP.NET MVC 5应用程序。我正在使用标准的ASP.NET Identity提供程序进行用户和角色管理。重要的是,我正在使用来自自己的存储库项目的IdentityUser,但这似乎没问题。我可以注册、登录、编辑用户并管理他们的角色。

我使用以下代码将用户添加到角色中:

UserManager.AddToRole(userdetail.Id, r);
db.Entry(userdetail).State = EntityState.Modified;
db.SaveChanges();

这似乎在数据库级别上运作正常。

但是,我无法使用基于角色的身份验证,实际上是最简单的。

HttpContext.User.IsInRole("Administrator")

也不起作用。

[Authorize(Roles="Administrator")]

也不起作用。

我只能用这种方法来检查用户是否是管理员:

UserManager.IsInRole(userID, "Administrator").

为什么?

我找到的每个教程都可以正常工作。不同的项目仓库可能是原因吗?或者ASP.NET Identity出了很多问题?

请给予建议,


3
我也有同样的问题,有解决办法吗? - janhartmann
答案已发布,请接受它。是jd4u发布的那个。 - DtechNet
6个回答

27

似乎存在一个问题。[该问题是设计上的]

  • 在AuthorizeAttribute和User.IsInRole中,角色名称区分大小写。
  • 在UserManager.IsInRole中,角色名称不区分大小写。

此外,确保使用正确的角色名称进行验证。

[以上是基于使用以下代码执行的测试结果。角色名称="Admin",用户已添加到角色"Admin"中。]

[Authorize(Roles="Admin")] /*True as "Admin" has A capital as entered in Role name*/
public ActionResult Secured()
{
    if (User.IsInRole("admin")) /*This is False*/
    {
         Console.WriteLine("In");
    }
    if(UserManager.IsInRole(User.Identity.GetUserId(), "admin")) /*This is True!!*/
    {
         Console.WriteLine("In");
    }
    return View();
}

如果我们将属性更改为[Authorize(Roles="admin")],它会重定向到登录页面。


你是否知道如何绕过这个问题,因为我遇到了完全相同的问题。我使用自定义的用户和角色存储,但我猜应该注意到它只能通过管理器而不是通过用户和注释正常工作。 - Base
这个救了我的命,我不知道为什么这个答案没有被接受。没有其他地方提到这点。在谷歌上查一下“Identity userinrole”,你会看到不准确的“User.IsInRole”<--行不通!当然,它们是老问题,ASP.NET MVC 5现在已经两年了,但没关系。如果有人正在编写原始的MVC 5堆栈,则这就是答案!可能也适用于.NET CORE。 - DtechNet
大小写敏感在这里简直是个罪行,一定是个bug。我在自己的代码中发现了这个问题,浪费了很多时间后才找到了这个答案。点赞你的回答! - Steve Hibbert
我不知道为什么这个答案被接受了。我在控制器上使用了Authorize属性,大小写与我的角色完全相同,拼写与我的角色完全相同,我肯定被分配到了这个角色(我通过RoleManager调用进行了检查并查看了数据库本身),但它仍然不让我进入。这是一个.Net Core API项目。 - ataraxia
1
在这种情况下,原始问题明确指出Authorize属性和User.IsInRole不起作用,但UserManager.IsInRole起作用。已知的原因是大小写敏感性不同,即此答案。在您的情况下,可能存在不同的问题。尝试复制原始问题,即检查UserManager.IsInRole是否起作用。如果UserManager(不区分大小写)也不起作用,则您有一个与原始帖子不同的问题(例如cookie中的缓存数据)。 - Sly Gryphon

25

在这种情况下,您需要注销并重新登录用户。

因为角色数据也存储在cookie中, 所以您必须重新发出cookie才能使其起作用。


2
您也可以通过更新安全戳来实现相同的功能,而无需再次登录和注销用户。请参见https://dev59.com/x2Ik5IYBdhLWcg3wNrq8#19505060。 - Funka

1

对我来说,以上解决方案都没有起作用,几乎所有的文章都没有用! 问题在于Authorize属性在由Identity Server 4发行的JWT令牌中搜索角色声明。而默认情况下,Identity Server在具有身份验证的新项目中不会序列化令牌中的角色声明。

以下配置是使其工作所必需的。(带有身份验证的ASP.Net 7新Blazor Web Assembly项目)

builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options => {
    options.IdentityResources["openid"].UserClaims.Add("role");
    options.ApiResources.Single().UserClaims.Add("role");
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

顺便说一下,这也是最简洁的解决方案,因为大多数文章都需要覆盖并实现自己的Identity Server主要工厂,并添加自定义身份资源等等。


0
你的 web.config 文件中有这个条目吗?
    <roleManager enabled="true">
        <providers>
            <clear />
            <add connectionStringName="ApplicationServices" name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" applicationName="/" />
        </providers>
    </roleManager>

另外,如果我没记错的话,在不同版本的.NET中,角色提供程序程序集有不同的命名空间。


9
你是在问最新的ASP.NET MVC 5和ASP.NET身份认证吗? - martonx
roleManager 是用作角色提供程序的(https://msdn.microsoft.com/en-us/library/system.web.security.roleprovider(v=vs.110).aspx ),它基本上已被弃用,不是所需的 ASP.NET Identity。 - JDPeckham

0

我在Asp.Net Core中使用IsInRoleAsync,我的问题是在创建角色时忽略了角色的标准化名称。因此,在更新了角色的标准化名称后,一切都正常工作。


0

我在一个 .net 7 webapi 项目中遇到了完全相同的问题。这是我发现的:

Jwt token 中的角色名称是规范化的,由于 Athorize 属性区分大小写,所以我必须使用 [Authorize(Roles="ADMIN")] 而不是 [Authorize(Roles="Admin")] 才能使角色正常工作。

最终,我将所有的角色名称都设置为大写,以避免这个陷阱。

我认为 JwtSecurityToken 生成方法使用规范化的角色名称来生成 JWT token 是我的问题根源。

无论如何,我认为 Authrize 属性和 JwtSecurityToken 应该给我们提供一个区分大小写的选项,或者至少警告我们关于这种区分大小写的比较算法。


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