如何使用SPA处理ASP.NET webapi中的密码重置令牌流

时间:2017-05-03 20:30:20

标签: asp.net asp.net-web-api asp.net-web-api2 asp.net-identity asp.net-spa

我有一个ASP.NET webapi2的API。不是.NET Core。然后我有一个React SPA。我使用Identity和Oauth2。

我正在实施auth系统,密码重置流程让我有点难过。 API将生成通过电子邮件发送给客户端的令牌。然后,客户端单击该链接以在某处导航。

链接导航到客户端javascript应用程序是有意义的,然后从该令牌中获取参数并将其提交给API。这个问题是API必须知道客户端URL才能生成链接。我不希望API知道有关客户端应用程序所在位置的任何信息,因为这似乎是愚蠢的耦合。

另一个选项是密码重置链接直接导航到API,然后再将用户重定向到客户端应用程序。这有一个问题,API需要知道客户端在哪里,它也有这个令人讨厌的重定向黑客。

是否有关于此的资源或有关如何工作的建议?

由于

2 个答案:

答案 0 :(得分:1)

我相信您所寻找的是身份提供者"登录"门户。密码重置的流程是身份提供者的一部分,而不是您的主要应用程序。因此,当您的用户单击其密码重置时,它会将其发送到身份提供商密码重置页面(此重置密码链接可能根本不应存在于您的主应用程序中)。一旦重置,用户将登录并使用授权令牌重定向到您的应用程序,您将交换访问令牌。必须为每个想要使用您的身份提供者的应用程序配置重定向。

答案 1 :(得分:0)

WebAPI不会在AccountController中公开所需的方法。

我使用了我添加到AccountController

的这两种方法
[Route("ForgotPassword")]
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var user = await UserManager.FindByNameAsync(model.UserName) ?? await UserManager.FindByEmailAsync(model.UserName);

    if (user == null)
    {
        return Ok("Ok");
    }


    if (user.Email == null)
    {
        throw new InvalidOperationException("Cannot send email. Email address not configured.");
    }

    var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);

#if DEBUG
    System.Diagnostics.Process.Start(
        string.Format(
            "http://localhost:4444/#/forgot-password-reset/{0}/{1}",
            HttpUtility.UrlEncode(user.UserName),
            HttpUtility.UrlEncode(token)
        )
    );
#endif

    SendMailForgotPassword(user, token);

    return Ok("Ok");
}

[Route("ForgotPasswordReset")]
public async Task<IHttpActionResult> ForgotPasswordReset(ForgotPasswordResetViewModel model)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    var user = await UserManager.FindByNameAsync(model.UserName) ?? await UserManager.FindByEmailAsync(model.UserName);
    if (user == null)
    {
        return Ok("Ok");
    }

    var result = await UserManager.ResetPasswordAsync(user.Id, model.Token, model.NewPassword);
    if (result.Succeeded)
    {
        return Ok("Ok");
    }

    throw new InvalidOperationException(string.Join("\r\n", result.Errors));
}