Custom authorization attribute in MVC 4 with roles

I created a custom authorization attribute for the base role. My idea is that when a user with the role name "employee" Log In cannot be allowed to access the "admin" page via the URL. But when I implement [MyRoleAuthorization] in the Employee controller and Log In, the error says: "This web page has a redirect loop." This is the code for [MyRoleAuthorization]

 public class MyRoleAuthorization : AuthorizeAttribute { string isAuthorized; private string AuthorizeUser(AuthorizationContext filterContext) { if (filterContext.RequestContext.HttpContext != null) { var context = filterContext.RequestContext.HttpContext; if (Convert.ToString(context.Session["RoleName"]) == "Admin") { isAuthorized = "Admin"; } else if (Convert.ToString(context.Session["RoleName"]) == "Employee") { isAuthorized = "Employee"; } else if (Convert.ToString((context.Session["RoleName"])) == "Customer") { isAuthorized = "Customer"; } else { throw new ArgumentException("filterContext"); } } return isAuthorized; } public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) throw new ArgumentException("filterContext"); if (AuthorizeUser(filterContext) == "Admin") { filterContext.Result = new RedirectToRouteResult (new RouteValueDictionary(new { controller = "Admin" })); } else if (AuthorizeUser(filterContext) == "Employee") { filterContext.Result = new RedirectToRouteResult (new RouteValueDictionary(new { controller = "Employee" })); } else if (AuthorizeUser(filterContext) == "Customer") { filterContext.Result = new RedirectToRouteResult (new RouteValueDictionary(new { controller = "Customer" })); } } } } 

My employee manager is as follows

  [MyRoleAuthorization] public ActionResult Index() { var employee = db.Employee.Include(e => e.User); return View(employee.ToList()); } 

Could you help me.

0
source share
3 answers

Your redirect code will always redirect the user to the employee index action, even if the action you are redirecting to is checked for the employee. You will need to provide another set of rules in your authorization and change the OnAuthorize method.

For instance,

 public class MyRoleAuthorization : AuthorizeAttribute { /// <summary> /// the allowed types /// </summary> readonly string[] allowedTypes; /// <summary> /// Default constructor with the allowed user types /// </summary> /// <param name="allowedTypes"></param> public MyRoleAuthorization(params string[] allowedTypes) { this.allowedTypes = allowedTypes; } /// <summary> /// Gets the allowed types /// </summary> public string[] AllowedTypes { get { return this.allowedTypes; } } /// <summary> /// Gets the authorize user /// </summary> /// <param name="filterContext">the context</param> /// <returns></returns> private string AuthorizeUser(AuthorizationContext filterContext) { if (filterContext.RequestContext.HttpContext != null) { var context = filterContext.RequestContext.HttpContext; string roleName = Convert.ToString(context.Session["RoleName"]); switch (roleName) { case "Admin": case "Employee": case "Customer": return roleName; default: throw new ArgumentException("filterContext"); } } throw new ArgumentException("filterContext"); } /// <summary> /// The authorization override /// </summary> /// <param name="filterContext"></param> public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) throw new ArgumentException("filterContext"); string authUser = AuthorizeUser(filterContext); if (!this.AllowedTypes.Any(x => x.Equals(authUser, StringComparison.CurrentCultureIgnoreCase))) { filterContext.Result = new HttpUnauthorizedResult(); return; } } 

}

Then it can be decorated as

 public class EmployeeController : Controller { [MyRoleAuthorization("Employee")] public ActionResult Index() { return View(); } } 

Your login code should now be changed to send the user to the correct controller.

+1
source

The biggest problem is that when you go to the employee controller as an employee, you are redirected to the employee controller, where your attribute redirects you to the employee controller and so on. Try to avoid redirecting inside the attribute, as it makes your code fragile, and when you return after many years, you will not remember why your routes do not work, as you intend

Try the following:

 public class MyRoleAuthorization : AuthorizeAttribute { public string Role{get;set;} private string AuthorizeUser(AuthorizationContext filterContext) { if (filterContext.RequestContext.HttpContext != null) { var context = filterContext.RequestContext.HttpContext; return (string)context.Session["RoleName"]; } throw new ArgumentException("filterContext"); } public override void OnAuthorization(AuthorizationContext filterContext) { if (filterContext == null) throw new ArgumentException("filterContext"); var role = AuthorizeUser(filterContext); if (role.Equals(Role)) { // insert positive outcome from role check, ie let the action continue } else { // denied! redirect to login page or show denied page (403) } } } [MyRoleAuthorization("Employee")] public ActionResult Index() { var employee = db.Employee.Include(e => e.User); return View(employee.ToList()); } 
+1
source

Apparently, during authorization, for example, you are redirected to the Client's controller. This controller probably has its own attribute on it, and therefore it allows the user who is considered as a client, and redirects it to the client controller ... Which has its own attribute, and therefore it allows the user ...

Infinite loop.

0
source

Source: https://habr.com/ru/post/974480/


All Articles