Authorization with Session variables in asp net mvc 5 - c#

So my project requirements changed and now I think I need to build my own action filter.
So, this is my current login controller:
public class LoginController : Controller
{
// GET: Login
public ActionResult Index()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginViewModel model)
{
string userName = AuthenticateUser(model.UserName, model.Password);
if (!(String.IsNullOrEmpty(userName)))
{
Session["UserName"] = userName;
return View("~/Views/Home/Default.cshtml");
}
else
{
ModelState.AddModelError("", "Invalid Login");
return View("~/Views/Home/Login.cshtml");
}
}
public string AuthenticateUser(string username, string password)
{
if(password.Equals("123")
return "Super"
else
return null;
}
public ActionResult LogOff()
{
Session["UserName"] = null;
//AuthenticationManager.SignOut();
return View("~/Views/Home/Login.cshtml");
}
}
And this is my action filter attempt:
public class AuthorizationFilter : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (HttpContext.Current.Session["UserName"] != null)
{
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary{{ "controller", "MainPage" },
{ "action", "Default" }
});
}
base.OnActionExecuting(filterContext);
}
}
I have already added it to FilterConfig, but when I login it does not load Default.cshtml it just keeps looping the action filter. The action result for it looks like this:
//this is located in the MainPage controller
[AuthorizationFilter]
public ActionResult Default()
{
return View("~/Views/Home/Default.cshtml");
}
So, what would I need to add in order to give authorization so only authenticated users can view the applicationĀ“s pages? Should I use Session variables or is there another/better way of doing this using? I am pretty much stuck with AuthenticateUser(), since what happens there now is just a simple comparison like the one we have there now.
Thank you for your time.

Create an AuthorizeAttribute with your logic in there:
public class AuthorizationFilter : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
{
// Don't check for authorization as AllowAnonymous filter is applied to the action or controller
return;
}
// Check for authorization
if (HttpContext.Current.Session["UserName"] == null)
{
filterContext.Result = new HttpUnauthorizedResult();
}
}
}
As long as you have the Login URL Configured in your Startup.Auth.cs file, it will handle the redirection to the login page for you. If you create a new MVC project it configures this for you:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(
new CookieAuthenticationOptions {
// YOUR LOGIN PATH
LoginPath = new PathString("/Account/Login")
}
);
}
}
Using this you can decorate your controllers with [AuthorizationFilter] and also [AllowAnonymous] attributes if you want to prevent the authorization from being checked for certain Controllers or Actions.
You might want to check this in different scenarios to ensure it provides tight enough security. ASP.NET MVC provides mechanisms that you can use out of the box for protecting your applications, I'd recommend using those if possible in any situation. I remember someone saying to me, if you're trying to do authentication/security for yourself, you're probably doing it wrong.

Since your attribute is added to the FilterConfig, it will apply to ALL actions. So when you navigate to your MainPage/Default action it will be applying the filter and redirecting you to your MainPage/Default action (and so on...).
You will either need to:
remove it from the FilterConfig and apply it to the appropriate actions / controllers
or add an extra check in the filter so that it doesn't redirect on certain routes

Related

How to create a custom attribute that will redirect to Login if it returns false, similar to the Authorize attribute - ASP.NET MVC

I tried Googling a few things about custom attributes but I'm still not sure how to go about it....
I'm storing a few important details of the user in Session cookies (ex UserID) once the user log's in.. and all I want to do is create an attribute where if the
if (Session["UserID"] == null)
then it will redirect to login just like the [Authorize] attribute does. That way I can apply this attribute on the Controller level everywhere.
Should I overwrite the Authorize attribute? Create a new one? How do I get it to redirect to login as well?
I'm also using ASP.NET MVC 4
Thanks for any help
You can create a custom AuthorizeAttribute and override AuthorizeCore() and HandleUnauthorizedRequest() as required. Add your own logic which will do the check and redirect if necessary.
I'm just showing a simple example using MVC's ActionFilterAttribute (which is not the best place to do authentication/authorization)
public class VerifyUserAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var user = filterContext.HttpContext.Session["UserID"];
if (user == null)
filterContext.Result = new RedirectResult(string.Format("/User/Login?targetUrl={0}",filterContext.HttpContext.Request.Url.AbsolutePath));
}
}
Do not forget to set the Session["UserID"] variable in your /User/Login action method after proper user validation.
You can create your own version of the Authorize attribute by implementing the IAuthorizationFilter interface. Here's an example:
class MyCustomFilter : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Session["UserID"] == null)
{
filterContext.Result = new RedirectResult("/");
}
}
}
and a usage example:
[MyCustomFilter]
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}

Use Authorize Attribute to Verify Identity User Logged In

