I'm building a small app with ASP.NET MVC and I'm using the ASP.NET membership provider for handling users. Hooked this up to the login page of the basic MVC template.
What is the best practice for checking a valid authentication globaly? I basically want to redirect to the front page or the login page if the user's not authenticated on all my pages.
-anders
The way we did it, back in the days of MVC Preview 4 or so, was to create a new "BaseController" class, which every other controller then inherits from. This BaseController class uses the Authorize attribute
[Authorize]
public class BaseController : Controller
{
...
}
The rest of our controllers then inherited from this one
public class HomeController : BaseController
{
...
}
Haven't had to work with MVC for a few months now, so I can't say if this is still applicable, so proceed with caution...
You should just annotate any action you want to authenticate with [Authorize], and optionally with some required roles:
[Authorize()]
public ActionResult Index() {
...
return View();
}
This includes your home page action, if you wish. Unauthorized attempts will be always redirected to the login page.
this may be slightly over complicated, but another approach could be to put a custom HTTP Module in the pipeline to redirect the request if the user isn't authenticated.
Related
I am developing a ASP.NET MVC 5 website which uses local STS for authentication.
I subclassed the AuthorizeAttribute to customize authentication/authorization process, added MyAuthorizeAttribute to GlobalFilters.
When user came in without authenticated, MyAuthorizeAttribute.OnAuthorize successfully caught it and create a SignInRequest to redirect to STS. That is what I want.
I observed that when user authenticated successfully and STS redirected user back, user's browser POSTed a SAML token embedded in request body to my MVC web application, this is by design, and I expected MyAuthenticateAttribute could catch this request, so I can extract the token from request body, check and validate it, however, MyAuthenticateAttribute.OnAuthorize() function didn't get called this time, it directly went to controller.
So is there anything wrong? Where should i catch and handle the token POSTed from user? Thanks.
You need to decorate your action method with [Authorize] attribute or if you want authorization to happen for all actions in a controller, then set that attribute on the controller itself.
Also take a look at the usage of [AllowAnonymous] at https://www.codeproject.com/Articles/1008731/Insight-of-ASP-NET-MVC-s-Authorize-Attribute
AuthorizeAttribute is both an Attribute and a IAuthorizationFilter. Attributes don't actually do anything, the MVC framework scans for where this attribute is added and registers it as a filter on the fly.
However, rather than decorating controllers or action methods with it, you could add it as a global filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizationAttribute());
filters.Add(new HandleErrorAttribute());
}
}
By the same token, you can create your own IAuthorizationFilter or subclass AuthorizeAttribute to do whatever you want. If registered globally, it will always run for all actions and then you can use it to do custom authorization of requests globally.
Is good idea to get user identity in ASP.NET Web API controller constructor, for example:
public PagesController(PageValidator pageValidator, PageMapper pageMapper, PagesManager pagesManager, UsersManager usersManager)
:base(usersManager)
{
_pageValidator = pageValidator;
_pageMapper = pageMapper;
_pagesManager = pagesManager;
if (User.Identity.IsAuthenticated)
_pagesManager.UserId = usersManager.GetByEmail(User.Identity.Name).Id;
}
Is always User.Identity was correct populated before this call raise?
This has bitten me a few times. Depending on where/how you are performing your authentication, you need to be careful where you access your identity, particularly in controller constructors.
For example, whilst the controller action is invoked AFTER an IAuthenticationFilter is instantiated, the controller's constructor is called before AuthenticateAsync; meaning any authentication you do in AuthenticateAsync will not be available in your controller's constructor (like in your example).
I typically don't rely on things being available during controller construction (unless handled by DI). Instead access the identity as you need it in your controller actions.
If you are looking at making identity lookup easier (i.e. pulling in your user object based on the User.Identity.Name property) create a base controller class that has a property or method that does it for you, then have your controllers inherit from that...
public User AuthenticatedUser
{
get
{
if (User.Identity.IsAuthenticated)
{
return usersManager.GetByEmail(User.Identity.Name);
}
return null;
}
}
EDIT
See here for a detailed breakdown of the Web.API lifecycle, showing controller creation occurring prior to authentication.
Yes. You can use this property in Controller in any place. ASP.NET has request pipeline: (http://www.dotnetcurry.com/aspnet/888/aspnet-webapi-message-lifecycle).
As you can see Authorization is early stage step in request pipeline.
Controller creation is the latest stage.
I have two controllers;
AccountController : Controller //For accounts <-- MVC
ItemController : ApiController //For Items <-- WEB API
The accounts controller is for all intents and purposes a pretty standard implementation of the Accounts code, the only major difference is that it's using a Custom MembershipProvider. On the accounts controller I also have one other Action:
[Authorize]
public ActionResult Bleh(){ return View(); }
Which if I attempt to get to:
http://localhost/Account/Bleh
Redirects me (as expected) to the Login page, which after logging in, returns me back to the Bleh page. All good. The problem is on the ItemController, I have an Action which too has an Authorize attribute on it:
[Authorize]
public HttpResponseMessage PostItem(Item item) { /**/ }
Going to this before logging in returns a 401 - Unauthorized - which again is as expected, but after logging in, it still returns a 401. I can't see why this is the case.
Am I missing any configuration elements? Routing? N.E. Other?
I was under the impression that Web Api would pick up the Forms Authentication in the same way as MVC, and I know the authentication is working as the MVC one is working.
Make sure that in the web.config hosting your API controller you have defined the authentication scheme:
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2400" />
</authentication>
or if you are using some other kind of custom authentication scheme that you are tracking users differently you might need to write a DelegatingHandler. Here's an example I wrote for Basic Authentication: https://stackoverflow.com/a/11536349/29407
I have rebuilt the application from scratch, and the forms code is working as expected now. I cannot for the life of me see any difference between my original code and the new code. I suspect maybe something in a config file somewhere, but after a pretty substantial amount of time it eludes me.
You can override OnRedirectToLogin Identity event and return response accordingly based on the fact that it is an API call (based on '/api/' in url)
I need to implement CSRF(Cross Site Request Forgery) Guard in my code (asp.net).
Though I got a library from OWASP, implementing it is a pain since no documentation is given. Can someone provide me an easier way to implement csrf guard in .net, or configure OWASP library correctly ?
Thanks
-Chandan
ASP.NET MVC
If you're using asp.net mvc you can use the anti-forgery token. Basically in your view you would place the following code:
#Html.AntiForgeryToken()
And on your controller you would put this attribute at the top of the controller:
[ValidateAntiForgeryToken]
public ActionResult Foo()
{
// Foo code
}
What this does is ensures that the user cannot submit the form from a remote site, because they are unable to generate the token. You can also create a token with a salt.
ASP.NET WebForms
For asp.net Webforms you can override the OnInit method and set the ViewStateUserKey to the the session id. Web forms will validate the viewstate with a MAC check thereby acting like an anti forgery token. Because an attacker cannot generate a valid viewstate (since they don't have the ability to generate a valid MAC because they can't put the session id in the viewstate) the MAC will fail. You will have to do this on each page, or create a base class that already overrides oninit and does this.
public partial class Default : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.ViewStateUserKey = Session.SessionID;
}
}
In rails I could do something like this to make sure a user is authenticated before accessing an action in the controller:
before_filter :checked_logged_in, :only => [:edit, :update]
I was wondering if ASP.NET MVC had something similar or if there was a framework out there that could essentially do something like the following:
For certain methods with actions that take a certain parameter, I want to point the action to a method, check to see if the user owns that object, and if so, proceed to the controller action. If not, I want to redirect him to another action where I can show him he has invalid credentials.
So basically I am looking for a sort of "before_filter." Anyone know of anything out there that can do this? Thanks!
They are called Action filters in ASP.Net MVC, you can read more here http://www.asp.net/mvc/tutorials/understanding-action-filters-cs.
Asp.net MVC comes with an Authorize filter to indicate actions that requiere the user to be authenticated.
Usage:
[Authorize]
public ActionResult Index()
{
}