我们将 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 配置,以便在模拟中正常工作?谢谢你。