In this article, we are going to understand the authorization flow using user roles and claims in the blazor webassembly application.
Index.razor:
Create A Sample Blazor WebAssembly Application:
Let's create a sample blazor webassembly application for our demo. We can use any IDE for the application development but the most recommended is Visual Studio 2019(version 16.8.*) and Visual Studio Code.
Authentication Setup:
To implement authorization first user need to be authenticated. So here we will implement some fake user authentication with some roles and claims. For complete authentication, implementation checks my blogs like Access Token and Refresh Token.
Package Manager
Install-Package Microsoft.AspNetCore.Components.Authorization -Version 5.0.1
.Net CLI
dotnet add package Microsoft.AspNetCore.Components.Authorization --Version 5.0.1
A core component of blazor authentication is 'Microsoft.AspNetCore.Components.Authorization.AuthenticationStateProvider', here we going to implement it by customizing it.Auth/CustomAuthStateProvider.cs:
using System.Security.Claims; using System.Threading.Tasks; using Microsoft.AspNetCore.Components.Authorization; namespace BW.Auth.Auth { public class CustomAuthStateProvider : AuthenticationStateProvider { public override async Task<AuthenticationState> GetAuthenticationStateAsync() { var identity = new ClaimsIdentity(new []{ new Claim(ClaimTypes.Name,"Naveen"), new Claim(ClaimTypes.Role, "user"), new Claim(ClaimTypes.Role, "admin") },"Fake Auth"); var user = new ClaimsPrincipal(identity); return await Task.FromResult(new AuthenticationState(user)); } } }
- Here we added roles like 'user' and 'admin' to my authentication.
_Import.razor:
@using BW.Auth.Shared @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.AuthorizationNow register the required service in Program.cs file
Program.cs:
builder.Services.AddScoped<AuthenticationStateProvider,CustomAuthStateProvider>(); builder.Services.AddOptions(); builder.Services.AddAuthorizationCore();Now add the 'CascadingAuthenticationState' and 'AuthorizeRouteView' components in the App.razor file.
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>
Roles Authorization On AuthorizeView Component:
The AuthorizeView component supports roles based authorization base on the role we can render the content inside of it.
Index.razor:
@page "/" <AuthorizeView Roles="superadmin"> <Authorized > <div>Hi @(context.User.Identity.Name), hurray you have 'super admin' role, you can claim this offer</div> </Authorized> </AuthorizeView> <AuthorizeView Roles="admin"> <Authorized > <div>Hi @(context.User.Identity.Name), hurray you have 'admin' role, you can claim this offer</div> </Authorized> </AuthorizeView> <AuthorizeView Roles="user"> <Authorized> <div>Hi @(context.User.Identity.Name), hurray you have 'user' role ,Claim your user offers </div> </Authorized> </AuthorizeView>Here we rendered 3 AuthorizeView components with respective roles to them. For my fake authentication, I have only roles like 'admin' and 'user'. So if run the application for me content inside of the 'superadmin' will not render.
We can also configure multiple roles on the AuthorizeView component with comma separation. So in this process, if we have at least one role then AuthorizeView renders.
Index.razor:
@page "/" <AuthorizeView Roles="superadmin, admin"> <Authorized > <div>Hi @(context.User.Identity.Name), this offer can claim by users with role either 'superadmin' or'admin' </div> </Authorized> </AuthorizeView>
- Here we configure multiple roles with comma separation, so to render this AuthorizeView component user should have at least one role.
Policy-Based Roles Authorization On AuthorizeView Component:
The policy is a set of rules. In the case of roles the policy will group the set of roles, so the user at least one role in the policy group then the user satisfied that policy, and then the AuthorizeView component renders.
Program.cs:
builder.Services.AddAuthorizationCore(options => { options.AddPolicy("mypolicy", policy => { policy.RequireRole("admin","superadmin"); }); });
- Here we grouped our roles under a policy named 'mypolicy'. Now we can use this policy name to authorize the user.
@page "/" <AuthorizeView Policy="mypolicy"> <Authorized > <div>Hi @(context.User.Identity.Name), this offer can claim by users with role either 'superadmin' or'admin' </div> </Authorized> </AuthorizeView>
- Here AuthorizeView component renders the users who matched with at least one role that is grouped under the policy.
Roles Authorize Attribute To Page Components:
The Authorize attribute will be used on Page components. One thing to remember this will not work for normal components. Based on the user role using the authorize attribute we can deny or allow the page access to the user.
Index.razor:
@page "/" @attribute [Authorize(Roles="admin")]
- Here our Index page component only accessed by the users who have an 'admin' role.
Index.razor:
@page "/" @attribute [Authorize(Roles="admin,superadmin")]We can set multiple Authorize attributes on our Page Component, in this case, the user should have match the roles specified in each attribute.
Index.razor:
@page "/" @attribute [Authorize(Roles="admin")] @attribute [Authorize(Roles="user")]
- User's having both roles only can access the Index page component.
Index.razor:
@page "/" @attribute [Authorize(Policy="admin")]
- Here users that match at least one role under the policy group will access this page.
Claims-Based Authorization:
The Claims mean key-value pair of data which something like user information. To use claims-based authorization we need to write the policy for it, which means we can't use claims directly like we do in the case of roles.
Let's update some claims to my login.
Auth/CustomAuthStateProvider.cs:
var identity = new ClaimsIdentity(new []{ new Claim(ClaimTypes.Name,"Naveen"), new Claim("PageAccesskey", "1"), new Claim("PageAccesskey", "2") },"Fake Auth");
- Here I have claims like 'PageAccessKey' with 2 different values like '1' and '2'.
Program.cs:
builder.Services.AddAuthorizationCore(options => { options.AddPolicy("myAccessPolicy", policy => { policy.RequireClaim("PageAccesskey"); }); });
- Here we check a claims policy where users must have the claim to satisfy this policy. One more thing if we observe here we are not checking the value of the cliams.
Pages/Index.razor:
<AuthorizeView Policy="myAccessPolicy" > <Authorized > <div>Hi @(context.User.Identity.Name) </div> </Authorized> </AuthorizeView>
- So here claims policy check whether the user has the registered claim or not.
Program.cs:
options.AddPolicy("myAccessPolicy", policy => { policy.RequireClaim("PageAccesskey","1","2","3"); });
- Here now claims policy registered values of the claims as well. So in this case users should have this claim and also should match with at least one of the values of the claim.
So that's all about the authorization in the blazor webassembly application.
Support Me!
Buy Me A Coffee
PayPal Me
Wrapping Up:
Hopefully, I think this article delivered some useful information about Authorization in the Blazor WebAssembly Application. I love to have your feedback, suggestions, and better techniques in the comment section below.
Excellent. Thank you.
ReplyDelete