Configure ASP.NET App with systemd Service file

sudo nano /etc/systemd/system/kestrel-helloapp.service
[Unit]
Description=Example .NET Web API App running on Ubuntu

[Service]
WorkingDirectory=/var/www/helloapp
ExecStart=/usr/bin/dotnet /var/www/helloapp/helloapp.dll
Restart=always
# Restart service after 10 seconds if the dotnet service crashes:
RestartSec=10
KillSignal=SIGINT
SyslogIdentifier=dotnet-example
User=www-data
Environment=ASPNETCORE_ENVIRONMENT=Production
Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false

[Install]
WantedBy=multi-user.target

Some values (for example, SQL connection strings) must be escaped for the configuration providers to read the environment variables. Use the following command to generate a properly escaped value for use in the configuration file:

systemd-escape "<value-to-escape>"
Environment=ConnectionStrings__DefaultConnection={Connection String}

And finallyset Content root :

Environment=ASPNETCORE_CONTENTROOT=/opt/bi/bi_web

Save the file and enable the service:

sudo systemctl enable kestrel-helloapp.service
sudo systemctl start kestrel-helloapp.service
sudo systemctl status kestrel-helloapp.service

References
https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-6.0#create-the-service-file
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-6.0#connection-string-prefixes
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-6.0#content-root

Change Default Port Number of ASP.NET App

Server Endpoints

There is a file in root folder called appsettings.json with you can change the server related configuration, this is an example with Kestrel:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Endpoints": {
      "Http": {
        "Url": "http://localhost:5400"
      },
      "Https": {
        "Url": "https://localhost:5401"
      }
    }
  }
}

From command line

You can run the application with the --urls parameter to specify the ports:

dotnet run --urls http://localhost:8076

References
https://stackoverflow.com/questions/70332897/how-to-change-default-port-no-of-my-net-core-6-api

Adding Custom Fields to Identity User in ASP.NET Identity

public class ApplicationUser : IdentityUser
{
    public string CustomTag { get; set; }
}

Use the ApplicationUser type as a generic argument for the context:

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);
    }
}

Update Pages/Shared/_LoginPartial.cshtml and replace IdentityUser with ApplicationUser:

@using Microsoft.AspNetCore.Identity
@using WebApp1.Areas.Identity.Data
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager

Update Areas/Identity/IdentityHostingStartup.cs or Startup.ConfigureServices and replace IdentityUser with ApplicationUser.

services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();

 

References
https://docs.microsoft.com/en-us/aspnet/core/security/authentication/customize-identity-model?view=aspnetcore-6.0#custom-user-data

Check authorization rules as part of procedural logic in ASP.NET Blazor

If the app is required to check authorization rules as part of procedural logic, use a cascaded parameter of type Task<AuthenticationState> to obtain the user’s ClaimsPrincipalTask<AuthenticationState> can be combined with other services, such as IAuthorizationService, to evaluate policies.

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the 
            // 'content-editor' policy.
        }
    }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#procedural-logic

Customize unauthorized content with the Router component in ASP.NET Blazor

The Router component, in conjunction with the AuthorizeRouteView component, allows the app to specify custom content if:

  • The user fails an [Authorize] condition applied to the component. The markup of the <NotAuthorized> element is displayed. The [Authorize] attribute is covered in the [Authorize] attribute section.
  • Asynchronous authorization is in progress, which usually means that the process of authenticating the user is in progress. The markup of the <Authorizing> element is displayed.
  • Content isn’t found. The markup of the <NotFound> element is displayed.
<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    <h1>Sorry</h1>
                    <p>You're not authorized to reach this page.</p>
                    <p>You may need to log in as a different user.</p>
                </NotAuthorized>
                <Authorizing>
                    <h1>Authorization in progress</h1>
                    <p>Only visible while authorization is in progress.</p>
                </Authorizing>
            </AuthorizeRouteView>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <h1>Sorry</h1>
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#customize-unauthorized-content-with-the-router-component

