Description
Spin-off of #39855 focusing on addition of top-level authorization configuration API.
Example matching Authorization
changes to consider, allowing sharing of policies, etc.:
var builder = WebApplication.CreateBuilder(args);
builder.Authentication.AddJwtBearer();
builder.Authorization.AddPolicy("HasProtectedAccess", policy =>
policy.RequireClaim("scope", "myapi:protected-access"));
var app = builder.Build();
app.MapGet("/hello", () => "Hello!");
app.MapGet("/hello-protected", () => "Hello, you are authorized to see this!")
.RequireAuthorization("HasProtectedAccess");
app.MapGet("/hello-also-protected", () => "Hello, you authorized to see this to!")
.RequireAuthorization("HasProtectedAccess");
app.Run();
The WebApplicationBuilder.Authorization
property is typed as AuthorizationOptions
allowing simple creation of policies and configuration of the default and fallback policies:
builder.Authorization.AddPolicy("HasProtectedAccess", policy => policy.RequireClaim("scope", "myapi:protected-access"));
builder.Authorization.DefaultPolicy = builder.Authorization.GetPolicy("HasProtectedAccess");
// Consider new methods to enable easily setting default/fallback policies by name
builder.Authorization.SetDefaultPolicy("HasProtectedAccess");
builder.Authorization.SetFallbackPolicy("HasProtectedAccess");
The WebApplicationBuilder
would register an IConfigureOptions<AuthorizationOptions>
in the services collection with a delegate that applies the settings.
Note this suggestion has a fundamental issue in that the AuthorizationOptions
isn't designed to be mutated in this way, rather it should be configured via a callback registered in DI so that it runs at the appropriate time during app startup and composes with other code that wishes to configure it.
Perhaps instead the Authentication
property should also read from configuration for authorization settings, and the Authorization
property would be a new type that simply provides easy access to adding a configuration delegate, e.g.:
builder.Authentication.AddJwtBearer();
builder.Authorization.Configure(authz =>
{
// Following is the code-based equivalent of config above
authz.AddPolicy("HasProtectedAccess", policy => policy.RequireClaim("scope", "myapi:protected-access"));
authz.DefaultPolicy = authz.GetPolicy("HasProtectedAccess");
});
Some other potential example policies as defined via configuration:
{
"Authorization": {
"DefaultPolicy": "HasProtectedAccess",
"Policies": {
"AuthenticatedUsers": {
"AuthenticationRequired": true
},
"Employees": {
"AuthenticationRequired": true,
"Roles": [ "Employees" ]
},
"OnlyHomers": {
"AuthenticationRequired": true,
"UserName": "Homer"
},
"ApiClients": {
"AuthenticationRequired": true,
// Any unrecognized properties are auto-mapped as claims perhaps?
"scope": [ "myapi:read", "myapi:protected-access" ]
}
}
}
}