From 49427139edbf254a764633e0ed45f39282b3e220 Mon Sep 17 00:00:00 2001
From: Hao Kung <HaoK@users.noreply.github.com>
Date: Wed, 29 Jun 2022 14:59:05 -0700
Subject: [PATCH] Add AuthorizationBuilder (#42264)

---
 .../Core/src/AuthorizationBuilder.cs          | 149 ++++++++++++++++++
 .../Core/src/AuthorizationOptions.cs          |   2 +-
 .../Core/src/PublicAPI.Unshipped.txt          |  12 ++
 .../src/PolicyServiceCollectionExtensions.cs  |   8 +
 .../Policy/src/PublicAPI.Unshipped.txt        |   1 +
 .../test/AuthorizationBuilderTests.cs         | 116 ++++++++++++++
 .../test/DefaultAuthorizationServiceTests.cs  | 111 +++----------
 7 files changed, 307 insertions(+), 92 deletions(-)
 create mode 100644 src/Security/Authorization/Core/src/AuthorizationBuilder.cs
 create mode 100644 src/Security/Authorization/test/AuthorizationBuilderTests.cs

diff --git a/src/Security/Authorization/Core/src/AuthorizationBuilder.cs b/src/Security/Authorization/Core/src/AuthorizationBuilder.cs
new file mode 100644
index 00000000000..793d2ab2709
--- /dev/null
+++ b/src/Security/Authorization/Core/src/AuthorizationBuilder.cs
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace Microsoft.AspNetCore.Authorization;
+
+/// <summary>
+/// Used to configure authorization
+/// </summary>
+public class AuthorizationBuilder
+{
+    /// <summary>
+    /// Initializes a new instance of <see cref="AuthorizationBuilder"/>.
+    /// </summary>
+    /// <param name="services">The services being configured.</param>
+    public AuthorizationBuilder(IServiceCollection services)
+        => Services = services;
+
+    /// <summary>
+    /// The services being configured.
+    /// </summary>
+    public virtual IServiceCollection Services { get; }
+
+    /// <summary>
+    /// Determines whether authorization handlers should be invoked after <see cref="AuthorizationHandlerContext.HasFailed"/>.
+    /// Defaults to true.
+    /// </summary>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder SetInvokeHandlersAfterFailure(bool invoke)
+    {
+        Services.Configure<AuthorizationOptions>(o => o.InvokeHandlersAfterFailure = invoke);
+        return this;
+    }
+
+    /// <summary>
+    /// Sets the default authorization policy. Defaults to require authenticated users.
+    /// </summary>
+    /// <remarks>
+    /// The default policy used when evaluating <see cref="IAuthorizeData"/> with no policy name specified.
+    /// </remarks>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder SetDefaultPolicy(AuthorizationPolicy policy)
+    {
+        Services.Configure<AuthorizationOptions>(o => o.DefaultPolicy = policy);
+        return this;
+    }
+
+    /// <summary>
+    /// Sets the fallback authorization policy used by <see cref="AuthorizationPolicy.CombineAsync(IAuthorizationPolicyProvider, IEnumerable{IAuthorizeData})"/>
+    /// when no IAuthorizeData have been provided. As a result, the AuthorizationMiddleware uses the fallback policy
+    /// if there are no <see cref="IAuthorizeData"/> instances for a resource. If a resource has any <see cref="IAuthorizeData"/>
+    /// then they are evaluated instead of the fallback policy. By default the fallback policy is null, and usually will have no
+    /// effect unless you have the AuthorizationMiddleware in your pipeline. It is not used in any way by the
+    /// default <see cref="IAuthorizationService"/>.
+    /// </summary>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder SetFallbackPolicy(AuthorizationPolicy? policy)
+    {
+        Services.Configure<AuthorizationOptions>(o => o.FallbackPolicy = policy);
+        return this;
+    }
+
+    /// <summary>
+    /// Adds a <see cref="AuthorizationPolicy"/> which can be used by <see cref="IAuthorizationService"/>.
+    /// </summary>
+    /// <param name="name">The name of this policy.</param>
+    /// <param name="policy">The <see cref="AuthorizationPolicy"/>.></param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddPolicy(string name, AuthorizationPolicy policy)
+    {
+        Services.Configure<AuthorizationOptions>(o => o.AddPolicy(name, policy));
+        return this;
+    }
+
+    /// <summary>
+    /// Add a policy that is built from a delegate with the provided name.
+    /// </summary>
+    /// <param name="name">The name of the policy.</param>
+    /// <param name="configurePolicy">The delegate that will be used to build the policy.</param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
+    {
+        Services.Configure<AuthorizationOptions>(o => o.AddPolicy(name, configurePolicy));
+        return this;
+    }
+
+    /// <summary>
+    /// Add a policy that is built from a delegate with the provided name and used as the default policy.
+    /// </summary>
+    /// <param name="name">The name of the default policy.</param>
+    /// <param name="policy">The default <see cref="AuthorizationPolicy"/>.></param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddDefaultPolicy(string name, AuthorizationPolicy policy)
+    {
+        SetDefaultPolicy(policy);
+        return AddPolicy(name, policy);
+    }
+
+    /// <summary>
+    /// Add a policy that is built from a delegate with the provided name and used as the DefaultPolicy.
+    /// </summary>
+    /// <param name="name">The name of the DefaultPolicy.</param>
+    /// <param name="configurePolicy">The delegate that will be used to build the DefaultPolicy.</param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddDefaultPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
+    {
+        if (configurePolicy == null)
+        {
+            throw new ArgumentNullException(nameof(configurePolicy));
+        }
+
+        var policyBuilder = new AuthorizationPolicyBuilder();
+        configurePolicy(policyBuilder);
+        return AddDefaultPolicy(name, policyBuilder.Build());
+    }
+
+    /// <summary>
+    /// Add a policy that is built from a delegate with the provided name and used as the FallbackPolicy.
+    /// </summary>
+    /// <param name="name">The name of the FallbackPolicy.</param>
+    /// <param name="policy">The Fallback <see cref="AuthorizationPolicy"/>.></param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddFallbackPolicy(string name, AuthorizationPolicy policy)
+    {
+        SetFallbackPolicy(policy);
+        return AddPolicy(name, policy);
+    }
+
+    /// <summary>
+    /// Add a policy that is built from a delegate with the provided name and used as the FallbackPolicy.
+    /// </summary>
+    /// <param name="name">The name of the Fallback policy.</param>
+    /// <param name="configurePolicy">The delegate that will be used to build the Fallback policy.</param>
+    /// <returns>The builder.</returns>
+    public virtual AuthorizationBuilder AddFallbackPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
+    {
+        if (configurePolicy == null)
+        {
+            throw new ArgumentNullException(nameof(configurePolicy));
+        }
+
+        var policyBuilder = new AuthorizationPolicyBuilder();
+        configurePolicy(policyBuilder);
+        return AddFallbackPolicy(name, policyBuilder.Build());
+    }
+}
diff --git a/src/Security/Authorization/Core/src/AuthorizationOptions.cs b/src/Security/Authorization/Core/src/AuthorizationOptions.cs
index 1b53575a612..041553819e5 100644
--- a/src/Security/Authorization/Core/src/AuthorizationOptions.cs
+++ b/src/Security/Authorization/Core/src/AuthorizationOptions.cs
@@ -14,7 +14,7 @@ public class AuthorizationOptions
     private Dictionary<string, AuthorizationPolicy> PolicyMap { get; } = new Dictionary<string, AuthorizationPolicy>(StringComparer.OrdinalIgnoreCase);
 
     /// <summary>
-    /// Determines whether authentication handlers should be invoked after <see cref="AuthorizationHandlerContext.HasFailed"/>.
+    /// Determines whether authorization handlers should be invoked after <see cref="AuthorizationHandlerContext.HasFailed"/>.
     /// Defaults to true.
     /// </summary>
     public bool InvokeHandlersAfterFailure { get; set; } = true;
diff --git a/src/Security/Authorization/Core/src/PublicAPI.Unshipped.txt b/src/Security/Authorization/Core/src/PublicAPI.Unshipped.txt
index 30396d6df21..38f8cdf2c05 100644
--- a/src/Security/Authorization/Core/src/PublicAPI.Unshipped.txt
+++ b/src/Security/Authorization/Core/src/PublicAPI.Unshipped.txt
@@ -1,3 +1,15 @@
 #nullable enable
+Microsoft.AspNetCore.Authorization.AuthorizationBuilder
+Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AuthorizationBuilder(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> void
 Microsoft.AspNetCore.Authorization.Infrastructure.PassThroughAuthorizationHandler.PassThroughAuthorizationHandler(Microsoft.Extensions.Options.IOptions<Microsoft.AspNetCore.Authorization.AuthorizationOptions!>! options) -> void
 static Microsoft.AspNetCore.Authorization.AuthorizationPolicy.CombineAsync(Microsoft.AspNetCore.Authorization.IAuthorizationPolicyProvider! policyProvider, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Authorization.IAuthorizeData!>! authorizeData, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Authorization.AuthorizationPolicy!>! policies) -> System.Threading.Tasks.Task<Microsoft.AspNetCore.Authorization.AuthorizationPolicy?>!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddDefaultPolicy(string! name, Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddDefaultPolicy(string! name, System.Action<Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder!>! configurePolicy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddFallbackPolicy(string! name, Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddFallbackPolicy(string! name, System.Action<Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder!>! configurePolicy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddPolicy(string! name, Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.AddPolicy(string! name, System.Action<Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder!>! configurePolicy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.Services.get -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetDefaultPolicy(Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetFallbackPolicy(Microsoft.AspNetCore.Authorization.AuthorizationPolicy? policy) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
+virtual Microsoft.AspNetCore.Authorization.AuthorizationBuilder.SetInvokeHandlersAfterFailure(bool invoke) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
diff --git a/src/Security/Authorization/Policy/src/PolicyServiceCollectionExtensions.cs b/src/Security/Authorization/Policy/src/PolicyServiceCollectionExtensions.cs
index 4c4a958a098..dd7cfd7ccc3 100644
--- a/src/Security/Authorization/Policy/src/PolicyServiceCollectionExtensions.cs
+++ b/src/Security/Authorization/Policy/src/PolicyServiceCollectionExtensions.cs
@@ -12,6 +12,14 @@ namespace Microsoft.Extensions.DependencyInjection;
 /// </summary>
 public static class PolicyServiceCollectionExtensions
 {
+    /// <summary>
+    /// Adds authorization services to the specified <see cref="IServiceCollection" />.
+    /// </summary>
+    /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
+    /// <returns>The <see cref="AuthorizationBuilder"/> so that additional calls can be chained.</returns>
+    public static AuthorizationBuilder AddAuthorizationBuilder(this IServiceCollection services)
+        => new AuthorizationBuilder(services.AddAuthorization());
+
     /// <summary>
     /// Adds the authorization policy evaluator service to the specified <see cref="IServiceCollection" />.
     /// </summary>
diff --git a/src/Security/Authorization/Policy/src/PublicAPI.Unshipped.txt b/src/Security/Authorization/Policy/src/PublicAPI.Unshipped.txt
index 9c11d1e7b2d..4150e1ff1c7 100644
--- a/src/Security/Authorization/Policy/src/PublicAPI.Unshipped.txt
+++ b/src/Security/Authorization/Policy/src/PublicAPI.Unshipped.txt
@@ -1,3 +1,4 @@
 #nullable enable
 static Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization<TBuilder>(this TBuilder builder, Microsoft.AspNetCore.Authorization.AuthorizationPolicy! policy) -> TBuilder
 static Microsoft.AspNetCore.Builder.AuthorizationEndpointConventionBuilderExtensions.RequireAuthorization<TBuilder>(this TBuilder builder, System.Action<Microsoft.AspNetCore.Authorization.AuthorizationPolicyBuilder!>! configurePolicy) -> TBuilder
+static Microsoft.Extensions.DependencyInjection.PolicyServiceCollectionExtensions.AddAuthorizationBuilder(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.AspNetCore.Authorization.AuthorizationBuilder!
diff --git a/src/Security/Authorization/test/AuthorizationBuilderTests.cs b/src/Security/Authorization/test/AuthorizationBuilderTests.cs
new file mode 100644
index 00000000000..46c2b660668
--- /dev/null
+++ b/src/Security/Authorization/test/AuthorizationBuilderTests.cs
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.AspNetCore.Authorization.Infrastructure;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.AspNetCore.Authorization.Test;
+
+public class AuthorizationBuilderTests
+{
+    [Fact]
+    public void CanSetFallbackPolicy()
+    {
+        // Arrange
+        var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+        // Act
+            .SetFallbackPolicy(policy);
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        Assert.Equal(policy, options.FallbackPolicy);
+    }
+
+    [Fact]
+    public void CanUnSetFallbackPolicy()
+    {
+        // Arrange
+        var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+            .SetFallbackPolicy(policy)
+        // Act
+            .SetFallbackPolicy(null);
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        Assert.Null(options.FallbackPolicy);
+    }
+
+    [Fact]
+    public void CanSetDefaultPolicy()
+    {
+        // Arrange
+        var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+        // Act
+            .SetDefaultPolicy(policy);
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        Assert.Equal(policy, options.DefaultPolicy);
+    }
+
+    [Theory]
+    [InlineData(true)]
+    [InlineData(false)]
+    public void CanSetInvokeHandlersAfterFailure(bool invoke)
+    {
+        // Arrange
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+        // Act
+            .SetInvokeHandlersAfterFailure(invoke);
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        Assert.Equal(invoke, options.InvokeHandlersAfterFailure);
+    }
+
+    [Fact]
+    public void CanAddPolicyInstance()
+    {
+        // Arrange
+        var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+        // Act
+            .AddPolicy("name", policy);
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        Assert.Equal(policy, options.GetPolicy("name"));
+    }
+
+    [Fact]
+    public void CanAddPolicyDelegate()
+    {
+        // Arrange
+        var builder = TestHelpers.CreateAuthorizationBuilder()
+        // Act
+            .AddPolicy("name", p => p.RequireAssertion(_ => true));
+
+        var options = builder.Services.BuildServiceProvider().GetRequiredService<IOptions<AuthorizationOptions>>().Value;
+
+        // Assert
+        var policy = options.GetPolicy("name");
+        Assert.NotNull(policy);
+        Assert.Equal(1, policy.Requirements.Count);
+        Assert.IsType<AssertionRequirement>(policy.Requirements.First());
+    }
+}
+
+internal class TestHelpers
+{
+    public static AuthorizationBuilder CreateAuthorizationBuilder()
+    {
+        var services = new ServiceCollection();
+        services.AddLogging();
+        services.AddOptions();
+        return services.AddAuthorizationBuilder();
+    }
+}
diff --git a/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs b/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs
index 937adbc55ea..fcab4e0388b 100644
--- a/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs
+++ b/src/Security/Authorization/test/DefaultAuthorizationServiceTests.cs
@@ -37,12 +37,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
         var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }));
 
         // Act
@@ -58,13 +53,10 @@ public class DefaultAuthorizationServiceTests
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
         {
-            services.AddAuthorization(options =>
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy =>
             {
-                options.AddPolicy("Basic", policy =>
-                {
-                    policy.AddAuthenticationSchemes("Basic");
-                    policy.RequireClaim("Permission", "CanViewPage");
-                });
+                policy.AddAuthenticationSchemes("Basic");
+                policy.RequireClaim("Permission", "CanViewPage");
             });
         });
         var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[] { new Claim("Permission", "CanViewPage") }, "Basic"));
@@ -81,12 +73,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -113,10 +100,7 @@ public class DefaultAuthorizationServiceTests
         {
             services.AddSingleton<IAuthorizationHandler>(handler1);
             services.AddSingleton<IAuthorizationHandler>(handler2);
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
-            });
+            services.AddAuthorizationBuilder().AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
         });
 
         // Act
@@ -141,11 +125,9 @@ public class DefaultAuthorizationServiceTests
         {
             services.AddSingleton<IAuthorizationHandler>(handler1);
             services.AddSingleton<IAuthorizationHandler>(handler2);
-            services.AddAuthorization(options =>
-            {
-                options.InvokeHandlersAfterFailure = invokeAllHandlers;
-                options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
-            });
+            services.AddAuthorizationBuilder()
+            .AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()))
+            .SetInvokeHandlersAfterFailure(invokeAllHandlers);
         });
 
         // Act