I'm creating a new ASP.NET web application and I'm not planning on making use of the concept of "roles". I do, however, want to make sure a user is logged in on certain pages. Is there any existing attribute that simply checks if a user is logged in and redirects them or throws an error if they're not? Every search I've done points to using roles (such as this one).
The [Authorize] attribute will only return successfully if the user initiating the request is logged in and will only work on controllers and action methods.
It can be used to decorate a particular action:
public class FooController : Controller
{
// only FooAction requires authentication in FooController
[Authorize]
public async Task<ActionResult> FooAction()
{
}
public async Task<ActionResult> BarAction()
{
}
}
...or an entire controller:
// all actions in FooController require authentication
[Authorize]
public class FooController : Controller
{
public async Task<ActionResult> FooAction()
{
}
public async Task<ActionResult> BarAction()
{
}
}
You also have Request.IsAuthenticated which can be used on both action and non-action methods:
if (Request.IsAuthenticated) //or #if in Razor
{
//request is authenticated
}
...and even User.Identity.IsAuthenticated as #Darko correctly pointed out in his answer. Personally, I prefer Request.IsAuthenticated over User.Identity.IsAuthenticated as it also provides some useful null-checks for User and User.Identity. Here's how Request.IsAuthenticated looks under the hood:
public bool IsAuthenticated
{
get
{
return(_context.User != null
&& _context.User.Identity != null
&& _context.User.Identity.IsAuthenticated);
}
}
You can use User property, just put if() where it can control access and that's it.
protected void Page_Load(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
Page.Title = "Home page for " + User.Identity.Name;
}
else
{
Page.Title = "Home page for guest user.";
}
}
This should work after you set the web.config . Here is the documentation https://msdn.microsoft.com/en-us/library/9wff0kyh(v=vs.85).aspx

Redirect To the log in page

I have an ASP MVC 5 web site, i have several controllers and views, how can i redirect the user aromatically to the Log-In view if he is not authenticated without preceding all the actions by if(User.Identity.Is Authenticated)
Decorate your controllers (if you want all actions within that controller to require authentication) or specific actions with the [Authorize] attribute. You can specify the login url the user gets redirected to in your web.config file.
[Authorize]
public class UserController : Controller
{
public ActionResult Index()
{
// Must be authorized
}
public ActionResult Users()
{
// Must be authorized
}
}
public class ProductController : Controller
{
public ActionResult Index()
{
// Doesn't require authorization
}
[Authorize]
public ActionResult Products()
{
// Must be authorized
}
}
Further reading:
http://msdn.microsoft.com/en-us/library/system.web.mvc.authorizeattribute(v=vs.118).aspx
For this task you can make use of the [Authorize] attribute, which you can implement at either the Class or Action level:
[Authorize]
public class AccountController : Controller
{
public AccountController () { . . . }
public ActionResult Register() { . . . }
public ActionResult Manage() { . . . }
public ActionResult LogOff() { . . . }
. . .
}
In the above instance attempting to access any action method in the controller will redirect the user to the login page, after which a further redirection to the initially requested action will be made.
For further information on how to use the Autohorize attribute please see the MSDN article, as it has expanded examples and background information.
You can use the events in the global.asax to authenticate and authorize on every request.
Application_AuthenticateRequest: Fired when the security module has established the current user's identity as valid. At this point, the user's credentials have been validated.
Application_AuthorizeRequest: Fired when the security module has verified that a user can access resources.
So, something like this (this isn't complete though)
protected void Application_AuthenticateRequest(Object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
// you can re-direct them for example
}
}
Answer 1 :
You can use inbuilt [Authorize] attribute in MVC..
[Authorize]
public class YourController : Controller
{
public ActionResult YourAction()
{
}
}
the [Authorize] attribute will check whether user is authenticated or not if not then it will redirect user to login page automatically
Answer 2 :
Or you can make your custom filter attribute as :
[AuthoriseUser]
public class YourController : Controller
{
public ActionResult YourAction()
{
}
}
public class AuthoriseUserAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
// Check user is authenticated
// if user is not authenticated then do as :
filterContext.Result = new RedirectToRouteResult(new
RouteValueDictionary(new { controller = "Login", action = "Index" }));
}
}
Answer 3 :
As you have said in your comments section that you don't want to write [Authorize] attribute on every controller in your project then below answer will help you :
public class YourController : Controller
{
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
//....Check user authentication here
}
}
public class MyController : YourController
{
public ActionResult Myaction()
{
// ...
}
}
In above answer all you have to do is to make your custom base controller YourController and then you can put your authentication stuff there and then every controller in your web app will inherit YourController instead of inbuilt base Controller class.

How to use the Authorize attribute both at the controller and action level?

