gpt4 book ai didi

c# - User.Identity 在 ClaimsIdentity 和 WindowsIdentity 之间波动

转载 作者:太空狗 更新时间:2023-10-29 19:42:08 25 4
gpt4 key购买 nike

我有一个允许使用表单登录和 Windows 身份验证登录的 MVC 站点。我使用自定义 MembershipProvider 对用户进行 Active Directory 身份验证,使用 System.Web.Helpers AntiForgery 类进行 CSRF 保护,以及 Owin cookie 身份验证中间件。

在登录期间,一旦用户通过 Active Directory 身份验证,我将执行以下操作:

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(StringConstants.ApplicationCookie);
var identity = new ClaimsIdentity(StringConstants.ApplicationCookie,
ClaimsIdentity.DefaultNameClaimType,
ClaimsIdentity.DefaultRoleClaimType);
if(HttpContext.Current.User.Identity is WindowsIdentity)
{
identity.AddClaims(((WindowsIdentity)HttpContext.Current.User.Identity).Claims);
}
else
{
identity.AddClaim(new Claim(ClaimTypes.Name, userData.Name));
}
identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "Active Directory"));
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, userData.userGuid));
authenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = false }, identity);

我的 SignOut 功能如下所示:
IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignOut(StringConstants.ApplicationCookie);

登录是通过 jQuery.ajax 请求执行的。成功后, Window.location更新到网站的主页。

使用表单和 IntegratedWindowsAuthentication 登录(IWA) 有效,但我在使用 IWA 登录时遇到了问题。这是发生的事情:
  • 用户在登录页面上选择 IWA 并点击提交按钮。这通过 ajax 请求发送到常规登录操作。
  • 该站点收到请求,看到“使用 IWA”选项并重定向到相关操作。发送 302 响应。
  • 浏览器自动处理 302 响应并调用重定向目标。
  • 过滤器看到请求被发送到 IWA 登录操作并且 User.Identity.IsAuthenticated == false。发送 401 响应。
  • 浏览器会自动处理 401 响应。如果用户尚未在浏览器中使用 IWA 进行身份验证,他们会收到一个弹出窗口(默认浏览器行为)。收到凭据后,浏览器会使用用户凭据执行相同的请求。
  • 该站点接收经过身份验证的请求并模拟用户对 Active Directory 执行检查。如果用户通过身份验证,我们将使用上面的代码完成 SignIn。
  • 用户被转发到站点的主页。
  • 该站点收到加载主页的请求。 这就是事情有时会出错的地方 .User.Identity此时的类型为 WindowsIdentityAuthenticationType设置为 Negotiate ,而不是我所期望的,ClaimsIdentity创建于 SignIn方法同上。
    该站点通过调用 @AntiForgery.GetHtml() 为用户准备主页在 View 中。这样做是为了使用登录用户的详细信息创建新的 AntiForgery token 。 token 是用 WindowsIdentity 创建的
  • 当主页加载时,向服务器发出的 ajax 请求以 ClaimsIdentity 到达。 !第一POST因此,请求到达不可避免地会导致 AntiForgeryException它发送的防伪 token 是“针对不同用户的”。

  • 刷新页面会导致主页加载 ClaimsIdentity并允许 POST要求发挥作用。

    二、相关问题 : 在刷新后的任何时候,一旦事情应该正常工作,就会出现 POST请求可能会到达 WindowsIdentity而不是与 ClaimsIdentity ,再次抛出 AntiForgeryException .
  • 这不是任何特定的帖子请求,
  • 它不是在任何特定时间后(可能是第一次/第二次请求,也可能是第 100 次),
  • 在该 session 期间不一定第一次调用特定的发布请求。

  • 我觉得我在 User.Identity 上遗漏了一些东西或者我在登录过程中做错了什么......有什么想法吗?

    备注 : 设置 AntiForgeryConfig.SuppressIdentityHeuristicChecks = true;允许 AntiForgery.Validate Action 是否成功 WindowsIdentityClaimsIdentity已收到,但正如 MSDN 上所述:

    Use caution when setting this value. Using it improperly can open security vulnerabilities in the application.



    没有更多的解释,我不知道这里实际上打开了哪些安全漏洞,因此我不愿意使用它作为解决方案。

    最佳答案

    原来问题是 ClaimsPrincipal 支持多个身份。如果您处于拥有多个身份的情况下,它会自行选择一个。我不知道是什么决定了 IEnumerable 中身份的顺序,但无论它是什么,它显然肯定会在用户 session 的生命周期中产生一个恒定的顺序。

    正如 asp.net/Security git 的问题部分所述,NTLM and cookie authentication #1467 :

    Identities contains both, the windows identity and the cookie identity.





    It looks like with ClaimsPrincipals you can set a static Func<IEnumerable<ClaimsIdentity>, ClaimsIdentity> called PrimaryIdentitySelector which you can use in order to select the primary identity to work with.



    为此,请创建一个带有签名的静态方法:
    static ClaimsIdentity MyPrimaryIdentitySelectorFunc(IEnumerable<ClaimsIdentity> identities)

    此方法将用于遍历 ClaimsIdentity 的列表s 并选择您喜欢的一种。
    然后,在您的 Global.asax.cs 将此方法设置为 PrimaryIdentitySelector ,像这样:
    System.Security.Claims.ClaimsPrincipal.PrimaryIdentitySelector = MyPrimaryIdentitySelectorFunc;

    我的 PrimaryIdentitySelector方法最终看起来像这样:
    public static ClaimsIdentity PrimaryIdentitySelector(IEnumerable<ClaimsIdentity> identities)
    {
    //check for null (the default PIS also does this)
    if (identities == null) throw new ArgumentNullException(nameof(identities));

    //if there is only one, there is no need to check further
    if (identities.Count() == 1) return identities.First();

    //Prefer my cookie identity. I can recognize it by the IdentityProvider
    //claim. This doesn't need to be a unique value, simply one that I know
    //belongs to the cookie identity I created. AntiForgery will use this
    //identity in the anti-CSRF check.
    var primaryIdentity = identities.FirstOrDefault(identity => {
    return identity.Claims.FirstOrDefault(c => {
    return c.Type.Equals(StringConstants.ClaimTypes_IdentityProvider, StringComparison.Ordinal) &&
    c.Value == StringConstants.Claim_IdentityProvider;
    }) != null;
    });

    //if none found, default to the first identity
    if (primaryIdentity == null) return identities.First();

    return primaryIdentity;
    }

    [编辑]
    现在,事实证明这还不够,因为 PrimaryIdentitySelector只有一个时似乎没有运行 IdentityIdentities列表。这会导致登录页面出现问题,有时浏览器会在加载页面时传递 WindowsIdentity,但不会在登录请求时传递它 {exasperated sigh}。为了解决这个问题,我最终为登录页面创建了一个 ClaimsIdentity,然后手动覆盖线程的 Principal,如 this SO question 中所述。 .

    这会导致 Windows 身份验证出现问题 OnAuthenticate不会发送 401 来请求 Windows 标识。要解决此问题,您必须注销登录身份。如果登录失败,请确保重新创建登录用户。 (您可能还需要重新创建 CSRF token )

    关于c# - User.Identity 在 ClaimsIdentity 和 WindowsIdentity 之间波动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50236994/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com