Redirect to Login when Unauthorized using Policy-Based Authorization in Blazor

Restrict access to Blazor Components using the Authorize attribute (Policy-Based Authorization) and redirect to login

March 22, 2021

In this article we will cover how to restrict access to blazor components using the Authorize attribute (Policy-Based Authorization) and make sure that only authenticated users can execute it.

User will get redirected to login page if not authorized to view the blazor component.

BlazorAuthenticationStateProvider.cs

Create BlazorAuthenticationStateProvider.cs class inside any folder or at root level and replace the code with given below.

using Blazored.SessionStorage;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
using System.Security.Claims;
using System.Threading.Tasks;
 
 
namespace HpBlogs
{
    public class BlazorAuthenticationStateProvider : AuthenticationStateProvider
    {
        private readonly ISessionStorageService sessionStorage;
        private readonly NavigationManager navManager;
        private readonly AppState appState;
        public BlazorAuthenticationStateProvider(ISessionStorageService sessionStorageServiceNavigationManager _navManagerAppState _appState)
        {
            sessionStorage = sessionStorageService;
            navManager = _navManager;
            appState = _appState;
        }
        public override async Task<AuthenticationStateGetAuthenticationStateAsync()
        {
            ClaimsIdentity identity = await GetClaimsIdentity();
            var user = new ClaimsPrincipal(identity);
            return await Task.FromResult(new AuthenticationState(user));
        }
        public async Task MakeUserAsAuthenticated(string mobileNumber)
        {
            ClaimsIdentity identity = await GetClaimsIdentity();
 
            var user = new ClaimsPrincipal(identity);
 
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
        }
        private async Task<ClaimsIdentityGetClaimsIdentity()
        {
 
            int _userid = await sessionStorage.GetItemAsync<int>("userID");
            string role = await sessionStorage.GetItemAsync<string>("role");
            string userName = await sessionStorage.GetItemAsync<string>("userName");
            string userMobile = await sessionStorage.GetItemAsync<string>("userMobile");
 
            ClaimsIdentity identity = new ClaimsIdentity();
            if (_userid > 0 && !string.IsNullOrEmpty(role))
            {
                identity = new ClaimsIdentity(new[] {
                    new Claim(ClaimTypes.Name,userName),
                    new Claim(ClaimTypes.MobilePhone,userMobile),
                    new Claim(ClaimTypes.Sid,_userid.ToString()),
                    new Claim(ClaimTypes.Role,role),
                    new Claim("LoggedIn","true"),
                }, "apiauth_type");
            }
 
            if (_userid > 0 && role == "ADM")
                identity.AddClaim(new Claim("AdminUser""true"));
 
            if (_userid > 0 && role == "CAN")
                identity.AddClaim(new Claim("CandidateUser""true"));
 
            return identity;
        }
        public void MarkUserAsLoggedOut()
        {
            sessionStorage.ClearAsync();
 
            var identity = new ClaimsIdentity();
            var user = new ClaimsPrincipal(identity);
            NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
 
 
            navManager.NavigateTo("/login"forceLoadfalse);
        }
    }
}

Program.cs

Register BlazorAuthenticationStateProvider.cs file inside a Main method and add all Authorization Policy as mentioned below.

using System;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Blazored.SessionStorage;
using Microsoft.AspNetCore.Components.Authorization;
 
namespace HpBlogs
{
    public class Program
    {
 
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("app");
 
            builder.Services.AddBlazoredSessionStorage(config => config.JsonSerializerOptions.WriteIndented = true);
 
            #region Settings Configuration
            HttpClient client = new HttpClient() { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) };
            builder.Services.AddScoped(sp => client);
            using var res = await client.GetAsync("settings.json");
            using var stream = await res.Content.ReadAsStreamAsync();
            builder.Configuration.AddJsonStream(stream);
            #endregion
 
 
            builder.Services.AddScoped<AuthenticationStateProviderBlazorAuthenticationStateProvider>();
 
