knut
knut

Reputation: 4745

Good practice to do common authorization in a custom controller factory?

My controllers share a client id. Route:

clients/{clientId}/{controller}/{action}/{id}

Sample URLs:

clients/1/orders/details/1
clients/2/children/index
clients/2/cars/create

You need proper authorization for a client. I don't want to do the same client authorization in every controller. I came up with the idea to do the autorization in a custom controller factory like this:

public class CustomControllerFactory : DefaultControllerFactory
{
    private readonly IAuthService _authService;

    public CustomControllerFactory(IAuthService authService)
    {
        _authService = authService;
    }

    protected override IController GetControllerInstance(
        RequestContext requestContext, Type controllerType)
    {
        var doAuth = requestContext.RouteData.Values.ContainsKey("clientId");
        if (doAuth)
        {
            var principal = requestContext.HttpContext.User;
            var clientId = long.Parse(
                requestContext.RouteData.Values["clientId"].ToString());
            var authorized = _authService.Client(principal, clientId);
            if (!authorized)
            {
                return new AuthController();
            }                
        }
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

Do you consider this a good practice or not? Why?

Upvotes: 4

Views: 3494

Answers (3)

vrluckyin
vrluckyin

Reputation: 1024

We have already used below concept to check authorization;

Step 1:Need to create 3 different tables and enter appropriate data;

A. Table: Actions

ID:int,PK Controller:varchar(100) Action:varchar(100) HttpMethod:varchar(10)

B. Table: Permission

Id: int,PK Name: varchar(100)

C. Table: Permission_Action

Id:int,PK PermissionId:int, FK ActionId:int, FK

Step 2: Create an ApplicationController that will be inherited from "Controler" class and all other controller should be inherited from "ApplicationController" instead of "Controller".

//Declaration of ApplicationController
public class ApplicationController : Controller
//Declaration of Other controller
public class OtherController : ApplicationController 

Step 3: For persistance, fetch all the controller and actions for a current user after authentication. Insted we can also fire SQL query every time.

Step 4: In "OnActionExecuting" method you will have information about controller and action of the current request. Looked into controller action list, fetched in Step 3, to find out the current controller and action.

 string controller = filterContext.RouteData.Values["controller"] as string;
 string action = filterContext.RouteData.Values["action"] as string;
 string httpMethod = filterContext.HttpContext.Request.HttpMethod.ToLowerInvariant();

Step 5: If found then user has right to proceed with an action otherwise return predefined "SecurityResult"

Example:

NOTE: actions related to "Authorization" should be assigned at the time of creating users. This part is excluded in this example;

A. Action table data:

{1,"Employee","Detail","get"},{2,"Employee","Create","get"},{3,"Employee","Create","post"},{4,"Employee","Delete","post"}

B. Permission table data:

{1, "View Employee Detail"},{2, "Create Employee Detail"},{3, "Delete Employee Detail"}

C. Permission_Action table data:

{1, 1, 1},{1, 2, 2},{1, 2, 3},{1, 3, 4}

D. Now user "vrluckyin" has only permission for viewing data and creating employee.

"Delete" action from "Employee" has not been assigned.

After authorization, if "vrluckyin" user tries to call "delete" action of "Employee" controller then system will return security view instead of delete view.

  • No need to write [Authorize] attribute on every action.
  • We can add/remove/update user rights easily. Only Database changes!!!

Enjoy!

Upvotes: 1

John Farrell
John Farrell

Reputation: 24754

This is the absolutely best practice when your application has a very strong multi-tenancy or user-ownership model.

[Authorize] attributes, even on the class level, are just clutter if you are decorating the majority of your application with them. [Authorize] attributes can also be forgotten. Your technique will always work.

Upvotes: 0

Darin Dimitrov
Darin Dimitrov

Reputation: 1039160

No, I don't consider this as a good practice. A custom AuthorizeAttribute seems far more adapted to handle authorization rather than a controller factory.

Upvotes: 4

Related Questions