Assume like this is my SampleController action method
public ActionResult AdminView()
{
return View()
}
If want this controller method to be called if the logged in user belongs to admin role, otherwise this method call should be blocked and the user should get an some custom unauthorized access error page.
In my asp .net mvc web application, when the user logs in, I am storing the user role in a session as a string. And whenever there is a need to validate the user role, I compare the value stored in the session against a constant say "ADMIN_ROLE". But I am writing that piece of code to check for the user role in almost every controller action method and then either return an appropriate view for the user or an unauthorized access page view if the user role is restricted for the controller action method.
I googled and read that we can use something like this.
[Authorize(Roles="admin")]
public ActionResult AdminView()
{
return View()
}
But I am not sure how the Authorize and the Roles keyword works. How when putting Roles = "Admin", is going to help in checking my user role string stored in the session, or how I can redirect a user to unauthorized page, in case the role does not match the role tagged for the action method.
As per my thinking you need to code for authorization.
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly RoleEnum[] _acceptedRoles;
public AuthorizeAttribute(params RoleEnum[] acceptedroles)
{
_acceptedRoles = acceptedroles;
}
public AuthorizeAttribute(params bool[] allowAll)
{
if (allowAll[0])
_acceptedRoles = new RoleEnum[] { RoleEnum.Admin, RoleEnum.user};
}
public void OnAuthorization(AuthorizationContext filterContext)
{
if (SessionHelper.UserInSession == null)//user not logged in
{
FormsAuthentication.SignOut();
filterContext.Result =
new RedirectToRouteResult(new System.Web.Routing.RouteValueDictionary {{ "controller", "Home" },
{ "action", "Index" },
{ "returnUrl", filterContext.HttpContext.Request.RawUrl } });//send the user to login page with return url
return;
}
if (!_acceptedRoles.Any(acceptedRole => SessionHelper.UserInSession.UserRoles.Any(currentRole => acceptedRole == currentRole.Role)))
//allow if any of the user roles is among accepted roles. Else redirect to login page
throw new UnauthorizedAccessException();
}
}
This is also work for return URL.
As per comments, if you are using custom authentication/authorization mechanism then you need to implement custom authorize attribute where you can put custom logic to check if user has admin role or not. Something like below:
public class CustomizedAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
//check for role in session variable "ADMIN_ROLE"
//if not valid user then set
filterContext.Result = new RedirectResult(URL)
}
}
There is a small nice explanation in this link:
http://weblogs.asp.net/jgalloway/archive/2011/04/28/looking-at-how-asp-net-mvc-authorize-interacts-with-asp-net-forms-authorization.aspx
as per this:
ASP.NET MVC includes an [Authorize] attribute, which when placed on any controller actions will forbid unauthorized access. The AuthorizeAttribute allows you to specify a list of roles or users.
You can also place the AuthorizeAttribute on a controller, in which case it will apply to all actions in the controller. Attempting to access an action secured by the AuthorizeAttribute when you're not logged in will take you to a standard LogOn screen, with a link to register if you don't already have an account.
How does the [Authorize] attribute redirect me to Log On?
The AuthorizeAttribute is an ActionFilter, which means that it can execute before the associated controller action. The AuthorizeAttribute performs its main work in the OnAuthorization method, which is a standard method defined in the IAuthorizationFilter interface. Checking the MVC source code, we can see that the underlying security check is really just looking at the underlying authentication information held by the ASP.NET context:
IPrincipal user = httpContext.User;
if (!user.Identity.IsAuthenticated)
{
return false;
}
If the user fails authentication, an HttpUnauthorizedResult ActionResult is returned, which produces an HTTP 401(Unauthorized) status code. If it weren’t for ASP.NET Forms Authentication, an HTTP 401 status code would be sent to the browser, which would show the browser’s default login prompt.
Related
I have created a ASP.NET MVC core application. I just finished creating and logging in a user. Now I'm trying to figure out
1. how to have the user login info saved
2. how to require a user to be logged in to visit the rest of the the site.
For saving the user log info. I was going to use either Identity or Asp.Net.Session, but seeing has I cant find anything that shows how to require the user to be logged in to visit routes, I’m unsure which option would work best.
Could someone explain to me how to require authentication before accessing a route, and which of the saving login info works best with that method?
Current Login Example
public ActionResult Login(LoginModel model){
if (ModelState.IsValid){
SqlConnect test = new SqlConnect("Data Source=/home/andrew/database.db","Accounts");
var check = test.count(model.UserName,model.Password);
if(check){
// Found in database
return RedirectToAction("Index","Home");
}
}
// If we got this far, something failed, redisplay form
return RedirectToAction("Error","Home");
}
You shouldn't secure routes. When using placeholders (such as in the default route), it is possible that more than one route can reach an action method. These alternate paths are sure to be difficult (nearly impossible) to keep secure as your application changes over time.
So the best option is to secure the resources by preventing them from being served. Note that this is also the way security works in ASP.NET, so both ASP.NET and MVC hook into the same mechanism (IPrincipal and IIdentity) to control both authentication and authorization. ASP.NET Identity and older security frameworks from Microsoft all use this extension point to plug into MVC and ASP.NET.
In MVC, it is the AuthorizeAttribute that uses these interfaces to secure action methods. AuthorizeAttribute can be used in several ways:
On Action Methods
public class MyController
{
[Authorize(Roles = "Admin,SuperUser")]
public ActionResult Index()
{
return View();
{
}
On Controllers
[Authorize(Roles = "Admin,SuperUser")]
public class MyController
{
[AllowAnonymous] // All users have access
public ActionResult Index()
{
return View();
{
// Only authenticated users in Admin or SuperUser
// role have access
public ActionResult Contact()
{
return View();
{
// Only authenticated users in Admin or SuperUser
// role have access
public ActionResult About()
{
return View();
{
}
Globally
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new AuthorizeAttribute());
filters.Add(new HandleErrorAttribute());
}
}
This means that only authenticated users can access any action method in your application. You can also use roles here like filters.Add(new AuthorizeAttribute() { Roles = "Foo,Bar" });. And you can allow specific controllers/actions access to unauthenticated users with the AllowAnonymousAttribute.
You can also subclass AuthorizeAttribute if you have more complex business logic than just Users and Roles.
I have a role system where the Admin can create new roles and grant Read, Write, Edit and Delete rights based on the page menu (each page menu has it's own controller) then assign that role to the user.
Users can also have multiple roles but i got that covered. The only problem I am facing is this: since Role assigning can be done dynamically from within the application i can't use the [Authorize(Roles = Role.Admin)] attribute over controller actions.
Instead i was thinking of creating [Read], [Write], [Edit] and [Delete] attributes that i would put over the actions to let me know what that action is for and then allow or deny users to call that action.
Would this be the correct approach? What would i need to have in those custom attributes and how would i allow/deny user to call them? Anyone have any similar experience?
Let's say i have Home and Admin controller and Role1 and Role2 with following rights:
Would something like the above approach works? How do I define custom access for controller actions?
I want to avoid having all the actions in the database and simplify the administration on the site.
In this way administration can be done on R/W/E/D flags on controller level instead of Role1 can all Home/Index, Home/GetRecords etc... action level.
I have same requirement for my project. In my project I have to allow user to access some pages and some pages to admin. Mostly admin can access everything, but I have to block user to access some pages/Action. I did below thing.
a. Create one class to Authenticate user/admin.
b. Create one class for User and inherited that class from "ActionFilterAttribute", and override the OnActionExecuting method.
c. Create one class for Admin and did samething as mentioned in "b", but for admin.
d. put the Authentication class name above the class name or method depending on access.
see sample code(step b). I removed some code, but you can get the idea.
public class AuthenticateUser : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext context)
{
//Do session check.
if (HttpContext.Current.Session["Id"] == null || String.IsNullOrEmpty(HttpContext.Current.Session["Id"].ToString()))
{
HttpContext.Current.Response.StatusCode = HttpStatusCode.Forbidden.GetHashCode();
if (filterContext.HttpContext.Request.IsAjaxRequest())
{
filterContext.Result = new JsonResult { Data = new { Status = HttpStatusCode.Forbidden, LogonRequired = true, result = "Session Expired" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
else
{
//redirect to login page
UrlHelper oUrl = new UrlHelper(HttpContext.Current.Request.RequestContext);
string s = oUrl.Action("", "UserInfo/");
HttpContext.Current.Response.Redirect(s);
}
}
//If usertype is User then allow it. If user type is admin then return redirect.
//Redirect code if admin
UrlHelper oUrl = new UrlHelper(HttpContext.Current.Request.RequestContext);
string s = oUrl.Action("", "UserInfo/");
HttpContext.Current.Response.Redirect(s);
}
}
I would define it differently, just give each user a set of roles.
Define each user with more than one role, if someone has access to write, you set a role for him to write, if he can also read you can add another role - read.
Now when you define your actions you can use this format[Authorize(Roles = Role.Read)]. Set each action by the access right it requires and you are done.
Use claims. each public controller action claim that you need to define.
Then have your roles defined by the list of claims/operations they can do.
Here's a great explanation here Role-based access control (RBAC) vs. Claims-based access control (CBAC) in ASP.NET MVC
So, I'm using the ASP.NET SimpleMembershipProvider user, roles and authorization structure. This controller requires the user is logged in, so that when it acesses this page while logged off, the login page appears.
[Authorize]
public class CompanyController : Controller
{
//stuff...
}
For this page, I want restricted access only to admins, so here it goes
[Authorize(Roles = "Admin")]
public class UserManagementController : Controller
{
//fields, methods, etc...
}
But when I try to access it logged off or logged in with a user account not in the "Admin" role, it shows the login page, but I wanted a custom page telling the user that page has restricted access and he does'nt have the credentials. How to do it, I mean without having to resort to if's and redirects in every method, that would blow the point of authorization atributes.
Thanx
You can put authorization attributes on methods NOT just the class for more fine grained control.
I have a ASP.NET MVC 4 application. I am trying to implement a solution where I check if a user can access a view, if not then display an error. If the user can access a view then I need to check if that user has read access or read and edit access to that view. If the user has read access then just a normal details view is displayed, if read and edit access then the user can see a details view or can edit the data.
Is something like this possible? I have tried looking through a couple of starter kits that I found on Codeplex but I can't find something like I want. How would this be implemented? If possible, if anyone knows of any sample project that I can download then I will appreciate. I like to work through code, I learn more this way.
I want this all to be database-driven.
You should look more into the AuthorizeAttribute and how to use roles. Basically you give your users roles (that may be fetched from the database) and for every view you wish to limit access in your application you add the Authorize attribute together with the roles. By default I think you can only limit to access or no access but you can probably override and write your custom attribute to give you the behavior you are interested in.
Alternatively, you can manage the user privileges in your controllers. Since you know the authenticated users roles and have access to them you can perform the check in the controller and create the view from that (disabled inputs etc.)
Related
ASP.Net MVC: Can the AuthorizeAttribute be overriden?
Granular permissions with certain requirements for an MVC site
As #Marcus said, you should use Attribute. When action starts, you can check user's role, he has access or not:
public class AttributeForTestAttribute : ActionFilterAttribute
{
public int RoleCanAccess { get; set; }
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
base.OnActionExecuting(filterContext);
//your validation here..
//for example:
if(_currentUser.Role < RoleHasAccess )
{
//user has not access to this action, redirect him to home page.
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "controller", "Home" }, { "action", "Index" }, { "returnUri", filterContext.HttpContext.Request.RawUrl } });
}
else
{
// user has access to this action
}
}
}
And in controller use your Attribute:
[AttributeForTest(RoleHasAccess = 2)]
public ActionResult SaveProduct(Product product)
{
}
I have an MVC3 web application with a front end and a backend. In the backend, each action is protected with an if..then..else redirecting to another action if the user is not logged in (it checks a session). It does this without windows roles.
I was wondering if it was possible to create an attribute that does the check and redirects the user to a login page without having to insert the same code over and over into each action?
EDIT #1
I've created a basecontroller which my admin controllers derived from and added the following member following on from what Virus said:
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
if (Session["loggedIn"] == null || (bool)Session["loggedIn"] != true)
{
TempData["targetAction"] = ControllerContext.ParentActionViewContext.RouteData.Values["action"] + "/" + ControllerContext.ParentActionViewContext.RouteData.Values["controller"];
RedirectToRoute("Admin/Login");
}
}
catch (NullReferenceException)
{
RedirectToRoute("Admin/Login");
}
}
But this code does'nt work. Can someone please tell me what is wrong?
you can do this easily.
No need to use attributes
Just create a common BaseController which is inherited from Controller class,
and inherit all your controllers from BaseController
override the OnActionExecuting event in BaseController and put the authorization logic on that.
the OnActionExecuting event will be executed every time when an action is invoked.
If you need to redirect to an Action, this code will help
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "Index" }, { "controller", "Account" } });
That's what the built-in AuthorizeAttribute filter does.
You can use the AuthorizeAttribute filter at a global level, controller level or even at action level. If the built-in Authorize filter is not enough for you can easily create a custom one by inheriting it as explained in this post.