-
Notifications
You must be signed in to change notification settings - Fork 24.8k
Roll Blazor into the Simple Auth article #36650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
abcdae3
Roll Blazor into the Simple Auth article
guardrex 9597a71
Updates
guardrex 45ce0bd
Updates
guardrex f11a443
Updates
guardrex b6a341e
Updates
guardrex e85e4d2
Updates
guardrex bc6e755
Apply suggestions from code review
guardrex e0d3848
Fix AuthorizeIndexPageHandlerFilter security flaw: pipeline not short…
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| --- | ||
| title: Simple authorization in ASP.NET Core MVC | ||
| ai-usage: ai-assisted | ||
| author: tdykstra | ||
| description: Learn how to use the [Authorize] attribute to restrict access in ASP.NET Core MVC apps. | ||
| ms.author: tdykstra | ||
| ms.date: 03/05/2026 | ||
| uid: mvc/security/authorization/simple | ||
| --- | ||
| # Simple authorization in ASP.NET Core MVC | ||
|
|
||
| Authorization in ASP.NET Core is controlled with the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) and its various parameters. In its most basic form, applying the `[Authorize]` attribute to a Razor component, controller, action, or Razor Page, limits access to that component to authenticated users. | ||
|
|
||
| This article covers scenarios that pertain to MVC apps. For the primary coverage on this subject, see <xref:security/authorization/simple>. | ||
|
|
||
| ## `[Authorize]` attribute | ||
|
|
||
| The following example limits access to authenticated users by specifying the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute): | ||
|
|
||
| ```csharp | ||
| [Authorize] | ||
| public class AccountController : Controller | ||
| { | ||
| public ActionResult Login() { ... } | ||
| public ActionResult Logout() { ... } | ||
| } | ||
| ``` | ||
|
|
||
| The [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) also supports role-based or policy-based authorization. For role-based authorization, use the <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Roles> parameter. In the following example, the user can only access the page if they're in the `Admin` or `Superuser` role: | ||
|
|
||
| ```csharp | ||
| [Authorize(Roles = "Admin, Superuser")] | ||
| public class OrderController : Controller | ||
| { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| For policy-based authorization, use the <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Policy> parameter. In the following example, the user can only access the page if they satisfy the requirements of the `Over21` [authorization policy](xref:security/authorization/policies): | ||
|
|
||
| ```csharp | ||
| [Authorize(Policy = "Over21")] | ||
| public class LicenseApplicationController : Controller | ||
| { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| If neither <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Roles> nor <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Policy> is specified, [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) uses the default policy: | ||
|
|
||
| * Authenticated (signed-in) users are authorized. | ||
| * Unauthenticated (signed-out) users are unauthorized. | ||
|
|
||
| To apply authorization to an action rather than the controller, apply the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the action. In the following example, only authenticated users can trigger a logout (call the `Logout` method): | ||
|
|
||
| ```csharp | ||
| public class AccountController : Controller | ||
| { | ||
| public ActionResult Login() { ... } | ||
|
|
||
| [Authorize] | ||
| public ActionResult Logout() { ... } | ||
| } | ||
| ``` | ||
|
|
||
| Use the [`[AllowAnonymous]` attribute](xref:Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute) to allow access by non-authenticated users to individual actions: | ||
|
|
||
| ```csharp | ||
| [AllowAnonymous] | ||
| ``` | ||
|
|
||
| > [!WARNING] | ||
| > For MVC controllers, the [`[AllowAnonymous]` attribute](xref:Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute) bypasses authorization statements. If you combine `[AllowAnonymous]` and one or more `[Authorize]` attributes, the `[Authorize]` attributes are ignored. If you apply `[AllowAnonymous]` at the controller level: | ||
| > | ||
| > * Any authorization requirements from `[Authorize]` attributes on the same controller or action methods on the controller are ignored. | ||
| > * Authentication middleware isn't short-circuited but doesn't need to succeed. | ||
|
|
||
| For information on how to require authentication for all app users, see <xref:security/authorization/secure-data#require-authenticated-users>. | ||
|
|
||
| ## Additional resources | ||
|
|
||
| * <xref:security/authorization/simple> | ||
| * <xref:razor-pages/security/authorization/simple> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
177 changes: 177 additions & 0 deletions
177
aspnetcore/razor-pages/security/authorization/simple.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| --- | ||
| title: Simple authorization in ASP.NET Core Razor Pages | ||
| ai-usage: ai-assisted | ||
| author: tdykstra | ||
| description: Learn how to use the [Authorize] attribute to restrict access in ASP.NET Core Razor Pages apps. | ||
| ms.author: tdykstra | ||
| ms.date: 03/05/2026 | ||
| uid: razor-pages/security/authorization/simple | ||
| --- | ||
| # Simple authorization in ASP.NET Core Razor Pages | ||
|
|
||
| Authorization in ASP.NET Core is controlled with the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) and its various parameters. In its most basic form, applying the `[Authorize]` attribute to a Razor component, controller, action, or Razor Page, limits access to that component to authenticated users. | ||
|
|
||
| This article covers scenarios that pertain to Razor Pages apps. For more information, see <xref:security/authorization/simple>. | ||
|
|
||
| ## `[Authorize]` attribute | ||
|
|
||
| Apply the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) to the page model class that derives from <xref:Microsoft.AspNetCore.Mvc.RazorPages.PageModel>. In the following example, only authenticated users can reach the `LogoutModel` page: | ||
|
|
||
| ```csharp | ||
| [Authorize] | ||
| public class LogoutModel : PageModel | ||
| { | ||
| public async Task OnGetAsync() { ... } | ||
| public async Task<IActionResult> OnPostAsync() { ... } | ||
| } | ||
| ``` | ||
|
|
||
| The [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) also supports role-based or policy-based authorization. For role-based authorization, use the <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Roles> parameter. In the following example, the user can only access the page if they're in the `Admin` or `Superuser` role: | ||
|
|
||
| ```csharp | ||
| [Authorize(Roles = "Admin, Superuser")] | ||
| public class OrderModel : PageModel | ||
| { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| For policy-based authorization, use the <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Policy> parameter. In the following example, the user can only access the page if they satisfy the requirements of the `Over21` [authorization policy](xref:security/authorization/policies): | ||
|
|
||
| ```csharp | ||
| [Authorize(Policy = "Over21")] | ||
| public class LicenseApplicationModel : PageModel | ||
| { | ||
| ... | ||
| } | ||
| ``` | ||
|
|
||
| If neither <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Roles> nor <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute.Policy> is specified, [`[Authorize]`](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) uses the default policy: | ||
|
|
||
| * Authenticated (signed-in) users are authorized. | ||
| * Unauthenticated (signed-out) users are unauthorized. | ||
|
|
||
| For guidance on <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute> and Razor Page handlers, see the [`[Authorize]` attribute in Razor Pages apps](#authorize-attribute-in-razor-pages-apps) section. | ||
|
|
||
| Use the [`[AllowAnonymous]` attribute](xref:Microsoft.AspNetCore.Authorization.AllowAnonymousAttribute) to allow access by non-authenticated users to individual actions: | ||
|
|
||
| ```csharp | ||
| [AllowAnonymous] | ||
| ``` | ||
|
|
||
| For information on how to require authentication for all app users, see <xref:security/authorization/secure-data#require-authenticated-users>. | ||
|
|
||
| ## `[Authorize]` attribute in Razor Pages apps | ||
|
|
||
| The <xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute> can't be applied to Razor Page handlers. For example, the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) can't be applied to `OnGet`, `OnPost`, or any other page handler. In a Razor Pages app, consider using an ASP.NET Core MVC controller for pages with different authorization requirements for different handlers. Using a controller when different authorization requirements are required is the least complex approach we recommend. | ||
|
|
||
| If you decide not to use an MVC controller, the following two approaches can be used to apply authorization to Razor Page handler methods: | ||
|
|
||
| * Use separate pages for page handlers requiring different authorization. Move shared content into one or more [partial views](xref:mvc/views/partial). When possible, this is the recommended approach. | ||
| * For content that must share a common page, write a filter that performs authorization as part of <xref:Microsoft.AspNetCore.Mvc.Filters.IAsyncPageFilter.OnPageHandlerExecutionAsync%2A?displayProperty=nameWithType>. This approach is demonstrated by the following example. | ||
|
|
||
| The `AuthorizeIndexPageHandlerFilter` implements the authorization filter: | ||
|
|
||
| ```csharp | ||
| public class AuthorizeIndexPageHandlerFilter( | ||
| IAuthorizationPolicyProvider policyProvider, | ||
| IPolicyEvaluator policyEvaluator) : IAsyncPageFilter, IOrderedFilter | ||
| { | ||
| private readonly IAuthorizationPolicyProvider policyProvider = | ||
| policyProvider; | ||
| private readonly IPolicyEvaluator policyEvaluator = policyEvaluator; | ||
|
|
||
| // Run late in the execution pipeline | ||
| public int Order => 10000; | ||
|
|
||
| public async Task OnPageHandlerExecutionAsync(PageHandlerExecutingContext context, | ||
| PageHandlerExecutionDelegate next) | ||
| { | ||
| var attribute = context.HandlerMethod?.MethodInfo? | ||
| .GetCustomAttribute<AuthorizePageHandlerAttribute>(); | ||
|
|
||
| if (attribute is null) | ||
| { | ||
| await next(); | ||
| return; | ||
| } | ||
|
|
||
| var policy = await AuthorizationPolicy | ||
| .CombineAsync(policyProvider, new[] { attribute }); | ||
|
|
||
| if (policy is null) | ||
| { | ||
| await next(); | ||
| return; | ||
| } | ||
|
|
||
| var httpContext = context.HttpContext; | ||
| var authenticateResult = await policyEvaluator | ||
| .AuthenticateAsync(policy, httpContext); | ||
| var authorizeResult = await policyEvaluator | ||
| .AuthorizeAsync(policy, authenticateResult, httpContext, | ||
| context.ActionDescriptor); | ||
|
|
||
| if (authorizeResult.Challenged) | ||
| { | ||
| context.Result = policy.AuthenticationSchemes.Count > 0 | ||
| ? new ChallengeResult(policy.AuthenticationSchemes.ToArray()) | ||
| : new ChallengeResult(); | ||
|
|
||
| return; | ||
| } | ||
| else if (authorizeResult.Forbidden) | ||
| { | ||
| context.Result = policy.AuthenticationSchemes.Count > 0 | ||
| ? new ForbidResult(policy.AuthenticationSchemes.ToArray()) | ||
| : new ForbidResult(); | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| await next(); | ||
| } | ||
|
|
||
| public Task OnPageHandlerSelectionAsync(PageHandlerSelectedContext context) | ||
| => Task.CompletedTask; | ||
| } | ||
| ``` | ||
|
|
||
| The `AuthorizePageHandlerAttribute` provides an `[AuthorizePageHandler]` attribute to the app: | ||
|
|
||
| ```csharp | ||
| [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] | ||
| public class AuthorizePageHandlerAttribute(string policy = null) | ||
| : Attribute, IAuthorizeData | ||
| { | ||
| public string Policy { get; set; } = policy; | ||
| public string Roles { get; set; } | ||
| public string AuthenticationSchemes { get; set; } | ||
| } | ||
| ``` | ||
|
|
||
| The `[AuthorizePageHandler]` attribute is applied to page handlers. In the following example, the attribute is set on the `OnPostAuthorized` page handler: | ||
|
|
||
| ```csharp | ||
| [TypeFilter(typeof(AuthorizeIndexPageHandlerFilter))] | ||
| public class IndexModel : PageModel | ||
| { | ||
| ... | ||
|
|
||
| [AuthorizePageHandler] | ||
| public void OnPostAuthorized() { ... } | ||
| } | ||
| ``` | ||
|
|
||
| > [!WARNING] | ||
| > The preceding approach does ***not***: | ||
| > | ||
| > * Compose with authorization attributes applied to the page, page model, or globally. Composing authorization attributes results in authentication and authorization executing multiple times when you have one more [`[Authorize]` attributes](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) or <xref:Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter> instances also applied to the page. | ||
| > * Work in conjunction with the rest of the ASP.NET Core authentication and authorization system. Verify that this approach works correctly for the app. | ||
|
|
||
| There are no plans to support the [`[Authorize]` attribute](xref:Microsoft.AspNetCore.Authorization.AuthorizeAttribute) on Razor Page handlers. | ||
|
|
||
| ## Additional resources | ||
|
|
||
| * <xref:security/authorization/simple> | ||
| * <xref:mvc/security/authorization/simple> | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.