This is the default index function of my home controller
public ActionResult Index()
{
if (User.Identity.IsAuthenticated)
{
return NewPosts();
}
else
{
ViewBag.Message = "Welcome!";
return View();
}
}
and this is the newposts function in the same home controller file
public ActionResult NewPosts()
{
return View();
}
I have log onto my account and I close my browser. Then I reopen it visiting the same index page, I see my identity (Welcome myusername) but the newposts function is not called and thus it doesnot display the newposts view as expected.
Why is that ? How can I fix this ?
Thank you.
I think a better way of getting this to work would be setting up a default page as 'NewPosts' for the site via the web.config. Then in your web.config, you can set the failed login page as 'Index'. This will cause users once they are log in to be sent to the 'NewPosts' page. If they close the browser (and their authentication cookie has not expired) then they will be sent to the 'NewPosts' page as well. If they are not logged in, then they will be kicked to the 'Index' page. Your if statement in your Index action method would no longer be required, as the web config forms authentication takes care of this for you in a more robust way. Here is an example of what the web config could look like:
<authentication mode="Forms">
<forms loginUrl="~/Home/Index" timeout="2880" defaultUrl="~/Home/NewPosts" >
</forms>
</authentication>
See here for more web.config info concerning forms authentication.
The problem is not about the controller, it's about caching of your browser.
If you hit Ctrl+F5 on the first page, it should recognize you as unauthorized.
I know this is not a real solution to force website visitors to hit Ctrl+F5 to refresh their browsers. There are many article in internet to tackle this kind of caching behavior, serach for them.
Two important points about your code:
1- Change return NewPosts(); to:
RedirectToAction("NewPost");
2- Decoreacte NewPosts method with [Authorize] attribute:
[Authorize]
public ActionResult NewPosts()
{
return View();
}
Related
When my AuthorizeAttribute is called, it sends the page to login like it should. But when login is completed, it goes out to home/index. This is super annoying. How can I keep that from happening?
Since the code path never goes into my controller, I don't have any control of what it's doing.
Using forms authentication, when you access a page that requires authentication, ASP.NET will redirect you to the login page, passing in the ReturnUrl as a parameter.
So, all you need to do is use that parameter to return the user to the place it was before.
public ActionResult Login(string username, string pass, string returnUrl)
{
// code to authenticate user here...
if (!string.IsNullOrEmpty(returnUrl))
return Redirect(returnUrl);
return RedirectToAction("Index", "Home");
}
You might also want to consider using FormsAuthentication.RedirectFromLoginPage
Redirects an authenticated user back to the originally requested URL or the default URL.
https://msdn.microsoft.com/en-us/library/ka5ffkce(v=vs.110).aspx
Notice that calling this method will also issue the authentication cookie, that you might be already doing. So you have to check you are not doing this twice.
Edit: See https://stackoverflow.com/a/1206728/722778
Perhaps you are generating your form specifying a controller an action (e.g. Html.BeginForm("Logon", "Account")?
In that case, try with only this in your view:
Html.BeginForm()
Or passing the ReturnUrl parameter yourselve:
Html.BeginForm("LogOn", "Account", new {ReturnUrl = Request.QueryString["ReturnUrl"] })
I am really having hard time working with Authorize; After checking the username and password of a registred user, the user should be redirected to the account page. In the account Controller I am using Authorize attribute as following:
[Authorize]
public ActionResult Index(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
The thing is if I compile the code and try to login with the right username and password, I will get an HTML 401 unauthorized error which is wierd!.
I tried to read a bit about it, in a book of Jon Galloway called Professional ASP.NET MVC 5, he explained that Web.config should be also edited when using [Authorize] (i dont know if i got it right!). So i tried to edit Web.config as following:
<authentication mode="Forms">
<forms loginUrl="~/Home/Login" timeout="2880" />
</authentication>
Now, i dont get the error anymore but when I change the url, Iam able to see the account page without to login which is bad and means that [Authorize] attribute is not working.
I Know that Authorize works with Roles and Users, i could write for example [Authorize(Uers = "blabla")], But the thing in my application that all users that are registred in the EF DB are able to see the account page.
Anyone can help me to solve this problem please:)?
Here you have the code of my login Form
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModels lgm)
{
if (ModelState.IsValid)
{
// Check if username exist
var dbUser = db.RegisterTables.FirstOrDefault(x => x.tUserName.ToLower().Equals(lgm.username));
if (dbUser != null)
{
if (Security.IsCorrectPassword(lgm.password, dbUser))
{
FormsAuthentication.SetAuthCookie(lgm.username, true);
return RedirectToAction("Index", "Account");
}
else ModelState.AddModelError("", "Check user or pass.");
}
else ModelState.AddModelError("", "Check user or pass.");
}
return View(lgm);
}
The code of the /Account/Index is just a normal ActionResult thats returns the view of the account.
Please bear with me as I am pretty new to designing websites.
When someone goes to my website they are initially sent to a log in page, which is defined in my web.config as:
<authentication mode="Forms">
<forms loginUrl="~/Login/Index" timeout="15"/>
</authentication>
However, before they log in I check whether the database they want to access has been defined (this is something that users may want to change frequently), and if it has not I want to send them to a different form. So, my login controller index looks like:
public ActionResult Index()
{
bool settingsSetUp = SupportLibrary.Settings.CompanyId != null;
if (settingsSetUp)
return View();
else
return RedirectToAction("index", "setup");
}
However, when I try this I always get "This page has a redirect loop" in Chrome. The page will not display in Firefox of IE either. On investigation the above method is always being called numerous times, so that eventually the browser decides it is being redirected too often. If I just set it to go to the view associated with the controller (no redirection) it calls the above method 15 times. Otherwise it is called 10 times before Chrome displays the error message.
Does anyone know why it is being called so many times as I think that is the root of the problem? Many thanks!
You are trying to load actions that require the user to be authenticated (they either have the Authorize attribute on them or it has been applied globally) which is causing a redirect back to the login action.
Check your actions to ensure that they can be accessed without being logged in if required.
I have an MVC4 application with Membership logon (through FormsAuthentication).
This is defined in web.config as follows.
My default url is home root (~/):
<roleManager enabled="true" />
<authentication mode="Forms">
<forms defaultUrl="~" loginUrl="~/Account" />
</authentication>
In my AccountController in the Login post method, following code is relevant.
This code is executed when the user clicks on the login with valid credentials.
if (Membership.ValidateUser(creds.Username, creds.Password))
{
FormsAuthentication.RedirectFromLoginPage(creds.Username, false);
return null;
}
Now, if I'm navigating (anonymously) to: ~/Admin, I get redirected to ~/Account to log in, which is perfect. I can see that the url is formed as follows:
http://localhost:23759/Account?ReturnUrl=%2fAdmin
But, when I succesfully login, I get redirected to home (~/) instead of ~/Admin
Please help!
Many thanks!
Edit: Found the actual issue: it was the post method that wasn't receiving the querystring
I found the solution!
Thanks to FlopScientist, who got me thinking further.
It was indeed because I was doing a POST method, which did not take the QueryString from the GET into account.
First I had this in my View:
#using (Html.BeginForm("Index", "Account")
{
<div class="LoginBox">
//Etc...
</div>
}
I have updated it to following:
#using (Html.BeginForm("Index", "Account", new { ReturnUrl = Request.QueryString["ReturnUrl"] }, FormMethod.Post))
{
//Etc...
}
Now I can actually see a querystring in my debug and I do get a correct redirect!
There doesn't seems any issue with your Return URL: [ %2f is / ] localhost:23759/Account?ReturnUrl=%2fAdmin
So, what remains is to do some checks as to what is causing such behaviour.
1.) Are you sure that the return page as specified in the return url:
localhost...?ReturnUrl=%2fAdmin
actually exists and your user has access to it?Here Admin is a folder, so you must have a page default.aspx inside this folder. If it does not exists, RedirectFromLoginPage by default will send you to DefaultURL.
2.) Also, Try using FormsAuthentication.GetRedirectUrl() method to see what happens.
if (Membership.ValidateUser(creds.Username, creds.Password))
{
Response.Redirect(FormsAuthentication.GetRedirectUrl(username, false));
}
3.) OR does this works ? [ Recommended for debug purposes ]
if (!string.IsNullOrEmpty(Request.QueryString["ReturnUrl"]))
{
Response.Redirect("~/Admin");
}
Lastly make sure there are NO such code lines redirecting user to other pages/DefaultURL.
It probably because that path is not detected as same app path:
By default, the ReturnUrl variable must refer to a page within the
current application. If ReturnUrl refers to a page in a different
application or on a different server, the RedirectFromLoginPage method
redirects to the URL in the DefaultUrl property. If you want to allow
redirects to a page outside the current application, you must set the
EnableCrossAppRedirects property to true using the
enableCrossAppRedirects attribute of the forms configuration element.
from: http://msdn.microsoft.com/en-US/library/1f5z1yty.aspx
I'm trying to setup Forms Authentication in an asp.net mvc 2 application that will be hosted on IIS 6. There's an issue somewhere in my routing, but I can't pinpoint exactly where it is.
Here is the route entries I'm using to route the mvc requests through the aspx processing on IIS 6. These may or may not be the "right" way, but they do work on the server at current.
routes.MapRoute(
"Default",
"{controller}.aspx/{action}/{id}",
new { action = "LogOn", id = "" }
);
routes.MapRoute(
"Root",
"",
new { controller = "Main", action = "LogOn", id = "" }
);
I've put the [Authorize] attribute on my Main controller.
In my web.config I have:
<authentication mode="Forms">
<forms loginUrl="~/Main.aspx/LogOn" timeout="2880"/>
</authentication>
When the application starts, a blank page loads. The page is quite literally blank. I haven't found a way to amend the loginUrl to actually execute the LogOn action & View for my Main controller.
Edited
Just as an fyi, I've setup my routing based on this article so that the mvc routing can work on IIS 6.
http://www.asp.net/mvc/tutorials/using-asp-net-mvc-with-different-versions-of-iis-cs
I'm guessing the problem here is that the windows form authentication settings aren't syncing with the routes setup so the app can run on IIS 6 via the aspx extension.
Anyone have thoughts on how I could fix this?
Edit 2
Tried adding the following route:
routes.MapRoute(
"Login",
"Login",
new { controller = "Main", action = "LogOn" }
);
Amended the web.config to:
<authentication mode="Forms">
<forms loginUrl="~/Login" timeout="2880"/>
</authentication>
The result is the same white screen as I originally got. It seems like the page doesn't get processed at all. Viewing the source from page generated shows absolutely nothing....no markup...no html declaration....just nothing.
EDIT 3
It seems that I can't seem to get the correct routing configured with the default forms authentication via the web.config. To circumvent this, I've created my own Authorize attribute class. At current, I only care that the user has logged into the system. To accomodate this, I moved the LogOn & LogOff actions to an Account controller. I've remapped the root path to point to this controller. In my custom Authorize attribute, I check to see if the user is logged in and redirect them back to the LogOn page if they aren't. Here is the code:
routes.MapRoute(
"Root",
"",
new { controller = "Account", action = "LogOn", id = "" }
);
And here's the code for the RequireLoginAttribute class I derrived.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class RequireLoginAttribute : AuthorizeAttribute, IAuthorizationFilter
{
#region IAuthorizationFilter Members
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.Request.IsAuthenticated)
{
//This didn't work...it would try routing to urls like
//http://localhost:1524/Main.aspx/Account.aspx/Logon
//new RedirectResult("Account.aspx/Logon");
//This seems sloppy to me somehow, but it works.
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Account", action = "LogOn" }));
}
}
#endregion
}
Now, I can just apply the [RequireLogin] attribute to the Main controller and it ensures the user must be authenticated.
For the curious, and completeness of this scenerio, I am using the following code in the LogOn action (repository isn't ready yet so things are hard coded):
public ActionResult LogOn(LogOnModel login, String returnUrl)
{
if (ModelState.IsValid)
{
FormsAuthentication.SetAuthCookie(login.UserName, false);
return Redirect(returnUrl ?? Url.Action("NextPage", "Main"));
}
else
{
return View(login);
}
}
The returnUrl is a throwback to the Windows Forms authentication. Since I can't seem to get that working here, the parameter will always be null.
Please, critique this if you see specific areas that need improvement. I'm reading what I can and trying to do things right, so all input is greatly appreciated. Thanks!
If you need the .aspx for the Default Root then why don't you need it for the login route ?
You could do a couple of things then
Actually create a ASP.NET page called Login.aspx and put it in the root of the folder (Authentication will work for your mvc pages as well)
Change your login route to say
routes.MapRoute("Login","Login.aspx",new { controller = "Main", action = "LogOn" });
You should also take a look at to see what route your actually hitting at any time.
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
Remember that the order you write your routes in Global matters. It stops checking when it finds one that works so your catch all should be last.
The details I posted in EDIT 3 summarize the solution to this issue. I appreciate all of your input into this question, but I've resolved it. I would have liked to have gotten the "out of the box" forms authentication working, but this solution serves well enough. If we move to IIS 7, I think all of this will become moot anyhow.
Thanks again for your help guys.