[Authorize] attribute in ASP.NET Blazor

The [Authorize] attribute can be used in Razor components:

@page "/"
@attribute [Authorize]

You can only see this if you're signed in.

Only use [Authorize] on @page components reached via the Blazor Router. Authorization is only performed as an aspect of routing and not for child components rendered within a page. To authorize the display of specific parts within a page, use AuthorizeView instead.

The [Authorize] attribute also supports role-based or policy-based authorization. For role-based authorization, use the Roles parameter:

@page "/"
@attribute [Authorize(Roles = "admin, superuser")]

<p>You can only see this if you're in the 'admin' or 'superuser' role.</p>

For policy-based authorization, use the Policy parameter:

@page "/"
@attribute [Authorize(Policy = "content-editor")]

<p>You can only see this if you satisfy the 'content-editor' policy.</p>

If neither Roles nor Policy is specified, [Authorize] uses the default policy, which by default is to treat:

  • Authenticated (signed-in) users as authorized.
  • Unauthenticated (signed-out) users as unauthorized.

Refererences
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#authorize-attribute

Content displayed during asynchronous authentication in ASP.NET Blazor

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authenticated.</p>
    </Authorized>
    <Authorizing>
        <h1>Authentication in progress</h1>
        <p>You can only see this content while authentication is in progress.</p>
    </Authorizing>
</AuthorizeView>

This approach isn’t normally applicable to Blazor Server apps. Blazor Server apps know the authentication state as soon as the state is established. Authorizing content can be provided in a Blazor Server app’s AuthorizeView component, but the content is never displayed.

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#content-displayed-during-asynchronous-authentication

Role-based and policy-based authorization in ASP.NET Blazor

The AuthorizeView component supports role-based or policy-based authorization.

For role-based authorization, use the Roles parameter:

<AuthorizeView Roles="admin, superuser">
    <p>You can only see this if you're an admin or superuser.</p>
</AuthorizeView>

For policy-based authorization, use the Policy parameter:

<AuthorizeView Policy="content-editor">
    <p>You can only see this if you satisfy the "content-editor" policy.</p>
</AuthorizeView>

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#role-based-and-policy-based-authorization

AuthorizeView component in ASP.NET Blazor

The AuthorizeView component selectively displays UI content depending on whether the user is authorized. This approach is useful when you only need to display data for the user and don’t need to use the user’s identity in procedural logic.

The component exposes a context variable of type AuthenticationState, which you can use to access information about the signed-in user:

<AuthorizeView>
    <h1>Hello, @context.User.Identity.Name!</h1>
    <p>You can only see this content if you're authenticated.</p>
</AuthorizeView>

You can also supply different content for display if the user isn’t authorized:

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you're authorized.</p>
        <button @onclick="SecureMethod">Authorized Only Button</button>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You're not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

@code {
    private void SecureMethod() { ... }
}

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#authorizeview-component

Expose the authentication state as a cascading parameter in ASP.NET Blazor

@page "/"

<button @onclick="LogUsername">Log username</button>

<p>@authMessage</p>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private string authMessage;

    private async Task LogUsername()
    {
        var authState = await authenticationStateTask;
        var user = authState.User;

        if (user.Identity.IsAuthenticated)
        {
            authMessage = $"{user.Identity.Name} is authenticated.";
        }
        else
        {
            authMessage = "The user is NOT authenticated.";
        }
    }
}

Set up the Task<AuthenticationState> cascading parameter using the AuthorizeRouteView and CascadingAuthenticationState components in the App component (App.razor):

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" 
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

In a Blazor WebAssembly App, add services for options and authorization to Program.cs:

builder.Services.AddOptions();
builder.Services.AddAuthorizationCore();

In a Blazor Server app, services for options and authorization are already present, so no further action is required.

References
https://docs.microsoft.com/en-us/aspnet/core/blazor/security/?view=aspnetcore-6.0#expose-the-authentication-state-as-a-cascading-parameter