如何从ClaimsPrincipal中移除ClaimsIdentity

4
我有一个基于ASP.Net MVC构建的人力资源网络应用程序,分为不同的区域,例如经理、员工等。这些区域代表系统中不同类型的用户,可以执行不同的任务。涉及到一个遗留数据库,每种用户类型的信息存储在不同的表中。此外,每种用户类型存储的信息类型不同,因此将表分开是有意义的。
我想实现基于声明的身份验证,原因有几个:一是更容易在客户端上存储有关每个用户的详细信息,如用户名、角色等。另一个原因是ClaimsPrincipal支持多个标识。这很重要,因为在某些情况下,单个人可能需要同时使用多个标识访问系统。例如,经理需要访问系统执行管理任务,但经理也是员工,应该能够以员工身份登录系统。每个区域都是独立处理的,因此即使用户既是经理也是员工,他们也必须分别登录每个区域。
所以我的问题是:通过ClaimsPrincipal实现多个标识是否是正确的方法?我是否忽略了其他技术?如果多个标识是正确的方法,如何在用户从一个区域注销但仍然在另一个区域登录时保持其登录状态?通常,要注销代码看起来像这样:
FederatedAuthentication.SessionAuthenticationModule.SignOut();

我的假设是这将使用户退出两个区域。这正确吗? 如果是这样,我认为我可以简单地从ClaimsPrincipal中删除特定的Identity,然后重置并写入SessionSecurityToken,但是ClaimsPrincipal没有remove方法,只有AddIdentity。所以我想出了以下伪代码:
登出时:
  • 计算ClaimsPrincipal中身份证数量
  • 如果计数==1,则正常注销
  • 如果计数>1,则由于我们无法删除身份,因此遍历身份并创建一个新的ClaimsPrincipal,该ClaimsPrincipal排除我们要注销的身份,然后重置并写入SessionSecurityToken
我在正确的轨道上吗?是否有一些好的示例来实现ClaimsPrincipal中的多个Identities?我已经搜索过了,虽然我找到了有关多个Identities的简短提及,但我没有找到实际示例。
2个回答

2

看起来你的问题可能是一个人为制造的问题:

每个区域都被单独处理,因此即使用户既是经理又是员工,他们也必须分别登录每个区域。

这种分离的要求是什么?这是问题的关键,与其尝试使用单个用户的多个身份来弥补可行的解决方案,更容易解决这个问题。


回答你的直接问题,不能从主体中删除身份。您只能创建一个新的主体,并用所需的声明替换现有的主体。

Thread.CurrentPrincipal = new ClaimsPrincipal(...);

如果你从现有主体的身份或声明中构建主体,你可以过滤掉想要删除的内容。
基于声明的身份验证的基础是将身份验证机制与授权机制分离的思想。当您需要知道用户的身份时,您进行身份验证。当您进行授权时,您使用与用户关联的声明来执行访问控制决策,例如允许他们进入系统的管理区域。
用户的身份应该是系统上下文中的“who they are”。在大多数系统中,用户将具有单个身份。出于技术原因,例如允许用户将单个身份验证与多个可变身份关联的系统,拥有多个身份可能会很有用,但通常情况下,如果每个用户只有一个单一身份,则系统最简单,因为实际情况是您有单个用户,他通常向您呈现单个身份。
我只能想到一个合法的原因,让用户使用多个身份登录系统:用户希望使用多个身份来分离他们的活动,例如工作账户和个人账户。
您的系统应该能够使用单个经过身份验证的身份运行。如果您的管理员需要通过额外的身份验证步骤才能到达管理部分,请不要尝试删除其现有身份-而是使用提升系统进行身份验证,并将身份添加到其现有主体中。用户没有改变,您只是获得了与他们相关的更多声明。

1
在我的情况下,多个身份是必要的,不仅仅是因为你提到的原因(分离他们的活动),而且因为他们的身份本质上是不同的。除了经理和员工之外,我们还允许供应商和系统管理员访问系统。在某些情况下,同一个人可能会担任这些角色中的多个。经理不仅仅是具有提升权限的员工,他们是不同的实体。经理甚至可能不是员工。它可以是第三方,但由于它可以是员工,我们需要适应这种情况。 - Louise Eggleton
我已经想出了一个解决方案,它涉及到多个身份。我将发布一个更新,其中包含我如何解决这个问题的代码,但基本上由于ClaimsPrincipal可以持有多个ClaimsIdentities,我访问了ClaimsPrincipal中的Identities,直接处理了这些Identities,根据需要添加或删除Identities,然后从这些identities集合重新创建了Principal。 - Louise Eggleton
我为授权与认证之间的区别点赞。 - Louise Eggleton
我想强调的是,除非认证机制本身对于访问控制决策非常重要,否则您的系统不应关心用户如何进行身份验证。您所描述的情况只是标准的联合登录,可能涉及多个主域。我没有看到需要使用离散身份解决的合理要求。 - Paul Turner

2
建议:在您的特定情况下,我们可以使用两个ClaimsIdentity处理不同的ClaimsPrincipal对象。
            var claims1 = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "Louise")
               , new Claim(ClaimTypes.Role, "Manager")
            };
            ClaimsIdentity claimsIdentity1 = new ClaimsIdentity(claims1 ,"XYZ");
            ClaimsPrincipal principal1 = new ClaimsPrincipal(claimsIdentity1);

            var claims2 = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "Louise")
               , new Claim(ClaimTypes.Role, "Employee")
            };
            ClaimsIdentity claimsIdentity2 = new ClaimsIdentity(claims2 ,"XYZ");
            ClaimsPrincipal principal2 = new ClaimsPrincipal(claimsIdentity2);

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