How am I supposed to use ReturnUrl = ViewBag.ReturnUrl in MVC 4 - asp.net-mvc-4

I'm working on 'ASP.NET MVC 4' application. I'm using/learning SimpleMembershipProvider and try to stick to the default logic created by VS2012 with the Internet template (if I'm not mistaken, the one with 'SimpleMembershipProvider' out of the box).
I'm stuck at the AccountController where I just can't figure put how exactly I can use this method:
private ActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
From what I understand the whole idea is to get redirected to the location from where you've decided to log in (exactly what I want to accomplish). I took a look at how it's used in the view :
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
Look for a place where actually ViewBag.ReturnUrl is set with some value and I only got this method here:
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
and I'm getting pretty confused about how exactly I'm supposed to get the location/url. I set some breakpoints and I have never seen returnUrl to be something different from null which in this scenario seems pretty logical to me since it doesn't get value anywhere (unless I miss something of course).
So I really can't figure out how this work. I post the above just to show that I tried to do my homework, I investigate as much as I could but I didn't found an answer so I ask here. Could you provide explanation/example on how this actually work?

When using forms authentication and the user is not authenticated or authorized the ASP.NET security pipeline will redirect to the login page and pass as a parameter in the query string the returnUrl equal to the page that redirected to the login page. The login action grabs the value of this parameter and puts it in the ViewBag so it can be passed to the View.
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The View then stores this value in the form as shown by this line of code in the View.
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
The reason it is stored in the View is so that when the user does a Submit after entering their user name and password, the controller action that handles the post back will have access to this value.
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid && WebSecurity.Login(model.UserName, model.Password, persistCookie: model.RememberMe))
{
return RedirectToLocal(returnUrl);
}
// If we got this far, something failed, redisplay form
ModelState.AddModelError("", "The user name or password provided is incorrect.");
return View(model);
}
If the model state is valid and they are authenticated by calling the WebSecurity.Login method then it calls the method RedirectToLocal with the value of returnUrl which came from the View, which originally came form the login action that created the View.
The returnUrl value will be null if the user is not redirected to the login page as is the case when they just click on the login link at the top of the page in the default layout. In this case the user will be redirected to the home page after successful login. The whole purpose of the returnUrl is to automatically send the user back to the page they were trying to access before they were authenticated/authorized.

That's because the default ASP.NET MVC template is using Forms authentication, and controllers are decorated with [Authorize] attribute:
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
[Authorize]
public class AccountController : Controller
{
//...
}
That means that if the user is not authenticated it will be redirected to the logon page defined in the LoginUrl attribute of the forms element.
During the redirection, FormsAuthentication which is an HttpModule will append the url which was requested in the query string automatically.
So if you navigate to /Account/Login, you wont get anything in the query string since it is decorated with [AllowAnonymous] attribute.
But if you navigate to /Account/Manage you'll notice that the returnUrl in the query string becomes /Account/Manage (/Account/Login?ReturnUrl=%2fAccount%2fManage)
So you are not setting the returnUrl, the framework does it for you, you just use it in the AccountController to know where to redirect the user after he is authenticated.

When an unauthenticated user tries to get into a section of your application which requires authentication, then returnUrl comes into the picture. The Url requested by the unauthenticated user is basically stored in returnUrl.
You can go through the PluralSight tutorial: Building Applications with ASP.NET MVC 4

Related

Net Core - Cookie SameSite

I found the problem in my project. The problem is that the cookie is not saved when the user is logged in via the iframe. Cookies are saved when you log in to the site normally, that is, directly through the domain. There are 2 different problems for me right now:
When logging into the site directly (www.example.com), the relevant cookie is saved. But this cookie is saved as Lax. I want it to be saved as none.
If there is no direct login to the site before, if you want to log in from within the iframe, the cookie is not saved. I want to create cookies on logins made via iframe.
I did not perform anything on the cookie. I guess SignAsync() creates the relevant cookies automatically. I am also attaching my codes inside the Account Controller.
public IActionResult Login(string returnurl)
{
return View(new LoginViewModel {ReturnUrl=returnurl, IsPersistent=true });
}
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel model)
{
var result = await signInManager.PasswordSignInAsync(model.Username, model.Password, model.IsPersistent, true);
if (result.Succeeded)
{
return Redirect(model.ReturnUrl ?? "/");
}
else
{
ModelState.AddModelError("","Invalid User Login");
return View(model);
}
}
I also tried the solutions in the links below but it didn't work for me. Maybe I have applied these solutions incorrectly.
https://learn.microsoft.com/tr-tr/aspnet/core/security/samesite/rp31?view=aspnetcore-3.1&viewFallbackFrom=aspnetcore-6.0
https://learn.microsoft.com/tr-tr/aspnet/core/security/samesite?view=aspnetcore-6.0
And here is a photo:
Cookie View with Cookie Editor

