1

我们将 Identity 2 与 MVC 5 一起用于我们的 Web 项目。要求是能够像这样在 web.config 中为 Web 应用程序配置模拟用户

<system.web>
  <identity impersonate="true" userName="domain\impersonated" password="password" />
</system.web>

我们实现了自定义 UserManager 并像这样配置身份验证:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.CreatePerOwinContext(MyIdentityContext.Create);
        app.CreatePerOwinContext<MyUserManager>(MyUserManager.Create);
        app.CreatePerOwinContext<MySignInManager>(MySignInManager.Create);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyUserManager, MyUser, Guid>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                    getUserIdCallback: (claimsIdentity) => (Guid.Parse(claimsIdentity.GetUserId()))),
            },
            ExpireTimeSpan = TimeSpan.FromMinutes(settingsFacade.GetSessionTimeout())
        });
    }
}

我们还实现了自定义 UserStore,使用 EF 与数据库交互。连接字符串配置为使用 Integrated Security=True 以使用我们的模拟用户访问数据库。

我们使用 ChangePassword Action 实现了 AccountController

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangePassword(ChangePasswordViewModel model)
{
    if (!ModelState.IsValid)
    {
       return View(model);
    }

    var userGuid = User.Identity.GetUserGuid();
    var result = UserManager.ChangePassword(userGuid, model.OldPassword, model.NewPassword);

    if (result.Succeeded)
    {
        var user = UserManager.FindById(User.Identity.GetUserGuid());
        if (user != null)
        {
            SignInManager.SignIn(user, isPersistent: false, rememberBrowser: false);
        }
        return RedirectToAction("Index", new { Message = AccountMessageId.ChangePasswordSuccess });
    }

    AddErrors(result);

    return View(model);
}

当调用 ChangePassword 操作时,它按预期在模拟用户下运行。当我停在 ChangePassword 内的断点上时

System.Security.Principal.WindowsIdentity.GetCurrent().Name = "domain\impersonated"

当我进入 UserManager.ChangePassword 并在我们的 UserStore 公共任务 FindByIdAsync(Guid userId) 中停止调试器时,WindowsIdentity 更改为运行应用程序池的用户而不是模拟用户。应用程序用户无权访问数据库。我们只希望模拟用户能够访问数据库。

System.Security.Principal.WindowsIdentity.GetCurrent().Name = "domain\appPoolUser"

我注意到当我替换同步扩展方法调用时

UserManager.ChangePassword(userGuid, model.OldPassword, model.NewPassword);

使用异步方法调用

UserManager.ChangePasswordAsync(userGuid, model.OldPassword, model.NewPassword).Result;

WindowsIdentity 不会更改,并且 FindByIdAsync 正在模拟用户上下文中运行。

我们做错了什么?为什么同步和异步方法的行为不同。我们是否缺少任何 OWIN 配置,以便在模拟中正常工作?谢谢你。

4

0 回答 0