I've got some functionality on my site that if a user logs in at any given point then upon successful login they'll be bounced back to the page that they viewing. And this is all working fine except when there are parameters on the query string. To explain:
A user will be on page:
http://localhost:55432/eng/speakers/?altTemplate=Speaker&id=0030X00002QCntgQAD
and hit the login button (which takes them to another page), the URL being:
http://localhost:55432/login/?redirectUrl=http://localhost:55432/eng/speakers/?altTemplate=Speaker&id=0030X00002QCntgQAD®ion=eng
As you can see I'm populating a parameter on the QS (redirectUrl)
On the login page there's a simple form that posts username and password to a method:
public ActionResult HandleLogin(string username, string password, [FromUri] string redirectUrl)
But when this method is being called the value of the redirectUrl parameter is:
http://localhost:55432/eng/speakers/?altTemplate=Speaker
i.e. everything including the ampersand has been removed.....
Would anyone know why this happens and more importantly how to stop it?
Thanks,
C
Related
i'm developing an MVC 4 web application.
I'm trying to make an url that changes in an authorized/unauthorized context.
I'm generating the following url for unauthorized user:
http://localhost/vendas-web/Login?ReturnUrl=%2Fvendas-web%2FClienteNovo%2FIndex%299999
The first time I've tested, it worked just fine.
But.. the second time I've tried, the query string got lost.. and the url turned into:
http://localhost/vendas-web/Login
When i test it against chrome on anonymous tab, it works FINE.
When i change the value of the last parameter, it works FINE.
There's some sort of cache related to this ?
What i'm doing wrong ?
Soo, my question is:
How do i keep my full url in any scenario ??
Ty
There's really not enough information here, but what you're likely talking about is that the first time a user needs to be authorized, they are automatically redirected to the first URL, which includes the ReturnUrl bit. That's built into the framework to allow the user to be redirected back to that URL after logging in. However, if you need to persist this past that initial first redirect to the login page, that's on you. Any links must manually add the query string param:
#Url.Action("SomeAction", new { ReturnUrl = Request["ReturnUrl"] })
And any forms must include it as a hidden input:
#Html.Hidden("ReturnUrl", Request["ReturnUrl"])
Otherwise, yes, it will be lost, because the literal URL you're now requesting doesn't include it. It's not just magically appended.
My problem was cache...
I've used this annotation to avoid using cache by application.
[OutputCache(NoStore = true, Duration = 0)]
I am struggling over this issue since yesterday.I am working on a web application which includes email service.Email includes 'link' to a certain page of that application.
Now:I have 2 scenarios:
1) If the user is logged in(in the application) already and he hit
the url he got in his email,the link will open perfectly.
2) If the user is not logged in(in the application) then the url
will not open and will redirect itself to the login page with the
functionality added in the BaseController.
*
Now what I want is when the user logs in after hitting the url and on
successfully login the user gets redirect to the link provided in the
Email.
*
for eg: If the user gets an email to the detail page of an employee,So on successfully login the user gets redirect to the Detail page of the employee.
Something like appending the redirecturl to the login page.
I think rewriting url is what I should be doing.
But I dont know how can I use that in this case.Help me out.
The default project template that comes with ASP.NET MVC 5 behaves exactly as you describe.
If you want to redirect to a custom login URL, reconfigure the LoginPath property of the CookieAuthenticationOptions object
LoginPath = new PathString("/Account/Login")
In the default template this is done in the Startup.Auth.cs class.
NOTE: If you are using an old version of ASP.NET MVC, the default project template behaved in the same way. But previously this was implemented using Forms Authentication, so in order to redirect to a custom login URL you would then have to set the loginUrl attribute of the <forms> tag in the Web.config file
By default if a user tries to access the authorized page when he is not authorized the automatically gets redirected to the log in page or the page which is configured in web.config file for the element. And you can see the query string returnUrl having the url that was tried to access initially get appended to the log in url.
To access the return url, include a new parameter as returnUrl and maintain the return url in a hidden field by model data to access on post back for redirection.
If the user is authenticated then on post back then redirect the user to the specified page what he intended to go for.
I don't remember exactly but few month ago I implemented similar functionality and i had to save returnUrl explicitly (due to MVC bug or something) - Refer this link
AccountController.cs - Snapshot
[HttpGet]
[AllowAnonymous]
public ActionResult Login(string returnUrl, string userName)
{
// You login method logic....
// Add this line to save the returnUrl value
ViewBag.ReturnUrl = returnUrl;
}
Login.cshtml - Snapshot
#using (Html.BeginForm("Login", "Account", FormMethod.Post ,new {ReturnUrl = ViewBag.ReturnUrl}))
{
<input type="hidden" name="ReturnUrl" value="#Request.QueryString["ReturnUrl"]" />
// .....
}
See if this helps in your case.
Trying to get password reset functionality in place. This will be for a user who has not and cannot log in to the system. I think I'm close but it doesn't feel right:
I have a ResetPassword method/view...it simply asks for the user's email address, does not confirm an account to the user but if one exists, sends email with link+token. That all works fine.
The next part is where my questions are....I receive the password token with this method (via the user's email link being clicked):
[HttpGet]
public ActionResult ReceiveResetToken(string token)
{
try
{
if (!String.IsNullOrEmpty(token))
{
var username = (from u in db.Users
where u.Userid == WebSecurity.GetUserIdFromPasswordResetToken(token)
select u.Email).ToString();
if (!String.IsNullOrEmpty(username))
{
WebSecurity.ConfirmAccount(token);
}
}
RedirectToAction("Index", "Home");
}
catch (Exception)
{
throw;
}
}
I'm missing something obvious here. The method isn't complete because I keep rethinking it...get the username, confirm the account, somehow log them in without knowing what their password is, redirect to change password page? Doesn't feel right.
So then I thought maybe pass along the hidden username with a ViewBag to the change dialogue...doesn't feel right either. I'd like a more elegant approach, receive the token, ask the username for the new password, update db and login. What is the pattern for receiving a password reset token?
EDIT -------
So as I am continuing to search for answers, I came across this little gem. Apparently there is a WebSecurity.ResetPassword method that accepts the token and a new password. This feels like the right path, no need to worry about logins, just change it and redirect to login...I'll finish up the code and post a solution as this seems to be a popular and often unanswered question on SO.
If anyone could confirm that I'm on the right path or post any thoughts on adding elegance to the pattern that'd be cool
It's a right path !
for me,
User give his email and i send him a token who is generate an GUID and i have passwordResetTokenDate who take a date when user asked the reset. (token is valid 48hours)
in email, there is a link with token and i give him a token, if when he click and something is wrong, he can copy pasted the token in textbox or re-clicking on the link
when he click on the link, i check the token and the date and passwordResetTokenDate if all is right, there is two textbox and user enter 2 times his new password.
when he save his password, i logged him.
WebSecurity.ResetPassword do the job !
here an example : (i have a custom websecurity with custom provider)
[AllowAnonymous]
public ActionResult ForgotMyPassword(string confirmation, string username)
{
username = HttpUtility.UrlDecode(username);
ViewBag.Succeed = false;
SetPasswordViewModel Fmp = new SetPasswordViewModel(username,confirmation);
return View(Fmp);
}
//
// POST: /Account/ForgotMyPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ForgotMyPassword(SetPasswordViewModel model)
{
ViewBag.Succeed = false;
if (ModelState.isValid)
{
ViewBag.Succeed = WebSecurity.ResetPassword(model.UserName, model.PasswordResetToken, model.Password.NewPassword);
}
if (!ViewBag.Succeed)
{
ModelState.AddModelError("","something"); //something
}
return View(model);
}
This is how it should work (as implemented in ASP Security Kit)
User clicks on forgot password link (which opens /account/forgot for example)
On this page, you ask user for his userName (which could be his email).
You check whether that user exists. If yes, you generate a reset token, saving it in the database for that username and send out an email to that user with a link (http://yourdomain.com/account/confirm/[tokenHere])
You display user a message something like "if you have an account with this username, you will receive an email with instructions to reset your password shortly." but you don't login user on this page because you just asked him for his username!
User receives the email, clicks on the link and the reset password page opens (/account/confirm/[tokenHere])
On this page, user needs to fill password and confirm password fields. Once done you will redirect user to login page (you may argue that you can directly sign in user once he resets his password; but redirecting to login seems to be the standard practice followed on most sites.)
Answering my own question in case it helps anyone.
Provide a form asking for email address to send password reset link
Use WebSecurity.GeneratePasswordResetToken(email, 1440) to generate token
Send email to user with link pointing to a token receiving method
Write an HttpGet method to receive the token and display newPassword form
The form posts the token and the new password model to a method that uses WebSecurity.ResetPassword(token, newPassword)
redirect to login
Haven't written it all out yet but I think this is the way to do it properly
I am using Access Control service (ACS). I fetched all identity providers (ip) which i set for my application using the following code :
public ActionResult IdentityProviders(string serviceNamespace, string appId)
{
string idpsJsonEndpoint = string.Format(Global.IdentityProviderJsonEndpoint, serviceNamespace, appId);
var client = new WebClient();
var data = client.DownloadData(idpsJsonEndpoint);
return Content(Encoding.UTF8.GetString(data), "application/json");
}
When user click over the signin link the above code called using ajax and get the ips and display them in jquery-ui dialog. And when user click any one of the ips for login the browser redirect to the selected ip login page. After successful login the control return to my control which i set as a returnUrl. Upto this every thing is works fine.
Now what i am trying to do is to pass some values to identity provider (ip) login page and want to get back those values at my returnUrl controller. For this i searched and came to know that there is a query string parameter known as wctx which we can set and get the value at return url. But i dont know how to do this. Can anybody please guid me how can i achieve this?
It is relatively (pretty) easy.
Your URL for listing IdPs looks something like this:
https://[your_namespace].accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=[your_realm]&reply_to=[configured_return_url_for_your_rp]&context=&request_id=&version=1.0&callback=
This is the most complete request for list of Identity Providers. Your may miss some variables (such as context, or reply_to), but what I show is the complete request.
So now you have two options:
inclide your own reply_to parameter. It must be withing the configured realm. So if your realm is https://www.mygreatapp.com/, your default return URL would probably be something like https://www.mygreatapp.com/returnUrl/ (if your controller to handle ACS response is returnUrlController. Now, you can safely change the reply_to to be https://www.mygreatapp.com/returnUrl/?foo=bar, just make sure you URL Encode the query string.
Use the context parameter. It is safer to use and I would suggest using it. Now your URL for fetching list of IdPs will be something like:
https://[your_namespace].accesscontrol.windows.net:443/v2/metadata/IdentityProviders.js?protocol=wsfederation&realm=[your_realm]&reply_to=[configured_return_url_for_your_rp]&context=[your_custom_string_value_which_you_may_even_encrypt]&request_id=&version=1.0&callback=
Note the now there is context value present in the request for IdP list ([your_custom_string_value_which_you_may_even_encrypt]). In your returnUrl handler controller, you can check for it with code similar (or equal) to the following:
if (ControllerContext.HttpContext.Request.Form["wresult"] != null)
{
// This is a response from the ACS - you can further inspect the message if you will
SignInResponseMessage message =
WSFederationMessage.CreateFromNameValueCollection(
WSFederationMessage.GetBaseUrl(ControllerContext.HttpContext.Request.Url),
ControllerContext.HttpContext.Request.Form)
as SignInResponseMessage;
if (!string.IsNullOrWhiteSpace(message.Context))
{
// do whatever you want with the context value
}
}
You may want to perform any/more additional checks while handling the SignInResponse from ACS.
How can I have the facebook auth dialog to return me an extra parameter upon success from the auth dialog?
To be more specific, I want to add a "returnUrl" that is the page that a user tried to access before being authenticated.
I tried adding as a querystring parameter to the url set in redirect_uri but it doesn't work when I try to get the token later from oauth/access_token.
thanks!
Adding a query string parameter to the redirect_uri should work; I have done it in the past. Just make sure you pass the exact same URL (including the query string parameter) to oauth/access_token.