One of the patterns we want to encourage with endpoint routing is the use of the fallback policy. This is the rough equivalent of a global authorization filter.
In this style it's much more common to opt-in globally to authorization, and then opt-out on the specific endpoints that you want to be public. This is where the attribute [AllowAnonymous] gets its name - because you require a login, but then mark the public areas as safe for anonymous access.
This is possible to do today but it's not super discoverable. Users don't seem to find WithMetadata super obvious as a powerful construct, and it's also not obvious that constructing and adding an attribute instance is the right thing to do.
```C#
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
})
.WithMetadata(new AllowAnonymousAttribute());
});
}
}
## Sample After
```C#
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
})
.AllowAnonymous();
});
}
}
If you haven't seen any IEndpointConventionBuilder extensions before, it's worth noting that they all use generics. This is needed because various endpoint routing things return different, strongly-typed builders, so we need to propagate the concrete type instead of the interface type.
C#
namespace Microsoft.AspNetCore.Builder
{
public static class AuthorizationEndpointConventionBuilderExtensions
{
/// <summary>
/// Allows anonymous access to the endpoint by adding <see cref="AllowAnonymousAttribute" /> to the endpoint metadata. This will bypass
/// all authorization checks for the endpoint including the default authorization policy and fallback authorization policy.
/// </summary>
/// <param name="builder">The endpoint convention builder.</param>
/// <returns>The original convention builder parameter.</returns>
public static TBuilder AllowAnonymous<TBuilder>(this TBuilder builder) where TBuilder : IEndpointConventionBuilder { }
}
}
I just ran into this myself with the app I'm building. Would love to see this method added.
Yeah, it will get done soon. Maybe today 馃憤
I predict that people are going to be confused by this.
1) it will override any lower level authorization (e.g. at the controller/action level) leaving people either confused why their [Authorize] is not working, or just leaving people with the incorrect assumption that their [Authorize] is secure (but they never tested it).
2) it's only useful if you've indicated a fallback policy (which I suspect will be rare?), yet it will show up in the intellisense for all EP routes, thus leading back to my first point.
The main use case for this is in cases where you don't have controllers and actions. People are already confused, they are trying to find the equivalent functionality to [AllowAnonymous] for delegates hooked up to routing.
Fallback policy is what we're pushing everyone towards instead of global authorization filters because it works on things that aren't MVC.
Maybe a compromise would be to call it something a bit more scary?
I'm kinda vaguely in favour of that because I already think that AllowAnonymous isn't descriptive enough for what it does. However, you can't really change what we've already build. IAllowAnonymous is a type that exists, that the auth system has built-in knowledge of 馃槅
The choice to call it AllowAnonymous() reflects what people already know about asp.net.
It's endpoint routing that would need to be updated, right? @rynowak ? It's an extension method that adds a AllowAnonymousAttribute to route metadata?
Yes, this is a 3 line change focused on making this capability more obvious.
Most helpful comment
The main use case for this is in cases where you don't have controllers and actions. People are already confused, they are trying to find the equivalent functionality to
[AllowAnonymous]for delegates hooked up to routing.Fallback policy is what we're pushing everyone towards instead of global authorization filters because it works on things that aren't MVC.