diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/IPageApplicationModelConvention.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/IPageApplicationModelConvention.cs
index 2dbe608d8c..2ffe77c41b 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/IPageApplicationModelConvention.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/ApplicationModels/IPageApplicationModelConvention.cs
@@ -6,7 +6,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
///
/// Allows customization of the of the .
///
- public interface IPageModelConvention
+ public interface IPageApplicationModelConvention
{
///
/// Called to apply the convention to the .
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcBuilderExtensions.cs
new file mode 100644
index 0000000000..353eaab441
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcBuilderExtensions.cs
@@ -0,0 +1,39 @@
+// 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;
+using Microsoft.AspNetCore.Mvc.Razor;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// Extensions methods for configuring Razor Pages via an .
+ ///
+ public static class MvcRazorPagesMvcBuilderExtensions
+ {
+ ///
+ /// Configures a set of for the application.
+ ///
+ /// The .
+ /// An action to configure the .
+ /// The .
+ public static IMvcBuilder AddRazorPagesOptions(
+ this IMvcBuilder builder,
+ Action setupAction)
+ {
+ if (builder == null)
+ {
+ throw new ArgumentNullException(nameof(builder));
+ }
+
+ if (setupAction == null)
+ {
+ throw new ArgumentNullException(nameof(setupAction));
+ }
+
+ builder.Services.Configure(setupAction);
+ return builder;
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
index 974dfb8ff5..bb71084366 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/MvcRazorPagesMvcCoreBuilderExtensions.cs
@@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Options;
namespace Microsoft.Extensions.DependencyInjection
{
@@ -51,6 +52,11 @@ namespace Microsoft.Extensions.DependencyInjection
// Internal for testing.
internal static void AddServices(IServiceCollection services)
{
+ services.TryAddEnumerable(
+ ServiceDescriptor.Transient<
+ IConfigureOptions,
+ RazorPagesOptionsSetup>());
+
services.TryAddEnumerable(
ServiceDescriptor.Singleton());
@@ -72,6 +78,7 @@ namespace Microsoft.Extensions.DependencyInjection
services.TryAddSingleton();
services.TryAddSingleton();
+
}
}
}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs
new file mode 100644
index 0000000000..7723852da9
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/DependencyInjection/RazorPagesOptionsExtensions.cs
@@ -0,0 +1,134 @@
+// 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;
+using Microsoft.AspNetCore.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.Authorization;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ ///
+ /// Extensions for .
+ ///
+ public static class RazorPagesOptionsExtensions
+ {
+ ///
+ /// Configures the specified to apply to all Razor Pages.
+ ///
+ /// The to configure.
+ /// The to add.
+ /// The .
+ public static RazorPagesOptions ConfigureFilter(this RazorPagesOptions options, IFilterMetadata filter)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (filter == null)
+ {
+ throw new ArgumentNullException(nameof(filter));
+ }
+
+ options.Conventions.Add(new FolderConvention("/", model => model.Filters.Add(filter)));
+ return options;
+ }
+
+ ///
+ /// Adds a with the specified policy to the page with the specified path.
+ ///
+ /// The to configure.
+ /// The path of the Razor Page.
+ /// The authorization policy.
+ /// The .
+ public static RazorPagesOptions AuthorizePage(this RazorPagesOptions options, string path, string policy)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(path));
+ }
+
+ var authorizeFilter = new AuthorizeFilter(policy);
+ options.Conventions.Add(new PageConvention(path, model => model.Filters.Add(authorizeFilter)));
+ return options;
+ }
+
+ ///
+ /// Adds a with the specified policy to all page under the specified path.
+ ///
+ /// The to configure.
+ /// The folder path.
+ /// The authorization policy.
+ /// The .
+ public static RazorPagesOptions AuthorizeFolder(this RazorPagesOptions options, string folderPath, string policy)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ if (string.IsNullOrEmpty(folderPath))
+ {
+ throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, nameof(folderPath));
+ }
+
+ var authorizeFilter = new AuthorizeFilter(policy);
+ options.Conventions.Add(new FolderConvention(folderPath, model => model.Filters.Add(authorizeFilter)));
+ return options;
+ }
+
+ private class PageConvention : IPageApplicationModelConvention
+ {
+ private readonly string _path;
+ private readonly Action _action;
+
+ public PageConvention(string path, Action action)
+ {
+ _path = path;
+ _action = action;
+ }
+
+ public void Apply(PageApplicationModel model)
+ {
+ if (string.Equals(model.ViewEnginePath, _path, StringComparison.OrdinalIgnoreCase))
+ {
+ _action(model);
+ }
+ }
+ }
+
+ private class FolderConvention : IPageApplicationModelConvention
+ {
+ private readonly string _folderPath;
+ private readonly Action _action;
+
+ public FolderConvention(string folderPath, Action action)
+ {
+ _folderPath = folderPath.TrimEnd('/');
+ _action = action;
+ }
+
+ public void Apply(PageApplicationModel model)
+ {
+ var viewEnginePath = model.ViewEnginePath;
+
+ var applyConvention = _folderPath == "/" ||
+ (viewEnginePath.Length > _folderPath.Length &&
+ viewEnginePath.StartsWith(_folderPath, StringComparison.OrdinalIgnoreCase) &&
+ viewEnginePath[_folderPath.Length] == '/');
+
+ if (applyConvention)
+ {
+ _action(model);
+ }
+ }
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs
index c748673790..b9333afe6c 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Infrastructure/PageActionDescriptorProvider.cs
@@ -7,7 +7,6 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Routing;
-using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.Extensions.Options;
@@ -85,9 +84,6 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
model.Selectors.Add(CreateSelectorModel(parentDirectoryPath, template));
}
- model.Filters.Add(new SaveTempDataPropertyFilter()); // Support for [TempData] on properties
- model.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()); // Always require an antiforgery token on post
-
for (var i = 0; i < _pagesOptions.Conventions.Count; i++)
{
_pagesOptions.Conventions[i].Apply(model);
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs
new file mode 100644
index 0000000000..18c32c7c82
--- /dev/null
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/Internal/RazorPagesOptionsSetup.cs
@@ -0,0 +1,26 @@
+// 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;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Options;
+
+namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
+{
+ public class RazorPagesOptionsSetup : IConfigureOptions
+ {
+ public void Configure(RazorPagesOptions options)
+ {
+ if (options == null)
+ {
+ throw new ArgumentNullException(nameof(options));
+ }
+
+ // Support for [TempData] on properties
+ options.ConfigureFilter(new SaveTempDataPropertyFilter());
+ // Always require an antiforgery token on post
+ options.ConfigureFilter(new AutoValidateAntiforgeryTokenAttribute());
+ }
+ }
+}
diff --git a/src/Microsoft.AspNetCore.Mvc.RazorPages/RazorPagesOptions.cs b/src/Microsoft.AspNetCore.Mvc.RazorPages/RazorPagesOptions.cs
index 4d931a796c..e7a5d5b37e 100644
--- a/src/Microsoft.AspNetCore.Mvc.RazorPages/RazorPagesOptions.cs
+++ b/src/Microsoft.AspNetCore.Mvc.RazorPages/RazorPagesOptions.cs
@@ -1,6 +1,7 @@
// 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;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
@@ -12,9 +13,9 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages
public class RazorPagesOptions
{
///
- /// Gets a list of instances that will be applied to
+ /// Gets a list of instances that will be applied to
/// the when discovering Razor Pages.
///
- public IList Conventions { get; } = new List();
+ public IList Conventions { get; } = new List();
}
}
\ No newline at end of file
diff --git a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
index b67c5405f2..1420b1a1c6 100644
--- a/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.FunctionalTests/RazorPagesTest.cs
@@ -131,6 +131,20 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
Assert.Equal("Hi2", content.Trim());
}
+ [Fact]
+ public async Task AuthorizePage_AddsAuthorizationForSpecificPages()
+ {
+ // Arrange
+ var url = "/HelloWorldWithAuth";
+
+ // Act
+ var response = await Client.GetAsync(url);
+
+ // Assert
+ Assert.Equal(HttpStatusCode.Redirect, response.StatusCode);
+ Assert.Equal("/Login?ReturnUrl=%2FHelloWorldWithAuth", response.Headers.Location.PathAndQuery);
+ }
+
private static string GetCookie(HttpResponseMessage response)
{
var setCookie = response.Headers.GetValues("Set-Cookie").ToArray();
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/MvcRazorPagesMvcBuilderExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/MvcRazorPagesMvcBuilderExtensionsTest.cs
new file mode 100644
index 0000000000..548fc09dbd
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/MvcRazorPagesMvcBuilderExtensionsTest.cs
@@ -0,0 +1,38 @@
+// 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.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.ApplicationParts;
+using Microsoft.AspNetCore.Mvc.Internal;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Microsoft.Extensions.Options;
+using Moq;
+using Xunit;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public class MvcRazorPagesMvcBuilderExtensionsTest
+ {
+ [Fact]
+ public void AddRazorPagesOptions_AddsApplicationModelConventions()
+ {
+ // Arrange
+ var services = new ServiceCollection().AddOptions();
+ var expected = Mock.Of();
+ var builder = new MvcBuilder(services, new ApplicationPartManager());
+ builder.AddRazorPagesOptions(options =>
+ {
+ options.Conventions.Add(expected);
+ });
+ var serviceProvider = services.BuildServiceProvider();
+ var accessor = serviceProvider.GetRequiredService>();
+
+ // Act
+ var conventions = accessor.Value.Conventions;
+
+ // Assert
+ Assert.Collection(conventions,
+ convention => Assert.Same(expected, convention));
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/RazorPagesOptionsExtensionsTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/RazorPagesOptionsExtensionsTest.cs
new file mode 100644
index 0000000000..6f2bca034c
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/DependencyInjection/RazorPagesOptionsExtensionsTest.cs
@@ -0,0 +1,117 @@
+// 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.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.Authorization;
+using Microsoft.AspNetCore.Mvc.Filters;
+using Microsoft.AspNetCore.Mvc.RazorPages;
+using Moq;
+using Xunit;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+ public class RazorPagesOptionsExtensionsTest
+ {
+ [Fact]
+ public void AddFilter_AddsFiltersToAllPages()
+ {
+ // Arrange
+ var filter = Mock.Of();
+ var options = new RazorPagesOptions();
+ var models = new[]
+ {
+ new PageApplicationModel("/Pages/Index.cshtml", "/Index.cshtml"),
+ new PageApplicationModel("/Pages/Users/Account.cshtml", "/Users/Account.cshtml"),
+ new PageApplicationModel("/Pages/Users/Contact.cshtml", "/Users/Contact.cshtml"),
+ };
+
+ // Act
+ options.ConfigureFilter(filter);
+ ApplyConventions(options, models);
+
+ // Assert
+ Assert.Collection(models,
+ model => Assert.Same(filter, Assert.Single(model.Filters)),
+ model => Assert.Same(filter, Assert.Single(model.Filters)),
+ model => Assert.Same(filter, Assert.Single(model.Filters)));
+ }
+
+ [Fact]
+ public void AuthorizePage_AddsAuthorizeFilterToSpecificPage()
+ {
+ // Arrange
+ var options = new RazorPagesOptions();
+ var models = new[]
+ {
+ new PageApplicationModel("/Pages/Index.cshtml", "/Index.cshtml"),
+ new PageApplicationModel("/Pages/Users/Account.cshtml", "/Users/Account.cshtml"),
+ new PageApplicationModel("/Pages/Users/Contact.cshtml", "/Users/Contact.cshtml"),
+ };
+
+ // Act
+ options.AuthorizePage("/Users/Account.cshtml", "Manage-Accounts");
+ ApplyConventions(options, models);
+
+ // Assert
+ Assert.Collection(models,
+ model => Assert.Empty(model.Filters),
+ model =>
+ {
+ Assert.Equal("/Users/Account.cshtml", model.ViewEnginePath);
+ var authorizeFilter = Assert.IsType(Assert.Single(model.Filters));
+ var authorizeData = Assert.IsType(Assert.Single(authorizeFilter.AuthorizeData));
+ Assert.Equal("Manage-Accounts", authorizeData.Policy);
+ },
+ model => Assert.Empty(model.Filters));
+ }
+
+ [Theory]
+ [InlineData("/Users")]
+ [InlineData("/Users/")]
+ public void AuthorizePage_AddsAuthorizeFilterToPagesUnderFolder(string folderName)
+ {
+ // Arrange
+ var options = new RazorPagesOptions();
+ var models = new[]
+ {
+ new PageApplicationModel("/Pages/Index.cshtml", "/Index.cshtml"),
+ new PageApplicationModel("/Pages/Users/Account.cshtml", "/Users/Account.cshtml"),
+ new PageApplicationModel("/Pages/Users/Contact.cshtml", "/Users/Contact.cshtml"),
+ };
+
+ // Act
+ options.AuthorizeFolder(folderName, "Manage-Accounts");
+ ApplyConventions(options, models);
+
+ // Assert
+ Assert.Collection(models,
+ model => Assert.Empty(model.Filters),
+ model =>
+ {
+ Assert.Equal("/Users/Account.cshtml", model.ViewEnginePath);
+ var authorizeFilter = Assert.IsType(Assert.Single(model.Filters));
+ var authorizeData = Assert.IsType(Assert.Single(authorizeFilter.AuthorizeData));
+ Assert.Equal("Manage-Accounts", authorizeData.Policy);
+ },
+ model =>
+ {
+ Assert.Equal("/Users/Contact.cshtml", model.ViewEnginePath);
+ var authorizeFilter = Assert.IsType(Assert.Single(model.Filters));
+ var authorizeData = Assert.IsType(Assert.Single(authorizeFilter.AuthorizeData));
+ Assert.Equal("Manage-Accounts", authorizeData.Policy);
+ });
+ }
+
+ private static void ApplyConventions(RazorPagesOptions options, PageApplicationModel[] models)
+ {
+ foreach (var convention in options.Conventions)
+ {
+ foreach (var model in models)
+ {
+ convention.Apply(model);
+ }
+ }
+ }
+ }
+}
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs
index d023636248..dc3f7055e5 100644
--- a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Infrastructure/PageActionDescriptorProviderTest.cs
@@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.AspNetCore.Mvc.Razor.Internal;
+using Microsoft.AspNetCore.Mvc.RazorPages.Internal;
using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
using Microsoft.AspNetCore.Razor.Evolution;
using Microsoft.Extensions.Options;
@@ -30,7 +31,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -53,7 +54,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -80,7 +81,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -109,7 +110,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act and Assert
@@ -133,7 +134,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -170,7 +171,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -208,7 +209,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(options),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -250,7 +251,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(options),
- GetAccessor());
+ GetRazorPagesOptions());
var context = new ActionDescriptorProviderContext();
// Act
@@ -291,14 +292,14 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var localFilter = Mock.Of();
var options = new MvcOptions();
options.Filters.Add(globalFilter);
- var convention = new Mock();
+ var convention = new Mock();
convention.Setup(c => c.Apply(It.IsAny()))
.Callback((PageApplicationModel model) =>
{
model.Filters.Add(localFilter);
});
- var razorOptions = new RazorPagesOptions();
- razorOptions.Conventions.Add(convention.Object);
+ var razorOptions = GetRazorPagesOptions();
+ razorOptions.Value.Conventions.Add(convention.Object);
var razorProject = new Mock();
razorProject.Setup(p => p.EnumerateItems("/"))
@@ -309,7 +310,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
var provider = new PageActionDescriptorProvider(
razorProject.Object,
GetAccessor(options),
- GetAccessor(razorOptions));
+ razorOptions);
var context = new ActionDescriptorProviderContext();
// Act
@@ -349,6 +350,11 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
return accessor.Object;
}
+ private static IOptions GetRazorPagesOptions()
+ {
+ return new OptionsManager(new[] { new RazorPagesOptionsSetup() });
+ }
+
private static RazorProjectItem GetProjectItem(string basePath, string path, string content)
{
var testFileInfo = new TestFileInfo
diff --git a/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs
new file mode 100644
index 0000000000..54b3d4d863
--- /dev/null
+++ b/test/Microsoft.AspNetCore.Mvc.RazorPages.Test/Internal/RazorPagesOptionsSetupTest.cs
@@ -0,0 +1,33 @@
+// 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.Mvc.ApplicationModels;
+using Microsoft.AspNetCore.Mvc.ViewFeatures.Internal;
+using Xunit;
+
+namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
+{
+ public class RazorPagesOptionsSetupTest
+ {
+ [Fact]
+ public void Configure_AddsGlobalFilters()
+ {
+ // Arrange
+ var options = new RazorPagesOptions();
+ var setup = new RazorPagesOptionsSetup();
+ var applicationModel = new PageApplicationModel("/Home.cshtml", "/Home.cshtml");
+
+ // Act
+ setup.Configure(options);
+ foreach (var convention in options.Conventions)
+ {
+ convention.Apply(applicationModel);
+ }
+
+ // Assert
+ Assert.Collection(applicationModel.Filters,
+ filter => Assert.IsType(filter),
+ filter => Assert.IsType(filter));
+ }
+ }
+}
diff --git a/test/WebSites/RazorPagesWebSite/HelloWorldWithAuth.cshtml b/test/WebSites/RazorPagesWebSite/HelloWorldWithAuth.cshtml
new file mode 100644
index 0000000000..c6a654ccce
--- /dev/null
+++ b/test/WebSites/RazorPagesWebSite/HelloWorldWithAuth.cshtml
@@ -0,0 +1,3 @@
+@page
+
+Can't see me
\ No newline at end of file
diff --git a/test/WebSites/RazorPagesWebSite/Login.cshtml b/test/WebSites/RazorPagesWebSite/Login.cshtml
new file mode 100644
index 0000000000..939fa6c3ed
--- /dev/null
+++ b/test/WebSites/RazorPagesWebSite/Login.cshtml
@@ -0,0 +1,2 @@
+@page
+@Context.Request.Query["ReturnUrl"]
\ No newline at end of file
diff --git a/test/WebSites/RazorPagesWebSite/RazorPagesWebSite.csproj b/test/WebSites/RazorPagesWebSite/RazorPagesWebSite.csproj
index 2303099db6..31acae6182 100644
--- a/test/WebSites/RazorPagesWebSite/RazorPagesWebSite.csproj
+++ b/test/WebSites/RazorPagesWebSite/RazorPagesWebSite.csproj
@@ -10,6 +10,7 @@
+
diff --git a/test/WebSites/RazorPagesWebSite/Startup.cs b/test/WebSites/RazorPagesWebSite/Startup.cs
index 0959cd28d8..1ec471eca4 100644
--- a/test/WebSites/RazorPagesWebSite/Startup.cs
+++ b/test/WebSites/RazorPagesWebSite/Startup.cs
@@ -10,15 +10,28 @@ namespace RazorPagesWebSite
{
public void ConfigureServices(IServiceCollection services)
{
- services.AddMvc().AddCookieTempDataProvider();
+ services
+ .AddMvc()
+ .AddCookieTempDataProvider()
+ .AddRazorPagesOptions(options =>
+ {
+ options.AuthorizePage("/HelloWorldWithAuth", string.Empty);
+ });
}
public void Configure(IApplicationBuilder app)
{
app.UseCultureReplacer();
+ app.UseCookieAuthentication(new CookieAuthenticationOptions
+ {
+ LoginPath = "/Login",
+ AutomaticAuthenticate = true,
+ AutomaticChallenge = true
+ });
+
app.UseStaticFiles();
-
+
app.UseMvc();
}
}