diff --git a/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs b/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs
index c6ecc5c699..356276852d 100644
--- a/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs
+++ b/src/Microsoft.AspNetCore.Mvc.Core/Authorization/AuthorizeFilter.cs
@@ -22,6 +22,14 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
///
public class AuthorizeFilter : IAsyncAuthorizationFilter, IFilterFactory
{
+ ///
+ /// Initializes a new instance.
+ ///
+ public AuthorizeFilter()
+ : this(authorizeData: new[] { new AuthorizeAttribute() })
+ {
+ }
+
///
/// Initialize a new instance.
///
diff --git a/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs
index 3429bad91e..7222cb16ab 100644
--- a/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.Core.Test/Authorization/AuthorizeFilterTest.cs
@@ -26,6 +26,26 @@ namespace Microsoft.AspNetCore.Mvc.Authorization
Assert.Contains(authorizationContext.HttpContext.User.Identities, i => i.IsAuthenticated);
}
+ [Fact]
+ public async Task DefaultConstructor_DeniesAnonymousUsers()
+ {
+ // Arrange
+ var authorizationContext = GetAuthorizationContext(anonymous: true);
+ // The type 'AuthorizeFilter' is both a filter by itself and also a filter factory.
+ // The default filter provider first checks if a type is a filter factory and creates an instance of
+ // this filter.
+ var authorizeFilterFactory = new AuthorizeFilter();
+ var filterFactory = authorizeFilterFactory as IFilterFactory;
+ var authorizeFilter = (AuthorizeFilter)filterFactory.CreateInstance(
+ authorizationContext.HttpContext.RequestServices);
+
+ // Act
+ await authorizeFilter.OnAuthorizationAsync(authorizationContext);
+
+ // Assert
+ Assert.IsType(authorizationContext.Result);
+ }
+
[Fact]
public async Task AuthorizeFilter_CreatedWithAuthorizeData_ThrowsWhenOnAuthorizationAsyncIsCalled()
{
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs
new file mode 100644
index 0000000000..9eecde77ed
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/GlobalAuthorizationFilterTest.cs
@@ -0,0 +1,46 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.FunctionalTests
+{
+ public class GlobalAuthorizationFilterTest : IClassFixture>
+ {
+ public GlobalAuthorizationFilterTest(MvcTestFixture fixture)
+ {
+ Client = fixture.Client;
+ }
+
+ public HttpClient Client { get; }
+
+ [Fact]
+ public async Task DeniesAnonymousUsers_ByDefault()
+ {
+ // Arrange & Act
+ var response = await Client.GetAsync("http://localhost/Administration/Index");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ Assert.NotNull(response.Headers.Location);
+ Assert.Equal(
+ "http://localhost/Home/Login?ReturnUrl=%2FAdministration%2FIndex",
+ response.Headers.Location.ToString());
+ }
+
+ [Fact]
+ public async Task AllowAnonymousUsers_ForActionsWithAllowAnonymousAttribute()
+ {
+ // Arrange & Act
+ var response = await Client.GetAsync("http://localhost/Administration/AllowAnonymousAction");
+
+ // Assert
+ Assert.Equal(HttpStatusCode.OK, response.StatusCode);
+ var body = await response.Content.ReadAsStringAsync();
+ Assert.Equal("Administration.AllowAnonymousAction", body);
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs b/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs
new file mode 100644
index 0000000000..ac7be06b5e
--- /dev/null
+++ b/test/WebSites/SecurityWebSite/Controllers/AdministrationController.cs
@@ -0,0 +1,24 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+
+namespace SecurityWebSite.Controllers
+{
+ // This controller is secured through the globally added authorize filter which
+ // allows only authenticated users.
+ public class AdministrationController : Controller
+ {
+ public IActionResult Index()
+ {
+ return Content("Administration.Index");
+ }
+
+ [AllowAnonymous]
+ public IActionResult AllowAnonymousAction()
+ {
+ return Content("Administration.AllowAnonymousAction");
+ }
+ }
+}
diff --git a/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs b/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs
new file mode 100644
index 0000000000..af49233670
--- /dev/null
+++ b/test/WebSites/SecurityWebSite/StartupWithGlobalDenyAnonymousFilter.cs
@@ -0,0 +1,36 @@
+// Copyright (c) .NET Foundation. All rights reserved.
+// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
+
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Mvc.Authorization;
+using Microsoft.Extensions.DependencyInjection;
+
+namespace SecurityWebSite
+{
+ public class StartupWithGlobalDenyAnonymousFilter
+ {
+ public void ConfigureServices(IServiceCollection services)
+ {
+ services
+ .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
+ .AddCookie(options =>
+ {
+ options.LoginPath = "/Home/Login";
+ options.LogoutPath = "/Home/Logout";
+ });
+
+ services.AddMvc(o =>
+ {
+ o.Filters.Add(new AuthorizeFilter());
+ });
+ }
+
+ public void Configure(IApplicationBuilder app)
+ {
+ app.UseAuthentication();
+
+ app.UseMvcWithDefaultRoute();
+ }
+ }
+}