问题
I wanted to generate a reset password link to send to the user's email that will open the ResetPassword page. On this page I will fill in the details regarding the new password and then confirm the password.
For this I have followed this Link
But there is a Url.Action method that i am not able to find in my web api project.
var callbackUrl = Url.Action(
"ConfirmEmail", "Account",
new { userId = user.Id, code = code },
protocol: Request.Url.Scheme);
Hase anybody done the reset password part in the web api? I need some help.
回答1:
You can use Url.Link
in Web API 2.0
var callbackUrl = Url.Link("Default", new { Controller = "Account",
Action = "ConfirmEmail", userId = user.Id, code = code });
回答2:
Url.Action does not exist because the Url helper in WebApi doe snot have the Action method. You can use Url.Route instead to generate the same thing but you will need to create a named route in order to use that method. If you are using attribute routing it, you can add a name to the route attribute like so:
[Route(Name="ConfirmEmail")]
and the helper would be
var callbackUrl = Url.Route("ConfirmEmail", new { userId = user.Id, code = code });
回答3:
Try following :
var code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
var callbackUrl = Url.Action("ResetPassword", "Account",
new { UserId = user.Id, code = code }, protocol: Request.Url.Scheme);
await UserManager.SendEmailAsync(user.Id, "Reset Password",
"Please reset your password by clicking here: <a href=\"" + callbackUrl + "\">link</a>");
return View("ForgotPasswordConfirmation");
For more information refer following link
回答4:
I created a simple "Change Password" form that I managed based on a menu click in my webAPI app. On the update handler for this form I created the following event handler. This simply calls the AccountController web service that comes with the VS2013 WebAPI template. This example has Authentication enabled and note the specific Url to use to include the defined Route in the AccountController method.
Look for the ChangePassword() method in the AccountController class generated in the WebAPI template to see what is getting called. I think this should answer your basic question.
function updateHandler(callback) {
var response;
var targetUrl;
// disabled the login button to avoid multiple events
$("#btnLogin").prop('disabled', true);
var loginData = {
grant_type: 'password',
NewPassword: $("#txtNewPassword").val(),
OldPassword: $("#txtOldPassword").val(),
ConfirmPassword: $("#txtConfirmPassword").val()
};
var token = sessionStorage.getItem(tokenKey);
var headers = {};
if (token) {
headers.Authorization = 'Bearer ' + token;
}
targetUrl = "/api/account/ChangePassword";
$.ajax({
type: 'POST',
url: targetUrl,
data: loginData,
headers: headers,
}).done(function (data) {
closeChangePassword();
}).fail(function (xhr, textStatus, errorThrown) {
passwordErrorHandler(xhr,0);
// re-enable the login button
$("#btnLogin").prop('disabled', false);
});
}
回答5:
You should never use Url.Link()
or Url.Action()
to send something to a user without setting host yourself in my opinion. You are exposing them to a possible Host Header Attack -> Password Reset Poisoning
.
If the IIS has a binding to accept connections on 80/443 the host header can be changed and in turn affecting the Url.Link()
or Url.Action()
methods. If you look at the request I'm making below I'm connecting to http://hostheaderattack
but manipulating the host
header.
Proof of Concept (PoC):
Url.Link:
public class TestController : ApiController
{
public IHttpActionResult Get()
{
var callbackUrl = Url.Link("Default", new
{
Controller = "Home",
Action = "Index",
});
return Ok(callbackUrl);
}
}
Url.Action:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Title = $"Url Created: {Url.Action("Index", "Home", "", Request.Url.Scheme)}";
return View();
}
}
I have demonstrated it here as well:
https://security.stackexchange.com/questions/170755/host-header-attack-password-reset-poisoning-asp-net-web-api-2-hosted-as-az/170759#170759
Some more reading about host header attack:
https://www.acunetix.com/blog/articles/automated-detection-of-host-header-attacks/
What you should do is never trust a user request and construct the url with host manually.
Example with manual host name for:
Url.Action: Url.Action("Index", "Home", null, Request.Url.Scheme, "example.com")
For Url.Link it is a bit trickier but it can be done like this:
public class TestController : ApiController
{
// GET api/<controller>
public IHttpActionResult Get()
{
var callbackUrl = Url.Link("Default", new
{
Controller = "Home",
Action = "Index",
});
callbackUrl = ReplaceHost(callbackUrl, "example.com");
return Ok(callbackUrl);
}
private string ReplaceHost(string original, string newHostName)
{
var builder = new UriBuilder(original);
builder.Host = newHostName;
return builder.Uri.ToString();
}
}
Source for ReplaceHost method:
https://stackoverflow.com/a/479812/3850405
来源:https://stackoverflow.com/questions/24203650/generate-reset-password-link-in-webapi