            builder.Services.AddAuthorizationCore(options =>
            {
                options.AddPolicy("LoggedIn"policy => policy.RequireClaim("LoggedIn""true"));
                options.AddPolicy("AdminUser"policy => policy.RequireClaim("AdminUser""true"));
                options.AddPolicy("CandidateUser"policy => policy.RequireClaim("CandidateUser""true"));
            });
 
            await builder.Build().RunAsync();
        }
    }
}

App.razor

Replace the code with given below to Authorize RouteView.

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

RedirectToLogin.razor

Create RedirectToLogin.razor Component and replace the code with given below.

@page "/auth/redirecttologin"
 
@inject NavigationManager navManager
@inject ISessionStorageService sessionStorage
@code
{
    protected override async Task OnInitializedAsync()
    {
        int user_id = await sessionStorage.GetItemAsync<int>("userID");
        if (user_id > 0)
            navManager.NavigateTo("/"false);
        else
            navManager.NavigateTo("/login"false);
    }
}
<Loader />

Login.razor

Create Login.razor Component and replace the code with given below.

@page "/login"
 
<AuthorizeView>
    <NotAuthorized Context="Auth">
 
        <section>
            <h2>LOGIN PAGE</h2>
           @*login html part*@
        </section>
 
    </NotAuthorized>
    <Authorized>
        <h2>You are Already Logged in</h2>
    </Authorized>
</AuthorizeView>

Login.razor.cs

Create Login.razor.cs file and replace the code with given below.

using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
 
namespace HpBlogs.Pages
{
    public partial class Login
    {
        [Inject]
        public AuthenticationStateProvider stateProvider { getset; }
 
        [Inject]
        public Blazored.SessionStorage.ISessionStorageService sessionStorage { getset; }
        
 
        // CALL this method on Login Button
        public async Task Login_User()
        {
            // Login Code here. After Successful Login
 
            await sessionStorage.SetItemAsync("userMobile""Mobile");
            await sessionStorage.SetItemAsync("userName""userName");
            await sessionStorage.SetItemAsync("userID", 1);
            await sessionStorage.SetItemAsync("role""role");
 
            await ((BlazorAuthenticationStateProvider)stateProvider).MakeUserAsAuthenticated();
        }
    }
}

Admin.razor

Create Admin.razor Component and replace the code with given below.

Only the Admin user can access this page as this page have "AdminUser" authorization policy.

@page "/admin"
 
<AuthorizeView Policy="AdminUser">
    <Authorized Context="Auth">
 
        <section>
            <h2>ADMIN PAGE</h2>
        </section>
 
    </Authorized>
    <NotAuthorized>
        <RedirectToLogin />
    </NotAuthorized>
</AuthorizeView>

Candidate.razor

Create Candidate.razor Component and replace the code with given below.

Only the Candiate user can access this page as this page have "CandidateUser" authorization policy.

@page "/candidate"
 
<AuthorizeView Policy="CandidateUser">
    <Authorized Context="Auth">
 
        <section>
            <h2>Candidate PAGE</h2>
        </section>
 
    </Authorized>
    <NotAuthorized>
        <RedirectToLogin />
    </NotAuthorized>
</AuthorizeView>
 
 

Dashboard.razor

Create Dashboard.razor Component and replace the code with given below.

All the LoggedIn user can access this page as this page does not have any authorization policy.

@page "/dashboard"
 
    <AuthorizeView>
        <Authorized Context="Auth">
 
            <h2>Dashboard</h2>
 
        </Authorized>
        <NotAuthorized>
            <RedirectToLogin />
        </NotAuthorized>
    </AuthorizeView>

Logout

Add below mentioned code and call it on Logout Button click.

public void Logout()
    {
        ((BlazorAuthenticationStateProvider)stateProvider).MarkUserAsLoggedOut();
    }

Post Comments(0)

Leave a reply

Will not be displayed in comment box .

Loading...