Allow direct configuration of authorization policies via endpoint metadata
See original GitHub issueRelates to #34545
We should allow the definition and/or application of authorization policies to specific endpoints via endpoint metadata at the time they’re declared. This will make configuration of resource authorization for Minimal API style applications much simpler and more inline with the principals of Minimal APIs while still enabling re-use of policies via language features rather than relying on their definition at the time authorization is added to DI.
The AuthorizationMiddleware
would be updated to retrieve metadata for the current request and ensure any instances that implement IAuthorizationRequirement
are passed to the IAuthorizationService
for evaluation (e.g. as IAuthorizationHandler
or IAuthorizeData
, etc.).
New extension methods would be added to enable setting AuthorizationPolicy
on endpoint definitions, as well as methods for setting IAuthorizationRequirement
, IAuthorizationHandler
or IAuthorizeData
as metadata:
// Set authorization metadata via an instance of AuthorizationPolicy
public static TBuilder RequireAuthorization<TBuilder>(this TBuilder builder, AuthorizationPolicy policy) where TBuilder : IEndpointConventionBuilder;
// Set authorization metadata via a callback accepting Action<AuthorizationPolicyBuilder>
public static TBuilder RequireAuthorization<TBuilder>(this TBuilder builder, Action<AuthorizationPolicyBuilder> configurePolicy) where TBuilder : IEndpointConventionBuilder;
// Set authoriziation metadata via an instance of IAuthorizationRequirement
public static TBuilder RequireAuthorization<TBuilder>(this TBuilder builder, IAuthorizationRequirement authoriziationRequirement) where TBuilder : IEndpointConventionBuilder;
// Set authoriziation metadata via an instance of IAuthorizationHandler
public static TBuilder RequireAuthorization<TBuilder>(this TBuilder builder, IAuthorizationHandler authoriziationHandler) where TBuilder : IEndpointConventionBuilder;
// Set authoriziation metadata via an instance of IAuthorizeData
public static TBuilder RequireAuthorization<TBuilder>(this TBuilder builder, IAuthorizeData authorizeData) where TBuilder : IEndpointConventionBuilder;
Example usage:
...
app.UseAuthentication();
app.UseAuthorization();
// Create and use a policy on multiple endpoints
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireClaim("some:claim", "this-value")
.Build();
app.MapGet("/protected", () => "you are allowed!")
.RequireAuthorization(policy);
app.MapGet("/also-protected", () => "you are allowed!")
.RequireAuthorization(policy);
// Create and pass a policy inline to the endpoint definition
app.MapGet("/fowlers-only-policy", () => "you are allowed!")
.RequireAuthorization(new AuthorizationPolicyBuilder().RequireUserName("Fowler").Build());
// Define a policy directly on the endpoint via a callback accepting Action<AuthorizationPolicyBuilder>
app.MapGet("/fowlers-only-builder", () => "you are allowed!")
.RequireAuthorization(p => p.RequireUserName("Fowler"));
// Use a custom attribute that implements IAuthorizationRequirement and IAuthorizationHandler to allow declarative metadata based authorization
app.MapGet("/fowlers-only-attribute", [RequiresUsername("Fowler")] () =>"you are allowed!");
// Use the attribute imperatively
app.MapGet("/fowlers-only-inline", () => "you are allowed!")
.RequireAuthorization(new RequiresUsernameAttribute("Fowler"));
...
public class RequiresUsernameAttribute : Attribute, IAuthorizationHandler, IAuthorizationRequirement
{
public RequiresUsernameAttribute(string username)
{
Username = username;
}
public string Username { get; set; }
public Task HandleAsync(AuthorizationHandlerContext context)
{
if (context.User.Identity?.Name == Username)
{
context.Succeed(this);
}
return Task.CompletedTask;
}
}
Issue Analytics
- State:
- Created 2 years ago
- Comments:27 (27 by maintainers)
Top GitHub Comments
I’m using this to track the authz caching work discussed to speed up the hot path so endpoints don’t combine authz policies every time
I think we just need to throw for this metadata. @DamianEdwards is looking at auto injecting middlware in the web application builder cases if you configure auth.