This webpage has a redirect loop asp.net mvc4

I have a startup class with following code
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType="ApplicationCookie",
LoginPath = new Microsoft.Owin.PathString("/auth/login")
});
}
}
When I run my project showing me
The webpage at
/auth/login?ReturnUrl=%2Fauth%2Flogin%3FReturnUrl%3D%252Fauth%252Flogin%253FReturnUrl%253D%25252Fauth%25252Flogin%25253FReturnUrl%25253D%2525252Fauth%2525252Flogin%2525253FReturnUrl%2525253D%252525252Fauth%252525252Flogin%252525253FReturnUrl%252525253D%25252525252Fauth%25252525252Flogin%25252525253FReturnUrl%25252525253D%2525252525252Fauth%2525252525252Flogin%2525252525253FReturnUrl%2525252525253D%252525252525252Fauth%252525252525252Flogin%252525252525253FReturnUrl%252525252525253D%25252525252525252Fauth%25252525252525252Flogin%25252525252525253FReturnUrl%25252525252525253D%2525252525252525252Fauth%2525252525252525252Flogin%2525252525252525253FReturnUrl%2525252525252525253D%252525252525252525252Fauth%252525252525252525252Flogin%252525252525252525253FReturnUrl%252525252525252525253D%25252525252525252525252Fauth%25252525252525252525252Flogin%25252525252525252525253FReturnUrl%25252525252525252525253D%2525252525252525252525252Fauth%2525252525252525252525252Flogin%2525252525252525252525253FReturnUrl%2525252525252525252525253D%252525252525252525252525252Fauth%252525252525252525252525252Flogin%252525252525252525252525253FReturnUrl%252525252525252525252525253D%25252525252525252525252525252Fauth%25252525252525252525252525252Flogin%25252525252525252525252525253FReturnUrl%25252525252525252525252525253D%2525252525252525252525252525252Fauth%2525252525252525252525252525252Flogin%2525252525252525252525252525253FReturnUrl%2525252525252525252525252525253D%252525252525252525252525252525252Fauth%252525252525252525252525252525252Flogin%252525252525252525252525252525253FReturnUrl%252525252525252525252525252525253D%25252525252525252525252525252525252Fauth%25252525252525252525252525252525252Flogin%25252525252525252525252525252525253FReturnUrl%25252525252525252525252525252525253D%2525252525252525252525252525252525252Fauth%2525252525252525252525252525252525252Flogin%2525252525252525252525252525252525253FReturnUrl%2525252525252525252525252525252525253D%252525252525252525252525252525252525252Fauth%252525252525252525252525252525252525252Flogin%252525252525252525252525252525252525253FReturnUrl%252525252525252525252525252525252525253D%25252525252525252525252525252525252525252F
has resulted in too many redirects. Clearing your cookies for this
site or allowing third-party cookies may fix the problem. If not, it
is possibly a server configuration issue and not a problem with your
computer.
I cleared my cookie but still unchanged.
I agree with #StephenMuecke this is from a
endless redirect loop.
If the page you are trying to land need authentication to view, by either having [Authorize]
on the controller class or :
[Authorize]
public class AccountController:Controller
{
or at the controller ActionResult:
[Authorize]
public ActionResult Index
This will redirect the user to the login page.
If this does not allow anonymous authenitcation, it is immpossible for a user to land on the page
without being logged in.
[Authorize]
public ActionResult Login(string message, string returnUrl)
{
Hence the app keeps redirecting the user to the login page continously until there is
some type of overflow.
You need to use this:
[AllowAnonymous]
public ActionResult Login(string message, string returnUrl)
{
ReturnUrl=%2Fauth%2Flogin%3FReturnUrl%3D%252Fauth%252Flogin%253FReturnUrl%253D%25252Fauth%
The return url requires authentication, so login, which requires authentication.. and so on.
This same prinicple works throughout your entire project.

Ember + web api single page redirect

I have a asp.net mvc web api app with ember and simplemembershipprovider. I am using the ember template and with it, ember app is created upon user successfully logged in in the home controller.
public ActionResult Index(string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return View("App");
}
ViewBag.ReturnUrl = returnUrl;
return View();
}
Sometimes user would click a link in an email with an id when visiting the site, if the url includes an id, upon successful login, I want to redirect user to a detail page base on the provided id in the url. An example would be http://siteURL.com/#/product/1412 . I am having a hard time figuring out how to do this. Since this is a client side ember route, MVC does not differentiate between this route and http://siteURL.com so it just ignores the redirect request. Here is what I have tried.
assign the url in the login controller - nothing happens after json data is returned, stays in the login page and never hit the HomeController even though user is not authenticated.
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
returnUrl = "http://siteURL.com/#/product/1412";
return Json(new { success = true, redirect = returnUrl });
use response redirect. Same as #1
Response.Redirect(returnUrl);
Assigned url in home controller, same as above.
if (User.Identity.IsAuthenticated)
{
returnUrl = "http://siteURL.com/#/product/1412";
return View("App");
}
ViewBag.ReturnUrl = returnUrl;
return View();
Most browsers don't even send the # up to the server, so you won't have it to redirect. Here's a few options
Don't use the hash, not every browser supports it, http://emberjs.com/guides/routing/specifying-the-location-api/
Give them a fake address that redirects, http://siteURL.com/Redirect/product/1412
inject that url into some js on the page that redirects on load

user isn't authenticated in custom authorize attribute

I've made my own authorize attribute, and this is what it looks like
public class RedirectAuthorize : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "NotExist" }));
}
}
}
So if the user isn't authenticated, I want them to get redirected to the NotExist controller. I've debugged and it seems that unauthorized users get in the if clause, which is correct. But I've also tried doing this with logged in users, and they get in the if clause as well which is wrong.
I dont understand why this is happening. It makes me hesitate about whether my log-in didnt work. Is this the right way of logging a user in?
FormsAuthentication.SetAuthCookie(acc.username, false);
I've never made a log-in system in asp.net mvc before, so please tell me what I'm doing wrong.
Edit:
It seems that the default [Authorized] attribute isn't working either... I really think the problem lays in the log in:
[HttpPost]
public ActionResult Login(User acc)
{
if(ModelState.IsValid)
{
if (Validate(acc.username, acc.password))
{
FormsAuthentication.SetAuthCookie(acc.username, false);
return RedirectToAction("Index", "System");
}
}
ModelState.AddModelError("IncorrectDetails", "Wrong details. Please try again.");
return View(acc);
}
The custom authorize attribute looks correct.
Since you are setting the cookie yourself I would guess you are not using the built-in membership provider.
If you set the cookie yourself, you also need to read the auth cookie and set the Identity and Principal objects on each request. Otherwise, HttpContext.User.Identity.IsAuthenticated will always be false, which seems to be what you are experiencing.

