ASP.NET Identity WebAPI 密码重置令牌无效
ASP.NET Identity WebAPI invalid password reset token
我有一个生成密码重置令牌的 Webapi 服务。
令牌生成服务端点:
[Authorize(Users = "abcd")]
[HttpGet]
[ActionName("GenerateForgotPasswordToken")]
public async Task<IHttpActionResult> GenerateForgotPasswordToken(string key)
{
if (key == null || UserManager.FindById(key) == null)
{
return InternalServerError(new Exception("User not found"));
}
return Ok(await UserManager.GeneratePasswordResetTokenAsync(key));
}
我的应用程序用户管理器:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
//var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
var manager = new ApplicationUserManager(new UserStore<IdentityUser>(new MTA()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<IdentityUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
令牌将在电子邮件中用于向用户发送密码重置 URL。 URL 指向一个 ASP.NET MVC 视图,它是我的 WebAPI 项目的一部分,显然托管在 IIS 中的同一个 Web 应用程序中。页面上的密码重置按钮调用我重置密码的其他服务端点。
密码重置服务端点:
[HttpGet]
[AllowAnonymous]
public async Task<HttpResponseMessage> ResetPassword([FromUri]string email,[FromUri]string code,[FromUri]string password)
{
var user = await UserManager.FindByEmailAsync(email);
var result = await UserManager.ResetPasswordAsync(user.Id, code, password);
if (result.Succeeded)
{
return Request.CreateResponse();
}
return Request.CreateResponse(System.Net.HttpStatusCode.Ambiguous);
}
此外,这两个 Web api 端点都在同一个控制器中,并且在控制器中我定义了一个全局 UserManger,如下所示:
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
当我使用高级 REST 客户端等外部工具时,我能够点击第一个端点以生成令牌,然后将令牌连同电子邮件和新密码传递到第二个端点并成功重置密码。但是,当我的 ASP.NET MVC 控制器使用第一个端点生成的相同令牌并调用 passwordReset 端点时,令牌无效!我已经确保没有 Encoding/Decoding 问题,并且第二个端点收到的令牌在两个测试中都是相同的。
我的所有 WebApi 和 ASP 控制器都在同一个项目中并托管在同一个 Web 应用程序中。
我认为问题可能与新的 Token 提供程序 有关,当请求基于 OwinContext 时,但我不明白为什么可以通过网络浏览器调用它。
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
看完这个问题我发现了问题:
在我的例子中,IIS 配置为在运行时生成 机器密钥 ,这就是为什么即使我的所有代码都是 运行 作为单个应用程序,令牌仍然无效的原因.
这里是 IIS 机器密钥配置指南:How to Generate Machine Key using IIS
我有一个生成密码重置令牌的 Webapi 服务。
令牌生成服务端点:
[Authorize(Users = "abcd")]
[HttpGet]
[ActionName("GenerateForgotPasswordToken")]
public async Task<IHttpActionResult> GenerateForgotPasswordToken(string key)
{
if (key == null || UserManager.FindById(key) == null)
{
return InternalServerError(new Exception("User not found"));
}
return Ok(await UserManager.GeneratePasswordResetTokenAsync(key));
}
我的应用程序用户管理器:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
//var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
var manager = new ApplicationUserManager(new UserStore<IdentityUser>(new MTA()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<IdentityUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<IdentityUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
令牌将在电子邮件中用于向用户发送密码重置 URL。 URL 指向一个 ASP.NET MVC 视图,它是我的 WebAPI 项目的一部分,显然托管在 IIS 中的同一个 Web 应用程序中。页面上的密码重置按钮调用我重置密码的其他服务端点。
密码重置服务端点:
[HttpGet]
[AllowAnonymous]
public async Task<HttpResponseMessage> ResetPassword([FromUri]string email,[FromUri]string code,[FromUri]string password)
{
var user = await UserManager.FindByEmailAsync(email);
var result = await UserManager.ResetPasswordAsync(user.Id, code, password);
if (result.Succeeded)
{
return Request.CreateResponse();
}
return Request.CreateResponse(System.Net.HttpStatusCode.Ambiguous);
}
此外,这两个 Web api 端点都在同一个控制器中,并且在控制器中我定义了一个全局 UserManger,如下所示:
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
当我使用高级 REST 客户端等外部工具时,我能够点击第一个端点以生成令牌,然后将令牌连同电子邮件和新密码传递到第二个端点并成功重置密码。但是,当我的 ASP.NET MVC 控制器使用第一个端点生成的相同令牌并调用 passwordReset 端点时,令牌无效!我已经确保没有 Encoding/Decoding 问题,并且第二个端点收到的令牌在两个测试中都是相同的。
我的所有 WebApi 和 ASP 控制器都在同一个项目中并托管在同一个 Web 应用程序中。
我认为问题可能与新的 Token 提供程序 有关,当请求基于 OwinContext 时,但我不明白为什么可以通过网络浏览器调用它。
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
看完这个问题我发现了问题:
在我的例子中,IIS 配置为在运行时生成 机器密钥 ,这就是为什么即使我的所有代码都是 运行 作为单个应用程序,令牌仍然无效的原因.
这里是 IIS 机器密钥配置指南:How to Generate Machine Key using IIS