Introduce support for defining Authorization policies via Configuration
- Dominant language
- C#
- Stars
- 38.4k
- Forks
- 10.9k
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 290
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.:
```csharp
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:
```csharp
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` 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.:
```jsonc
{
"Authorization": {
"DefaultPolicy": "HasProtectedAccess",
"FallbackPolicy": "",
"InvokeHandlersAfterFailure": true,
"Policies": {
"HasProtectedAccess": {
"Claims": [
{ "scope" : "myapi:protected-access" }
]
}
}
}
}
```
```csharp
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:
```jsonc
{
"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" ]
}
}
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.