In my .Net MVC application, I have default controller, which anyone should have access (as it contains the welcome page, register, login, password reset methods etc). All the other controllers have been inherited from a controller with authorize attribute.
I can browse to default/index, and default/register pages(i.e. any request of GET type). But any POST request to a default controller action acts like they need authorization. For example, when the user enters email/password and click login, it makes a POST request to default/login.
I tried with setting location paths in webconfig but still no luck. I have noticed that every POST request returns the form authorization cookie with empty in its value, while GET requests do not send back auth cookie.
Any idea what I have missed?
Thanks a lot in advance :)
Anuruddha
You can try with this
[HttpPost]
[AllowAnonymous]
public ActionResult Index()
{
//...
}
Related
When I first started developing my MVC app (which requires authorization, to selectively render a SPA, which in turn does it's own authorization via ADAL.js) I simply decorated the HomeController's Index method with [Authorize] like thus,
[Authorize]
public ActionResult Index(bool ok = false)
{
return View();
}
and everything works fine.
However, sometimes I want users to share URLs with each other. My SPA uses hash-based routing to render various states. As long as both users are logged in already, they can share links with each other and everything magically works ok.
But, if the user clicking a link is yet-to-login, we lose the state communicated in the URL.. everything after the hash.. e.g. if user A sends unauthenticated user B this URL: http://mycorp.com/#/orders/85/edit the HomeController's going to notice user B is unauthenticated, and the middleware is going to kick user B over to our Microsoft login page.. and when he redirects back, the critical #/orders/85/edit portion of the URL in is gone.
My solution was to remove the [Authorize] attribute from the Index action, and instead do something like this:
public ActionResult Index(bool ok=false)
{
if (!User.Identity.IsAuthenticated)
{
if (!ok)
return View("SetCookie_Then_RedirectWith_OK_InQueryString");
if (ok)
//how do I do this part?
return new RedirectResult(Microsoft.Owin.Security.OpenIdConnect.Url);
}
else
//now we're authenticated,
//let JS resume by looking for cookie set previously
return View("Index");
}
Notice the how do I do this part comment above. That's my question.
+++++++++ FWIW ++++++++++
My app features a Startup.Auth.cs file with the familiar middleware declared...
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
...blah...
}
);
I presume I can do something fancy here in Startup.Auth.cs w/Notification Handlers but, I was hoping to directly call the middleware into action from the Index method.
I have a simple MVC application - a list of employees, buttons to delete the employee, and login screen
When the user presses the button to delete the Employee they are requested to Login
This takes them away from the EmployeeController to an AccountController that handles the login. The returnUrl is also passed to this. The user gets authenticated successfully and the Account controller goes to Redirect to the ReturnUrl and this is where it throws a 404.
The returnUrl = /Employees/Delete/127 - the id of the employee. As far as I can see this is correctly configured in the controller and RouteConfig.
When I remove the [Authorise] attribute it works just fine. So I suspect it must be with the redirect but I do not understand why?
EDIT:
I also tried HttpPost in the using FormMethod.Post in the view but it made no difference but after leaving the Login I don't know it it os post or get - or could the Redirect to the return url be generating a Get and not a post?
EDIT AGAIN: Thinking about this it is probably not a good design. I am requesting the user to Authorize after they have pressed the delete button. I should probably not expose the delete button unless they are already Authorized but is it possible to do anyway?
I think this might be because Delete action is HttpPost and when redirecting you are issuing a GET to Employee/Delete
Change the [HttpPost] attribute to [HttpGet]. Redirecting will invoke the Get Method
I'm in the process of creating an Intranet site using Windows Authentication.
Maybe I'm not going about this the best way, but I'm trying to load partial views via calling a controller method that has an Authorize action filter wrapped around it, so that only authorized individuals are able to see that portion of the page. Say, for instance, I wanted to load administrator tools onto the page but only if the logged-in individual is an administrator.
So on the index.cshtml page I might have something like:
#Html.Action("LoadAdminTools","ControllerName")
The Controller would contain the code:
[Authorize(Roles="Admins")]
public ActionResult LoadAdminTools()
{
return PartialView("_AdminToolsPartialView");
}
And then the partial view containing the admin controls (or whatever) would render to the page - only if the logged-in user was part of the Admins role.
The 'problem' I'm having is that if the person logged-in is not authorized to load the partial view, the browser pops up the login dialog asking for the user's credentials. Closing the dialog without inputting any credentials causes the expected results - the partial view doesn't load while the rest of the page does. Cool, but annoying. Input the incorrect credentials and you get a 401 error - also as expected.
If it helps: In IIS, Anonymous Authentication is disabled, Windows Authentication is enabled.
"Automatic logon with current user name and password" is selected in Internet Options under "Security Settings - Local Intranet Zone."
My question is this: Is there a way to use the [Authorize] action filter to load a partial view (or to do anything, really) without the browser asking the user to log in? Just have it take the current logged-in credentials, check if they comply with the action filter, if they do, load the partial view, if not, then don't. If there isn't, is there simply a better way of going about what I want to accomplish here?
UPDATE
Beautiful. I read the solution to the question you posted, Mystere Man, created a new class inside the Controller's folder called IntranetAuthorizeAttribute.cs, threw in the code:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class IntranetAuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAuthenticated)
{
filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult(403);
}
else
{
base.HandleUnauthorizedRequest(filterContext);
}
}
}
Replaced the Authorize filter with my new IntranetAuthorize filter:
[IntranetAuthorize(Roles="Admins")]
public ActionResult LoadAdminTools()
{
return PartialView("_AdminToolsPartialView");
}
And now it loads the page just fine with no browser login dialog - with the partial view when it's an authorized user, and without the partial view when it is not an authorized user =)
Thank you!
Unfortunately, ASP.NET (and thus MVC) conflates Authorization and Authentication in may scenarios.
Check this question for a solution.
Why does AuthorizeAttribute redirect to the login page for authentication and authorization failures?
I just want to ensure they are logged in before running any code.
I found User.Identity.IsAuthenticated Which can be used for boolean to check login. But if I did redirect, it would still run code, plus I would have to put it everywhere?
In ROR there was a before_filter option we did, that checked at the top of each controller, and wouldnt run it otherwise.
Please can someone guide me on how to do this.
You can use AuthorizeAttribute for this:
When you mark an action method with AuthorizeAttribute, access to that
action method is restricted to users who are both authenticated and
authorized. If you mark a controller with the attribute, all action
methods in the controller are restricted.
The Authorize attribute lets you indicate that authorization is
restricted to predefined roles or to individual users. This gives you
a high degree of control over who is authorized to view any page on
the site.
If an unauthorized user tries to access a method that is marked with
the Authorize attribute, the MVC framework returns a 401 HTTP status
code. If the site is configured to use ASP.NET forms authentication,
the 401 status code causes the browser to redirect the user to the
login page.
For example:
[Authorize]
public ActionResult DoSomething()
{
// ...
}
At the top of your controller class, write this :-
[Authorize]
public class StoreManagerController : Controller
Use the Authorize Attribute.
[Authorize]
public ActionResult About()
{
return View();
}
This is my application's current workflow for user registration.
register form ( GET /register )
submit the form ( POST /register )
after success, redirect route to "/registerSuccess"
in (GET /registerSuccess ) view, I want to show the message like "username has been registered successfully".
Controller Actions:
public ActionResult Register()
{
return View();
}
[HttpPost]
public ActionResult Register(string name, string password, string confirmPassword)
{
TempData["registered_user"] = name;
return RedirectToRoute("RegisterSuccess");
}
public ActionResult RegisterSuccess()
{
return View();
}
RegisterSuccess View
<h2><%: TempData["registered_user"] %> has been registered successfully.</h2>
It is working fine except the username is empty when user refresh the page (GET /registerSuccess).
Is it normal behavior in other applications? or Should I do something about it? :) (It is my pet project and requirements come from me :P )
update: Actually, there is one more step which is registered user required admin's approval. So, I can't let user log in after successful register. I'm currently using cookie-based FormsAuthentication to track logged in user.
I prefer to use PRG pattern rather than showing flash message in the submit form.
that is normal behaviour.. when the user 'refreshes' the page is requested directly not through your Register function so registered_user key is gone by then. When you do the initial registration you should use a session marker (say a cookie) to track a successfully logged in user.
Using cookies tutorial is a good place to start
If you were to use HTTP authentication (say Basic Auth) then the browser submits the username and password (in clear text for basic auth) with every request that sends out a 401 Unauthorized (see HTTP/1.0 Protocol)
Hmm...
Normally you should think of a SSO solution, that holds your User's authentication (token).
then you would just need to display the current authenticated user (as a completed registration normally logs in the user)
other solution would be, to add the user in the url, so that the success page has all parameters.
/registerSuccess/<username>
(and maybe check, that the logged in user is just registered, and is the same)
for your own fun project, i would do the second one. ist just plain simple.