.Net Core动态控制器授权策略控制:如何为不同实现指定角色与策略
Alright, let's tackle this problem step by step—since you're working with .NET Core 2 and need to set up differentiated authorization roles/policies for both dynamic controllers and generic controller implementations, here's how you can make it work:
If your dynamic controllers are generated explicitly (not via generics), you have two straightforward options:
- Add the
[Authorize]attribute directly when defining or generating the controller type. For example:// Dynamically generated controller [Authorize(Roles = "InventoryAdmin")] public class DynamicInventoryController : ControllerBase { // Controller actions go here } - Use controller conventions if you want to apply authorization rules across multiple dynamic controllers based on naming or other criteria. You can create a custom
IControllerModelConventionto inject authorization filters dynamically.
This is where things get nuanced—since you need different rules per generic type parameter, the key is using controller conventions to inspect the generic controller's type and attach the appropriate authorization filter.
Step 1: Define Your Generic Controller
First, set up your base generic controller:
public class GenericCrudController<T> : ControllerBase where T : class { // CRUD actions (Get, Post, Put, Delete) go here }
Step 2: Register Generic Controller Implementations
In your Startup.cs, register specific generic controller instances (e.g., GenericCrudController<Product>, GenericCrudController<Order>) and configure conventions:
public void ConfigureServices(IServiceCollection services) { services.AddMvc() .AddControllersAsServices() .ConfigureApplicationPartManager(apm => { // Register your generic controller for target entity types var genericControllerType = typeof(GenericCrudController<>); // Add implementations for Product and Order entities foreach (var entityType in new[] { typeof(Product), typeof(Order) }) { var concreteControllerType = genericControllerType.MakeGenericType(entityType); apm.ApplicationParts.Add(new AssemblyPart(concreteControllerType.Assembly)); apm.FeatureProviders.Add(new GenericControllerFeatureProvider(entityType)); } }) // Attach our custom authorization convention .ConfigureConventions(conventions => { conventions.Add(new GenericControllerAuthorizationConvention()); }); // Optional: Register named authorization policies for reusability services.AddAuthorization(options => { options.AddPolicy("ProductManagement", policy => policy.RequireRole("ProductAdmin", "Editor")); options.AddPolicy("OrderManagement", policy => policy.RequireRole("OrderAdmin", "Manager")); }); }
Step 3: Create the Custom Authorization Convention
This convention will inspect each controller, check if it's a generic instance, and apply rules based on the generic type parameter:
public class GenericControllerAuthorizationConvention : IControllerModelConvention { public void Apply(ControllerModel controller) { // Skip non-generic controllers if (!controller.ControllerType.IsGenericType) return; var genericEntityType = controller.ControllerType.GetGenericArguments()[0]; // Apply role/policy based on the entity type if (genericEntityType == typeof(Product)) { // Option 1: Direct role requirement controller.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder() .RequireRole("ProductAdmin") .Build())); // Option 2: Use a pre-defined policy (from Startup.cs) // controller.Filters.Add(new AuthorizeFilter("ProductManagement")); } else if (genericEntityType == typeof(Order)) { controller.Filters.Add(new AuthorizeFilter(new AuthorizationPolicyBuilder() .RequireRole("OrderAdmin") .Build())); } // Add more cases for other entity types as needed } }
Step 4: Implement GenericControllerFeatureProvider (Optional)
Customize how your generic controllers are discovered by MVC with this feature provider:
public class GenericControllerFeatureProvider : IControllerFeatureProvider { private readonly Type _entityType; public GenericControllerFeatureProvider(Type entityType) { _entityType = entityType; } public bool IsController(TypeInfo typeInfo) { return typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(GenericCrudController<>) && typeInfo.GetGenericArguments()[0] == _entityType; } }
This approach ensures each generic controller instance gets the exact authorization rules it needs, whether you're using direct role checks or named policies.
内容的提问来源于stack exchange,提问作者johnny 5

