Reputation: 4745
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
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.
Enjoy!
Upvotes: 1
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
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