-
Notifications
You must be signed in to change notification settings - Fork 10.5k
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" ]
}
}
}
}
{ "Authorization": { "DefaultPolicy": "HasProtectedAccess", "FallbackPolicy": "", "InvokeHandlersAfterFailure": true, "Policies": { "HasProtectedAccess": { "Claims": [ { "scope" : "myapi:protected-access" } ] } } } }