MVC 4 Using Authorize with Custom Code Not Working

New to MVC 4. What I do not want to do is used the built-in Account management that comes with MVC 4. However, I have created an Account folder under Views, an AccountModel, and AccountController.
What I would like to do is restrict access to Views within the Account folder. for this, in my AccountController, I use the following:
[Authorize]
public class AccountController : Controller
{
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
public ActionResult bob()
{
return View();
}...
On my home page, I have a link to the bob view under the Accounts view which now reroutes me to the login page (which is correct).
Now, upon form submittal, with the right credentials (anything goes) I should be able to see bob, but instead I am redirected back to the Login because I was not authorized. The code:
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
return RedirectToLocal(returnUrl);
}...
I do not want to use the built-in connect to the DB, but rather what do I need to check the username against a string and then keep an authorization = true so that I can view bob?
In the long run, I plan on connecting to a DB and pulling info back with a SPROC, so right now, I just want the user to be authenticed based upon a string that is checked.
You continue to be Redirected until ASP.net sees a Forms Authenticated cookie.
FormsAuthentication.SetAuthCookie(theUsersNameasString, boolForSessionOrPersistentCookie);
Assuming your Web.Config is configured for Forms Authentication
<authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication>
ASP.Net will look for .ASPXAUTH cookie unless the name of this cookie was altered in WEB.CONFIG