@@ -196,10 +178,7 @@ public class DefaultAuthorizationServiceTests
             services.AddSingleton<IAuthorizationHandler>(handler1);
             services.AddSingleton<IAuthorizationHandler>(handler2);
             services.AddSingleton<IAuthorizationHandler>(handler3);
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
-            });
+            services.AddAuthorizationBuilder().AddPolicy("Custom", policy => policy.Requirements.Add(new CustomRequirement()));
         });
 
         // Act
@@ -222,12 +201,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -249,12 +223,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage", "CanViewAnything")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -275,12 +244,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -301,12 +265,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[0],
@@ -325,12 +284,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
 
         // Act
         var allowed = await authorizationService.AuthorizeAsync(null, null, "Basic");
@@ -344,12 +298,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
         var user = new ClaimsPrincipal(new ClaimsIdentity());
 
         // Act
@@ -364,12 +313,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireClaim("Permission", "CanViewPage")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -517,12 +461,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => policy.RequireRole("Admin", "Users"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => policy.RequireRole("Admin", "Users")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
@@ -541,12 +480,7 @@ public class DefaultAuthorizationServiceTests
     public void PolicyThrowsWithNoRequirements()
     {
         Assert.Throws<InvalidOperationException>(() => BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Basic", policy => { });
-            });
-        }));
+            services.AddAuthorizationBuilder().AddPolicy("Basic", policy => { })));
     }
 
     [Fact]
@@ -554,12 +488,7 @@ public class DefaultAuthorizationServiceTests
     {
         // Arrange
         var authorizationService = BuildAuthorizationService(services =>
-        {
-            services.AddAuthorization(options =>
-            {
-                options.AddPolicy("Hao", policy => policy.RequireUserName("Hao"));
-            });
-        });
+            services.AddAuthorizationBuilder().AddPolicy("Hao", policy => policy.RequireUserName("Hao")));
         var user = new ClaimsPrincipal(
             new ClaimsIdentity(
                 new Claim[] {
-- 
GitLab