Skip to content

Allow direct configuration of authorization policies via endpoint metadata #39840

Closed
@DamianEdwards

Description

@DamianEdwards

Relates 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;
    }
}

Metadata

Metadata

Assignees

Labels

api-approvedAPI was approved in API review, it can be implementedarea-authIncludes: Authn, Authz, OAuth, OIDC, Bearerarea-signalrIncludes: SignalR clients and serversold-area-web-frameworks-do-not-use*DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions