Chapter 24: Authorization: Securing your application
This chapter introduction frames authorization as deciding what authenticated users may do and previews the ASP.NET Core techniques used to enforce it.
After this chapter you will be able to
- Authentication and authorization distinction. Explain that authentication establishes who a user is, whereas authorization determines whether that user may perform a particular action in the application. Illustrate why an application with logged-in users still needs authorization by distinguishing permissions for admins, sales users, and customers.
- Authentication and authorization distinction. Explain that authentication determines who made a request, whereas authorization determines whether that requester is allowed to perform a requested action. State that authentication normally happens first so the application can identify the user before deciding whether to allow the action.
- Claims-based access decisions. Describe a claim as information about a user consisting of a type and an optional value, and explain how authorization can require either the presence of a claim or a particular claim value. Use the airport example to relate a BoardingPassNumber to access through security and FrequentFlyerClass with value Gold to lounge access.
- Authorization middleware ordering. Describe where AuthorizationMiddleware belongs in the ASP.NET Core middleware pipeline: after routing and authentication, but before endpoint execution. Explain why routing must first select an endpoint and authentication must first populate the current user.
- Endpoint authorization decision. Explain how authorization requirements attached as endpoint metadata, typically with the [Authorize] attribute, are evaluated against HttpContext.User. Describe the two outcomes: an authorized request continues down the pipeline, whereas an unauthorized request short-circuits it and never executes the endpoint.
- Authenticated endpoint restrictions. Describe how applying [Authorize] to an action or Razor Page restricts that endpoint to authenticated, logged-in users, while authenticated users can execute it normally.
- Anonymous endpoint exemptions. Explain how [AllowAnonymous] lets an action or Razor Page ignore an [Authorize] requirement, especially a global one, so public endpoints such as login, error, and password-reset actions remain reachable.
- Authorization failure outcomes. Distinguish a challenge response from a forbid response when AuthorizationMiddleware rejects a request to an authorized endpoint. Explain that a challenge means the user is not authenticated, whereas a forbid means the user is authenticated but fails another authorization requirement, such as a required claim.
- Web app authorization redirects. Describe how cookie-authenticated traditional web apps handle challenge and forbid responses. State that a challenge redirects an unauthenticated user to the login page, while a forbid redirects an already authenticated but unauthorized user to a forbidden or access-denied page.
- API authorization status responses. Describe how an API handles authorization failures: challenge returns HTTP 401 Unauthorized and forbid returns HTTP 403 Forbidden. Explain that the API does not redirect; the client-side SPA or mobile app detects and handles these responses.
- Claims-based authorization policies. Explain that an authorization policy encapsulates the requirements a request must meet, and that claims on the authenticated user's ClaimsPrincipal can satisfy those requirements. Describe claim-based checks such as requiring a BoardingPassNumber claim or a FrequentFlyerClass claim with a particular value.
- Policy application and outcomes. Describe how to apply a named policy to a Razor Page with the [Authorize] attribute and how its name matches the policy registered in Program.cs. Trace the three results when a request reaches that protected page: a successful user proceeds to the endpoint, an unauthenticated user is redirected to login, and an authenticated user who fails the policy is sent to a forbidden or access-denied page.
- Simple policy builder configuration. Describe registering authorization with AddAuthorizationBuilder() in Program.cs and defining a named policy with AddPolicy() and an AuthorizationPolicyBuilder lambda. Explain that RequireClaim() can require a claim type alone or require that the claim have a specified value, such as BoardingPassNumber equal to A1234.
- Limits of basic claim policies. Explain why requiring a single claim or a claim with one specific value is insufficient for some authorization policies. Describe the airline-lounge example as a rule that combines age, alternative eligibility conditions, and a disqualifying condition.
- Custom policy building blocks. Describe custom authorization requirements and handlers as the building blocks that can be combined to create authorization policies with more complex rules. State that a policy can permit multiple valid ways of satisfying its requirements.
- Policy requirement-handler structure. Describe how an ASP.NET Core authorization policy is built from one or more requirements, and how each requirement can have one or more handlers. Use the CanAccessLounge example to identify its MinimumAgeRequirement and AllowedInLoungeRequirement.
- Policy satisfaction logic. Explain that all requirements in a policy must be satisfied, while any one handler can satisfy a given requirement. Describe this as logical AND between requirements and logical OR between handlers, including that a failed requirement prevents the protected endpoint from executing.
- Custom authorization requirements. Describe how a custom authorization requirement is represented by a class implementing IAuthorizationRequirement, and explain that it is typically a lightweight POCO containing only the data needed to express the requirement. Explain how a parameterized requirement such as MinimumAgeRequirement can be reused across policies with different values.
- Multi-requirement policy configuration. Explain how the CanAccessLounge policy is configured in Program.cs by creating requirement instances and adding them to an AuthorizationPolicyBuilder. State that the policy is applied declaratively with the Authorize attribute and that its requirements must be satisfied for the policy to succeed.
- Authorization handler outcomes. Trace how an AuthorizationHandler<T> evaluates a particular requirement using AuthorizationHandlerContext and calls context.Succeed(requirement) when it satisfies that requirement. Distinguish doing nothing when a handler cannot establish success from calling context.Fail(), which guarantees that the requirement and whole policy fail even if another handler succeeds.
- Resource-based authorization need. Explain why editing only recipes created by the current user requires resource-based authorization: the application must load the specific Recipe and use its details when deciding whether the user is authorized.
- Imperative authorization purpose. Distinguish declarative authorization using the [Authorize] attribute from imperative authorization, and explain why the recipe-editing scenario needs imperative authorization after the Recipe has been loaded from the database.
- IAuthorizationService authorization call. Describe how to inject IAuthorizationService and call AuthorizeAsync with the current ClaimsPrincipal user, the loaded Recipe resource, and the "CanManageRecipe" policy; explain that AuthorizationResult.Succeeded determines whether execution may continue.
- Resource-based handler structure. Describe how to create a resource-based authorization handler by deriving from AuthorizationHandler<TRequirement, TResource> and implementing HandleRequirementAsync with both the requirement and resource types.
- Recipe ownership decision. Explain how IsRecipeOwnerHandler uses the Recipe resource and the current user to decide whether the user created that recipe, calling Succeed() only when the ownership requirement is met.
- Server-side authorization protection. Explain why hiding or disabling an Edit link in the UI cannot secure a Razor Pages application. State that the Edit.cshtml page handler must still authorize the request on the server because a malicious user can directly access or circumvent the client UI.
- Conditional Edit link rendering. Describe how the View.cshtml PageModel uses IAuthorizationService.AuthorizeAsync for the current user and Recipe to set a CanEditRecipe property. Explain that the Razor template wraps the Edit link in an if clause so the link renders only when CanEditRecipe indicates the user can edit that recipe.
What it builds on
- Introducing authentication and authorization (chapter 23) · Authentication, users, claims, and the ClaimsPrincipal established by the authentication system.
- Your first Razor Pages application (chapter 13) · Razor Pages as a UI and request-handling model.
- Your first MVC web application (chapter 19) · MVC controllers as an alternative application model.
- Understanding users and claims in ASP.NET Core (chapter 23) · The earlier explanation that users in ASP.NET Core can have claims.
- Combining middleware in a pipeline (chapter 4) · The middleware pipeline and the fact that middleware executes in a configured order.
- Endpoint routing in ASP.NET Core (chapter 6) · Endpoint routing selects an endpoint and makes it available during request processing.
- Authentication in ASP.NET Core: Services and middleware (chapter 23) · Authentication middleware creates the user for a request.
- Understanding pipeline short-circuiting (chapter 22) · Short-circuiting stops later components in a pipeline from executing.
Section by section
Introduction
This chapter introduction frames authorization as deciding what authenticated users may do and previews the ASP.NET Core techniques used to enforce it.
- Authentication and authorization distinction: Explain that authentication establishes who a user is, whereas authorization determines whether that user may perform a particular action in the application. Illustrate why an application with logged-in users still needs authorization by distinguishing permissions for admins, sales users, and customers.
Why it matters: Knowing the difference prevents treating a successful login as permission to perform every action. - Authorization techniques roadmap: Describe the chapter's progression from requiring authenticated users, through claims-based policies and custom requirement-handler policies, to resource-based authorization and hiding unauthorized Razor UI elements. State that the chapter focuses on Razor Pages and MVC controllers, while minimal API authorization is covered in chapter 25.
Why it matters: This roadmap helps you choose the authorization approach that fits a simple endpoint rule, a claim requirement, or a decision involving a specific resource.
Key terms: authentication, authorization, authenticated users, claims-based authorization, policies, authorization requirements, authorization handlers, resource-based authorization, Razor Pages
24.1 Introduction to authorization
This section distinguishes authentication from authorization and uses an airport journey to introduce claims-based authorization.
- Authentication and authorization distinction: Explain that authentication determines who made a request, whereas authorization determines whether that requester is allowed to perform a requested action. State that authentication normally happens first so the application can identify the user before deciding whether to allow the action.
Why it matters: Separating these two checks helps you understand why identifying a user does not automatically give them permission to do everything. - Claims-based access decisions: Describe a claim as information about a user consisting of a type and an optional value, and explain how authorization can require either the presence of a claim or a particular claim value. Use the airport example to relate a BoardingPassNumber to access through security and FrequentFlyerClass with value Gold to lounge access.
Why it matters: Claims let an application make access decisions from facts associated with an authenticated user rather than treating all users alike. - Authorization per protected action: Explain that authorization is evaluated for each distinct protected action, so a claim accepted for one action may need to be presented again for another. Describe the two airport outcomes when a required boarding-pass claim is absent or invalid: an unauthenticated traveler can return to check-in, while someone with an invalid ticket is denied access.
Why it matters: Access is tied to the action being requested, which prevents an earlier successful check from granting unrestricted access.
Key terms: authentication, authorization, authenticated request, claim, type, value, BoardingPassNumber, FrequentFlyerClass, Gold, unauthorized request
24.2 Authorization in ASP.NET Core
This section explains how ASP.NET Core authorizes a routed, authenticated request through endpoint metadata and AuthorizationMiddleware before the endpoint executes.
- Authorization middleware ordering: Describe where AuthorizationMiddleware belongs in the ASP.NET Core middleware pipeline: after routing and authentication, but before endpoint execution. Explain why routing must first select an endpoint and authentication must first populate the current user.
Why it matters: Correct middleware order ensures authorization can inspect both the selected endpoint's requirements and the authenticated user. - Endpoint authorization decision: Explain how authorization requirements attached as endpoint metadata, typically with the [Authorize] attribute, are evaluated against HttpContext.User. Describe the two outcomes: an authorized request continues down the pipeline, whereas an unauthorized request short-circuits it and never executes the endpoint.
Why it matters: This is how ASP.NET Core prevents users who do not meet an endpoint's requirements from running protected application code.
Key terms: AuthorizationMiddleware, UseAuthorization(), UseRouting(), UseAuthentication(), UseEndpoints(), RoutingMiddleware, [Authorize], endpoint metadata, authorization requirements, HttpContext.User
24.2.1 Preventing anonymous users from accessing your application
This section shows how to restrict endpoints to authenticated users with [Authorize] and exempt necessary public endpoints with [AllowAnonymous].
- Authenticated endpoint restrictions: Describe how applying [Authorize] to an action or Razor Page restricts that endpoint to authenticated, logged-in users, while authenticated users can execute it normally.
Why it matters: This provides the basic authorization boundary that prevents anonymous visitors from using protected parts of an application. - Authorization metadata processing: Explain that [Authorize] attaches authorization metadata to an endpoint, and that RoutingMiddleware makes this metadata available to AuthorizationMiddleware after endpoint selection.
Why it matters: Understanding the metadata flow explains how an endpoint attribute is enforced by the request pipeline. - Anonymous endpoint exemptions: Explain how [AllowAnonymous] lets an action or Razor Page ignore an [Authorize] requirement, especially a global one, so public endpoints such as login, error, and password-reset actions remain reachable.
Why it matters: Exempting required public endpoints avoids locking users out of the very pages they need to authenticate or recover access.
Key terms: [Authorize], authenticated user, unauthenticated user, action, Razor Page, authorization metadata, AuthorizationMiddleware, RoutingMiddleware, endpoint, [AllowAnonymous]
24.2.2 Handling unauthorized requests
This section explains how ASP.NET Core distinguishes challenge and forbid authorization failures and produces different responses for cookie-based web apps and APIs.
- Authorization failure outcomes: Distinguish a challenge response from a forbid response when AuthorizationMiddleware rejects a request to an authorized endpoint. Explain that a challenge means the user is not authenticated, whereas a forbid means the user is authenticated but fails another authorization requirement, such as a required claim.
Why it matters: Knowing why authorization failed lets you understand whether a user must sign in or lacks permission even after signing in. - Web app authorization redirects: Describe how cookie-authenticated traditional web apps handle challenge and forbid responses. State that a challenge redirects an unauthenticated user to the login page, while a forbid redirects an already authenticated but unauthorized user to a forbidden or access-denied page.
Why it matters: Traditional browser apps can guide people to sign in or explain that they do not have access instead of exposing raw authorization errors. - API authorization status responses: Describe how an API handles authorization failures: challenge returns HTTP 401 Unauthorized and forbid returns HTTP 403 Forbidden. Explain that the API does not redirect; the client-side SPA or mobile app detects and handles these responses.
Why it matters: API clients need status codes rather than browser redirects so they can decide how to prompt, recover, or report an authorization failure.
Key terms: AuthorizationMiddleware, challenge, forbid, authorization requirements, claim, [Authorize], cookie authentication, login page, access denied, ASP.NET Core Identity
24.3 Using policies for claims-based authorization
This section shows how to define and apply named authorization policies that use user claims to control access to ASP.NET Core endpoints.
- Claims-based authorization policies: Explain that an authorization policy encapsulates the requirements a request must meet, and that claims on the authenticated user's ClaimsPrincipal can satisfy those requirements. Describe claim-based checks such as requiring a BoardingPassNumber claim or a FrequentFlyerClass claim with a particular value.
Why it matters: Policies let an application make access decisions from information about the authenticated user, not merely whether they signed in. - Policy application and outcomes: Describe how to apply a named policy to a Razor Page with the [Authorize] attribute and how its name matches the policy registered in Program.cs. Trace the three results when a request reaches that protected page: a successful user proceeds to the endpoint, an unauthenticated user is redirected to login, and an authenticated user who fails the policy is sent to a forbidden or access-denied page.
Why it matters: Knowing the distinct outcomes helps you protect endpoints while giving appropriate responses to users who need to sign in versus users who lack permission. - Simple policy builder configuration: Describe registering authorization with AddAuthorizationBuilder() in Program.cs and defining a named policy with AddPolicy() and an AuthorizationPolicyBuilder lambda. Explain that RequireClaim() can require a claim type alone or require that the claim have a specified value, such as BoardingPassNumber equal to A1234.
Why it matters: This is the standard way to centralize reusable, named claim requirements that endpoints can enforce. - Claims over role checks: Justify preferring claims-based authorization over role-based authorization for new ASP.NET Core applications. State that RequireRole() remains primarily for legacy compatibility, while roles can still be used to assign claims rather than being checked directly for authorization.
Why it matters: Using claims makes authorization rules more flexible and follows the approach recommended for ASP.NET Core applications. - Limits of simple policies: Distinguish simple claim policies from authorization rules that require custom policies. Explain that RequireClaim() cannot express a condition such as being over age 18 when the DateOfBirth claim has no single correct value, and that although RequireAssertion() could calculate it, custom requirements and handlers are recommended for such complex rules.
Why it matters: Recognizing when simple claim checks stop being clear helps you move to maintainable custom authorization policies.
Key terms: ClaimsPrincipal, claim, claims-based authorization, policy, authorization, Authorize, authorization middleware, EndpointMiddleware, unauthenticated, forbidden
24.4 Creating custom policies for authorization
This section introduces why complex authorization rules require custom policy requirements and handlers rather than only the basic claim checks of AuthorizationPolicyBuilder.
- Limits of basic claim policies: Explain why requiring a single claim or a claim with one specific value is insufficient for some authorization policies. Describe the airline-lounge example as a rule that combines age, alternative eligibility conditions, and a disqualifying condition.
Why it matters: Recognizing when basic claim requirements are not enough tells you when to build a custom authorization policy. - Custom policy building blocks: Describe custom authorization requirements and handlers as the building blocks that can be combined to create authorization policies with more complex rules. State that a policy can permit multiple valid ways of satisfying its requirements.
Why it matters: Requirements and handlers let an application encode real authorization rules when fixed claim-value checks do not match the business rule.
Key terms: AuthorizationPolicyBuilder, claim, FrequentFlyerClass, DateOfBirth, EmployeeNumber, IsBannedFromLounge, custom authorization requirements, handlers, policy
24.4.1 Requirements and handlers: The building blocks of a policy
This section explains how authorization policies are composed from requirements and handlers and how their AND/OR evaluation controls access.
- Policy requirement-handler structure: Describe how an ASP.NET Core authorization policy is built from one or more requirements, and how each requirement can have one or more handlers. Use the CanAccessLounge example to identify its MinimumAgeRequirement and AllowedInLoungeRequirement.
Why it matters: This structure lets you break an access rule into clear, reusable authorization checks. - Policy satisfaction logic: Explain that all requirements in a policy must be satisfied, while any one handler can satisfy a given requirement. Describe this as logical AND between requirements and logical OR between handlers, including that a failed requirement prevents the protected endpoint from executing.
Why it matters: Getting the AND/OR rules right prevents accidentally granting access too broadly or denying valid users. - Multiple policy combination: State that applying multiple [Authorize] attributes with different policies to a Razor Page or action method requires every applied policy to be satisfied for the request to be authorized.
Why it matters: Multiple policies add restrictions rather than offering alternative ways to gain access.
Key terms: policy, requirement, handler, CanAccessLounge, MinimumAgeRequirement, AllowedInLoungeRequirement, authorize middleware, protected endpoint, FrequentFlyerHandler, IsAirlineEmployeeHandler
24.4.2 Creating a policy with a custom requirement and handler
This section builds the CanAccessLounge policy from custom requirement objects and DI-registered handlers, explaining how handlers determine authorization success or failure.
- Custom authorization requirements: Describe how a custom authorization requirement is represented by a class implementing IAuthorizationRequirement, and explain that it is typically a lightweight POCO containing only the data needed to express the requirement. Explain how a parameterized requirement such as MinimumAgeRequirement can be reused across policies with different values.
Why it matters: Requirements declare what a policy needs without embedding the logic that decides whether a user meets it. - Multi-requirement policy configuration: Explain how the CanAccessLounge policy is configured in Program.cs by creating requirement instances and adding them to an AuthorizationPolicyBuilder. State that the policy is applied declaratively with the Authorize attribute and that its requirements must be satisfied for the policy to succeed.
Why it matters: A policy combines the access conditions that ASP.NET Core evaluates before the protected Razor Page or action executes. - Authorization handler outcomes: Trace how an AuthorizationHandler<T> evaluates a particular requirement using AuthorizationHandlerContext and calls context.Succeed(requirement) when it satisfies that requirement. Distinguish doing nothing when a handler cannot establish success from calling context.Fail(), which guarantees that the requirement and whole policy fail even if another handler succeeds.
Why it matters: Correct handler outcomes determine whether alternative ways to satisfy a requirement work and whether a blocking condition overrides them. - Handler execution and registration: Explain that ASP.NET Core runs all handlers for each requirement and all requirements in a policy regardless of whether handlers call Succeed, Fail, or neither. Describe registering authorization handlers in the DI container, using singleton when they have no dependencies and an appropriate scoped lifetime when they depend on scoped services such as an EF Core DbContext.
Why it matters: Handlers must be registered so authorization can invoke them, and their DI lifetime must be compatible with the services they use. - Declarative authorization limitation: Explain why the declarative Authorize attribute cannot handle authorization decisions that depend on a resource loaded inside an endpoint, such as deciding whether a user may edit a document they created. State that this scenario requires the imperative, resource-based authorization approach introduced next.
Why it matters: Recognizing when endpoint-level authorization is too early prevents access-control checks from being made without the resource data they require.
Key terms: IAuthorizationRequirement, requirement, AllowedInLoungeRequirement, MinimumAgeRequirement, POCO, CanAccessLounge, AuthorizationPolicyBuilder, Authorize, authorization policy, Program.cs
24.5 Controlling access with resource-based authorization
This section introduces resource-based authorization for cases where access depends on details of a specific loaded resource, using recipe editing as the example.
- Resource-based authorization need: Explain why editing only recipes created by the current user requires resource-based authorization: the application must load the specific Recipe and use its details when deciding whether the user is authorized.
Why it matters: Some access rules cannot be decided from the user or a general policy alone; they depend on the particular item being accessed. - Create page authentication: Describe how adding an [Authorize] attribute without a policy to the Create.cshtml Razor Page requires a user to authenticate before creating a recipe, and state that the attribute applies to every handler on that page.
Why it matters: This protects the create operation with the simple authenticated-user rule before more specific resource checks are needed. - IDOR risk from entity IDs: Explain that exposing an entity's integer ID in a URL can let a user alter the ID to request another entity, and that authorization checks are necessary to avoid an insecure direct object reference vulnerability.
Why it matters: Checking access to the requested resource prevents a changed URL from becoming a way to access or edit someone else's data.
Key terms: resource-based authorization, Recipe, resource, AuthorizeAttribute, [Authorize], Create.cshtml, Razor Page, page handlers, integer ID, insecure direct object reference
24.5.1 Manually authorizing requests with IAuthorizationService
This section shows how to perform imperative, resource-based authorization after loading a Recipe by calling IAuthorizationService from a Razor Page.
- Imperative authorization purpose: Distinguish declarative authorization using the [Authorize] attribute from imperative authorization, and explain why the recipe-editing scenario needs imperative authorization after the Recipe has been loaded from the database.
Why it matters: Some access decisions depend on the specific resource, so the application cannot always authorize solely from endpoint metadata. - IAuthorizationService authorization call: Describe how to inject IAuthorizationService and call AuthorizeAsync with the current ClaimsPrincipal user, the loaded Recipe resource, and the "CanManageRecipe" policy; explain that AuthorizationResult.Succeeded determines whether execution may continue.
Why it matters: This is the explicit authorization check that connects the signed-in user, a policy, and the resource being protected. - Failed authorization response: Explain that a failed AuthorizationResult should return ForbidResult, and describe how this becomes an HTTP 403 Forbidden response or an access-denied redirect depending on the configured authentication services and application type.
Why it matters: Correctly handling a denied request prevents the protected operation from continuing and gives the client an appropriate response. - Imperative policy configuration: State that the "CanManageRecipe" policy is configured through AddAuthorization in Program.cs with one or more requirements, one or more handlers for each requirement, and DI registration of the handlers; identify IsRecipeOwnerRequirement as the simple marker requirement introduced here.
Why it matters: Calling a policy by name only works after its requirements and authorization handlers have been configured and registered.
Key terms: declarative authorization, imperative authorization, [Authorize] attribute, resource-based authorization, Recipe, IAuthorizationService, AuthorizeAsync, ClaimsPrincipal, User, CanManageRecipe
24.5.2 Creating a resource-based AuthorizationHandler
This section shows how to implement and register a resource-based authorization handler, and weighs framework authorization against manual domain-level checks.
- Resource-based handler structure: Describe how to create a resource-based authorization handler by deriving from AuthorizationHandler<TRequirement, TResource> and implementing HandleRequirementAsync with both the requirement and resource types.
Why it matters: A resource-aware handler can make an authorization decision about the particular object a user is trying to access. - Recipe ownership decision: Explain how IsRecipeOwnerHandler uses the Recipe resource and the current user to decide whether the user created that recipe, calling Succeed() only when the ownership requirement is met.
Why it matters: This enables fine-grained authorization of an individual recipe rather than merely granting permission to edit every recipe. - Handler dependency lifetime: Explain why IsRecipeOwnerHandler is registered as a scoped DI service: it depends on UserManager<>, which uses EF Core and therefore has scoped dependencies; a handler without scoped dependencies can be singleton.
Why it matters: Matching the handler lifetime to its dependencies prevents invalid DI lifetime combinations. - Authorization design trade-offs: Distinguish resource-based authorization through IAuthorizationService from manual business-logic checks, including the framework approach's declarative policies, separation of authorization need from requirements, and access to request-related services, versus the simpler and more framework-independent domain approach.
Why it matters: Choosing deliberately lets an application balance authorization infrastructure benefits against domain simplicity and testability.
Key terms: AuthorizationHandler<TRequirement, TResource>, HandleRequirementAsync, requirement, resource, IAuthorizationService, IsRecipeOwnerHandler, IsRecipeOwnerRequirement, Recipe, ClaimsPrincipal, ApplicationUser
24.6 Hiding HTML elements from unauthorized users
This section improves Razor Pages user experience by hiding unauthorized UI elements while preserving server-side authorization as the essential security control.
- Server-side authorization protection: Explain why hiding or disabling an Edit link in the UI cannot secure a Razor Pages application. State that the Edit.cshtml page handler must still authorize the request on the server because a malicious user can directly access or circumvent the client UI.
Why it matters: A hidden button improves the interface, but only server-side authorization prevents unauthorized access. - Conditional Edit link rendering: Describe how the View.cshtml PageModel uses IAuthorizationService.AuthorizeAsync for the current user and Recipe to set a CanEditRecipe property. Explain that the Razor template wraps the Edit link in an if clause so the link renders only when CanEditRecipe indicates the user can edit that recipe.
Why it matters: Showing only actions that a user can complete avoids sending them to an access-denied page. - Authorization-aware recipe experience: State the final access behavior of the recipe application: anonymous users may browse recipes, users must log in to create recipes, and authenticated users may edit only recipes they created. Describe that the UI hides Edit links for recipes created by other users while endpoint authorization enforces that rule.
Why it matters: This summarizes how authentication, resource-based authorization, and UI behavior combine in the completed recipe application.
Key terms: server-side authorization, Edit.cshtml page handler, client-side security, IAuthorizationService, AuthorizeAsync, CanEditRecipe, PageModel, View.cshtml, Razor template, anonymous users
24.7 Summary
This summary recaps how ASP.NET Core authenticates users, authorizes their access through attributes and policies, and enforces more complex or resource-specific rules on the server.
Where this is used later
- Authentication for APIs and distributed applications (chapter 25) · Builds API authentication and authorization on their distinct responsibilities.
- Understanding bearer token authentication (chapter 25) · It distinguishes bearer-token authentication from the authorization decisions made for API requests.
- Summary (chapter 25) · The purpose of authorization in controlling access to application resources
- Applying authorization policies to minimal API endpoints (chapter 25) · It supports applying authorization policies to minimal API endpoints.
- Adding JWT bearer authentication to minimal APIs (chapter 25) · JWT bearer authentication configures authentication for API requests that can produce 401 or 403 authorization outcomes.
- (chapter intro) (chapter 25) · Requirements and handlers as policy building blocks.
- Preventing insecure direct object references (chapter 29) · It helps prevent insecure direct object references when users request entities by ID.
Concepts explained in this chapter
- authorizationAuthorization is the process of determining whether an authenticated subject has permission to perform an operation or access a resource.
- policyAn authorization policy is a named set of requirements that determines whether an authenticated subject may access a protected resource or operation.
- authorization requirementAn authorization requirement is a condition that must be satisfied for an authorization policy to succeed.
- claimA claim is a statement about an authenticated subject, represented as a type and value, that can support authorization decisions.
- authorization handlerAuthorizationHandler is an ASP.NET Core base class for implementing logic that evaluates authorization requirements, optionally against a resource.
- authorize attributeThe ASP.NET Core Authorize attribute marks an endpoint, controller, action, or Razor Page as requiring an authenticated user or satisfying specified authorization requirements.
- claims-based approachClaims-based authorization is an authorization approach that evaluates claims associated with an authenticated identity to decide whether access is permitted.
- AuthorizationPolicyBuilderAuthorizationPolicyBuilder is the ASP.NET Core builder API for constructing authorization policies from requirements and other authorization conditions.
- IAuthorizationServiceIAuthorizationService is the ASP.NET Core service interface for evaluating whether a user is authorized to perform an operation, optionally in the context of a resource.
- IAuthorizationRequirementIAuthorizationRequirement is the ASP.NET Core marker interface implemented by classes that represent authorization requirements.
- imperative authorizationImperative authorization is an authorization approach in which application code explicitly invokes authorization logic during endpoint execution.
- AddPolicyAddPolicy is an ASP.NET Core authorization configuration method that registers a named policy defined by a policy builder.
- authenticationAuthentication is the process of determining the identity of the subject that made a request.
- UseAuthorizationUseAuthorization is an ASP.NET Core extension method that adds authorization middleware to a web application's request pipeline.
- AuthorizeAsyncAuthorizeAsync is an ASP.NET Core authorization API method that asynchronously evaluates whether a user satisfies an authorization requirement or policy.
- RequireClaimRequireClaim is an authorization policy builder method that requires a user to possess a specified claim, optionally with a specified value.
- business-logic checkA business-logic check is an authorization decision performed directly within application or domain logic rather than through a framework authorization infrastructure.
- challenge responseA challenge response indicates that a request failed authorization because the user is not authenticated.
- forbid responseA forbid response indicates that an authenticated user lacks the authorization requirements needed to access an endpoint or execute an operation.
- Razor syntaxA Razor view is a server-rendered template that combines markup with embedded C# expressions and accesses data supplied by an application component.
- AllowAnonymousAllowAnonymous is an ASP.NET Core attribute that permits access to an endpoint, action, or Razor Page without authentication.
- AuthorizationMiddlewareAuthorizationMiddleware is ASP.NET Core middleware that determines whether an authenticated user may access a selected endpoint.
- insecure direct object referenceAn insecure direct object reference is a security vulnerability in which a user gains access to an unauthorized resource by manipulating a direct identifier in a request URL or other input.
- handlerA handler is an application component that receives a framework-dispatched request or event and performs the corresponding processing.
- FailFail is an authorization context operation that records explicit failure of an authorization requirement and its containing policy.
- SucceedSucceed is an authorization-handler operation that marks a specified requirement as satisfied.
- 401 unauthorizedA 401 Unauthorized response is an HTTP response indicating that authentication is required or has failed for the request.
- cookieAn authentication cookie is a client-side HTTP cookie containing serialized authentication state used to recognize a signed-in user across requests.
- metadataMetadata is descriptive information attached to an endpoint that can be inspected or used by framework components.
- UseAuthenticationUseAuthentication is an ASP.NET Core extension method that adds authentication middleware at a specified point in the request pipeline.
These guides are generated from the text of Manning books by Manning's knowledge graph and link to the sections they draw on. The full books are available on liveBook and at manning.com.