I have implemented my own custom Authorize attribute.
The attribute is applied both at the controller level and at the action level.
Here is an example of what I need to do:
[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
[ClaimsAuthorize(Roles = "Administrators")]
public ActionResult AdministrativeTask()
{
return View();
}
public ActionResult SomeOtherAction()
{
return View();
}
}
Currently if a user has the Administrator Role but not the AdvancedUsers role, he cannot execute "Administrative Task".
How can I change this behavior to perform a security check at the action level even if the user is not authorized at the controller level?
For the moment, the only solution I can think about is to implement 2 attributes: one for securing controllers, another for securing actions. Then I would play with the Order property to execute the one at the action level first.
However, I would prefer a solution with a single attribute if possible.
Use built-in [OverrideAuthorization]:
[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
[OverrideAuthorization]
[ClaimsAuthorize(Roles = "Administrators")]
public ActionResult AdministrativeTask()
{
return View();
}
public ActionResult SomeOtherAction()
{
return View();
}
}
OverrideAuthorization Attribute is available for MVC 5 (at least) and up. Once you decorate the Action with it, also decorate with the new Role and that will take effect over the Controller level Role.
This should not be possible. Imagine the logic which MVC uses with the authorization filters.
When the controller is determined - check if there is an authorization filter that applies to that controller and execute it.
When the action is known - do the same for the action.
In all cases a fail in authorization would short-circuit the pipeline.
To make specific actions restricted you simply use the Authorize-attribute on the methods that handle these actions.
When you mark an action method with the Authorize attribute, access to that action method is restricted to users who are both authenticated and authorized.
//[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
{
[ClaimsAuthorize(Roles ="Administrators", "Role2","Role3")]
public ActionResult AdministrativeTask()
{
return View();
}
}
OR you can override your authorization at controller level ,
Create a new OverrideAuthorizeAttribute attribute.
public class OverrideAuthorizeAttribute : AuthorizeAttribute {
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
}
}
and you can use this attribute to override your controller level autorization.
[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
[ClaimsAuthorize(Roles = "Administrators")]
public ActionResult AdministrativeTask()
{
return View();
}
[OverrideAuthorizeAttribute(Roles ="xxxx")] // This role will override controller
//level authorization
public ActionResult SomeOtherAction()
{
return View();
}
}
You need two authorization attributes - a base one with all authorization logic, and a second one, derived from the base attribute, that is only used to override the base attribute.
Example authorization attributes:
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
protected bool _canOverride = true;
//...custom authorization code goes here.....
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
//Don't authorize if the override attribute exists
if (_canOverride && actionContext.ActionDescriptor.GetCustomAttributes<OverrideClaimsAuthorizeAttribute>().Any())
{
return;
}
base.OnAuthorization(actionContext);
}
}
public class OverrideClaimsAuthorizeAttribute : ClaimsAuthorizeAttribute
{
public OverrideClaimsAuthorizeAttribute ()
: base()
{
_canOverride = false;
}
}
In the base authorization attribute we are saying to go ahead and authorize as normal, as long as the OverrideClaimsAuthorizeAttribute doesn't exist. If the OverrideClaimsAuthorizeAttribute does exist, then only run the authorization on classes where _canOverride is false (ie the OverrideClaimsAuthorizeAttribute class itself).
Example usage:
[ClaimsAuthorize(Roles = "AdvancedUsers")]
public class SecurityController : Controller
{
//Ignores the controller authorization and authorizes with Roles=Administrators
[OverrideClaimsAuthorize(Roles = "Administrators")]
public ActionResult AdministrativeTask()
{
return View();
}
//Runs both the controller and action authorization, so authorizes with Roles=Administrators AND Roles=AdvancedUsers
[ClaimsAuthorize(Roles = "Administrators")]
public ActionResult AdvancedAdministrativeTask()
{
return View();
}
//authorizes with controller authorization: Roles=AdvancedUsers
public ActionResult SomeOtherAction()
{
return View();
}
}
Check this previous question. (check #AndyBrown answer, case 2)
For a simple way you might also try adding (
[AllowAnonymous]) to override the controller
[Authorize]
then add a new custom filter to check for your logic for this particular action. Or you can add the code that checks for the role just inside it.

ASP .NET MVC Secure all resources

How to enable Authentication on whole controller and disable only for certain action methods. I want authentication for all resources. If I write something like that:
[Authorize]
public class HomeController : BaseController
{
//This is public
[UnAuthorized]
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
//This is private resource
public ActionResult PrivateResource()
{
return View();
}
}
Then anyone can access this resource. I need this because we have all resources are private and very few are public on our project. Do you have any ideas how to make it better way?
Organize your controllers accordingly. Have a base controller for all authenticated resources which you could annotate with the [Authorize] attribute and another one for public resources.
[Authorize]
public abstract BaseAuthenticatedController : Controller
{ }
public abstract BaseController : Controller
{ }
Based on solution which is found here I wrote the code that fixes exactly what I wanted.
Create custom authorization attribute base on AuthorizeAttribute and override method OnAuthorization:
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext != null)
{
object[] attributes = filterContext.ActionDescriptor.GetCustomAttributes(false);
if (attributes != null)
{
foreach (var attribute in attributes)
if (attribute is UnAuthorizedAttribute)
return;
}
}
base.OnAuthorization(filterContext);
}
I'm using a reflection here to recognize an action with UnAuthorized attribute. I don't know about performance issues in this case, but it solves the problem completely.
It's really strange that no one said about AllowAnonymous attribute which services for such situations:
[Authorize]
public class HomeController : BaseController
{
//This is public
[AllowAnonymous]
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
return View();
}
//This is private resource
public ActionResult PrivateResource()
{
return View();
}
}

Categories