EF CORE - AUTHORIZE PRODUCT CRUD OPERATIONS

ENTITY FRAMEWORK CORE (EF CORE) — PART 4: AUTHORIZE PRODUCT CRUD OPERATIONS

PART 3 added registration, login, logout and a protected Members page. This tutorial allows everyone to browse Products while requiring authentication to create, edit or delete a Product.

1. Define the authorization rules

Product pageRouteGuestAuthenticated user
Index/ProductsAllowedAllowed
Details/Products/Details?id=1AllowedAllowed
Create/Products/CreateLogin requiredAllowed
Edit/Products/Edit?id=1Login requiredAllowed
Delete/Products/Delete?id=1Login requiredAllowed

Hiding buttons improves the interface, but it is not security. Each modifying PageModel must also enforce authorization on the server.

2. Confirm Identity is working

cd ~/dotnetprojects/dotnetef
dotnet build
sqlite3 Data/identity.db ".tables"

Start the application and confirm that Register, Login and Logout from PART 3 work before continuing:

dotnet run

Stop it with Ctrl+C before editing the files.

3. Protect the Create PageModel

Open Pages/Products/Create.cshtml.cs. Add this using directive:

using Microsoft.AspNetCore.Authorization;

Add [Authorize] immediately above the generated class:

namespace dotnetef.Pages.Products;

[Authorize]
public class CreateModel : PageModel
{
    // Keep the existing generated code here.
}

The attribute protects both the GET request that displays the form and the POST request that inserts the Product.

4. Protect the Edit PageModel

Open Pages/Products/Edit.cshtml.cs and add:

using Microsoft.AspNetCore.Authorization;

Then add the authorization attribute:

namespace dotnetef.Pages.Products;

[Authorize]
public class EditModel : PageModel
{
    // Keep the existing generated code here.
}

This prevents guests from displaying or submitting the Edit form.

5. Protect the Delete PageModel

Open Pages/Products/Delete.cshtml.cs and add:

using Microsoft.AspNetCore.Authorization;

Then protect the class:

namespace dotnetef.Pages.Products;

[Authorize]
public class DeleteModel : PageModel
{
    // Keep the existing generated code here.
}

The confirmation page and its deletion handler now require login.

6. Leave Index and Details public

Do not add [Authorize] to these files:

Pages/Products/Index.cshtml.cs
Pages/Products/Details.cshtml.cs

They remain public because Razor Pages allows anonymous access unless authorization is explicitly required.

7. Hide the Create link from guests

Open Pages/Products/Index.cshtml. Locate the generated Create link and wrap it in an authentication check:

@if (User.Identity?.IsAuthenticated == true)
{
    <p>
        <a asp-page="Create">Create New</a>
    </p>
}

Logged-out visitors can still read the Product list, but they will not see a link to a page they cannot use.

8. Keep Details public and hide Edit and Delete

In the action column of Pages/Products/Index.cshtml, replace the generated links with:

<a asp-page="./Details"
   asp-route-id="@item.Id">Details</a>

@if (User.Identity?.IsAuthenticated == true)
{
    <span> | </span>
    <a asp-page="./Edit"
       asp-route-id="@item.Id">Edit</a>
    <span> | </span>
    <a asp-page="./Delete"
       asp-route-id="@item.Id">Delete</a>
}

Details remains visible to everyone. Edit and Delete appear only after login.

9. Hide the Edit link on the Details page

Open Pages/Products/Details.cshtml. Keep the Back to List link public and display Edit conditionally:

<div>
    @if (User.Identity?.IsAuthenticated == true)
    {
        <a asp-page="./Edit"
           asp-route-id="@Model.Product.Id">Edit</a>
        <span> | </span>
    }
    <a asp-page="./Index">Back to List</a>
</div>

10. Optionally show the Members link only after login

PART 3 deliberately showed Members to guests to demonstrate redirection. The navigation can now be made cleaner. In Pages/Shared/_Layout.cshtml, wrap the Members item:

@if (User.Identity?.IsAuthenticated == true)
{
    <li class="nav-item">
        <a class="nav-link text-dark"
           asp-page="/Members">Members</a>
    </li>
}

11. Build and run

dotnet build
dotnet run

Correct any build error before testing in the browser.

12. Test as a guest

Log out and test the following:

TestExpected result
Open /ProductsProduct list appears
Open a Details linkProduct details appear
Inspect the Product listCreate, Edit and Delete links are hidden
Type /Products/CreateRedirected to Login
Type /Products/Edit?id=1Redirected to Login
Type /Products/Delete?id=1Redirected to Login

Typing protected URLs manually confirms that security does not depend on hidden links.

13. Test as an authenticated user

  1. Click Login.
  2. Enter the account created in PART 3.
  3. Open /Products.
  4. Confirm that Create, Edit and Delete links are now visible.
  5. Create a Product.
  6. Edit that Product.
  7. Delete that Product.

14. Understand the two protection layers

LayerCodePurpose
User interfaceUser.Identity?.IsAuthenticatedHides unavailable actions from guests
Server authorization[Authorize]Rejects unauthorized requests even when a URL is entered manually

The server-side layer is essential. A visitor can alter URLs or send an HTTP request without using the application's links.

15. Alternative: protect pages by convention

For a larger application, individual attributes can be replaced by authorization conventions in Program.cs:

builder.Services.AddRazorPages(options =>
{
    options.Conventions.AuthorizePage(
        "/Products/Create"
    );
    options.Conventions.AuthorizePage(
        "/Products/Edit"
    );
    options.Conventions.AuthorizePage(
        "/Products/Delete"
    );
});

Use either the [Authorize] attributes from this tutorial or these conventions. Both are shown to explain the alternatives; duplicating them is unnecessary.

16. Common problems

ProblemRemedy
AuthorizeAttribute cannot be foundAdd using Microsoft.AspNetCore.Authorization;
Create, Edit or Delete still opens for guestsPlace [Authorize] immediately above the correct PageModel class and rebuild
Links remain visible after logoutWrap the links with User.Identity?.IsAuthenticated == true
All Product pages require loginRemove folder-wide authorization or add protection only to Create, Edit and Delete
Login succeeds but returns to the wrong pageUse the Identity-generated Login URL with its ReturnUrl parameter
Product actions return 404Use the generated Razor Page names and pass asp-route-id

What has been achieved?

  • Guests can browse the Product list and Product details.
  • Create, Edit and Delete require authentication.
  • Modification links are hidden from logged-out visitors.
  • Direct requests to protected URLs are rejected.
  • The difference between interface visibility and server security is clear.

PART 4 complete: Product reading remains public, while Product modification is restricted to authenticated users.

Official references

Next: ENTITY FRAMEWORK CORE (EF CORE) — PART 5 associates each Product with the authenticated user so users can modify only their own records.