{"id":56700,"date":"2021-01-27T08:00:03","date_gmt":"2021-01-27T07:00:03","guid":{"rendered":"https:\/\/code-maze.com\/?p=56700"},"modified":"2022-05-25T00:06:36","modified_gmt":"2022-05-24T22:06:36","slug":"using-roles-in-blazor-webassembly-hosted-applications","status":"publish","type":"post","link":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/","title":{"rendered":"Using Roles in Blazor WebAssembly Hosted Applications"},"content":{"rendered":"<p>In this article, we are going to learn how to use Roles in Blazor WebAssembly Hosted applications for an additional level of security for both Blazor-Client pages and Blazor-Server controllers.<\/p>\n<div style=\"padding: 20px; border-left: 5px #dc2323 solid; display: block; margin-bottom: 20px; box-shadow: 1px 1px 5px 0px lightgrey;\">To download the source code for this article, you can visit our <a href=\"https:\/\/github.com\/CodeMazeBlog\/blazor-wasm-hosted-security\/tree\/adding_roles_blazor_wasm_hosted\" target=\"_blank\" rel=\"nofollow noopener\">Roles in Blazor WebAssembly Hosted Applications<\/a> repository<\/div>\n<p>If you want to learn more about Blazor WebAssembly, we strongly suggest visiting our\u00a0<a href=\"https:\/\/code-maze.com\/blazor-webassembly-series\/\" target=\"_blank\" rel=\"noopener noreferrer\">Blazor WebAssembly series of articles<\/a>, where you can read about Blazor WebAssembly development, authentication, authorization, JSInterop, and other topics as well.<\/p>\n<p>So, let&#8217;s start.<\/p>\n<h2 id=\"adding-roles\">Adding Roles in the Database<\/h2>\n<p>We have already created the Blazor WebAssembly Hosted project with applied authentication in <a href=\"https:\/\/code-maze.com\/authentication-in-blazor-webassembly-hosted-applications\/\" target=\"_blank\" rel=\"noopener\">our previous article<\/a>. So, we will just continue with the same project.<\/p>\n<p>First of all, we have to support roles for ASP.NET Core Identity. To do that, let&#8217;s modify the configuration in the <code>Startup<\/code> class <strong>or the Program class if you are using .NET 6 and above<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"2\">services.AddDefaultIdentity&lt;ApplicationUser&gt;(options =&gt; options.SignIn.RequireConfirmedAccount = false)\r\n    .AddRoles&lt;IdentityRole&gt;()\r\n    .AddEntityFrameworkStores&lt;ApplicationDbContext&gt;();<\/pre>\n<p>All we do here is use the <code>AddRoles<\/code> method to include role services for ASP.NET Core Identity.<\/p>\n<p>Now, we have to add roles to the database. To do that, we are going to create a new class in the <code>Data<\/code> folder:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class RoleConfiguration : IEntityTypeConfiguration&lt;IdentityRole&gt;\r\n{\r\n    public void Configure(EntityTypeBuilder&lt;IdentityRole&gt; builder)\r\n    {\r\n        builder.HasData(\r\n            new IdentityRole\r\n            {\r\n                Name = \"Visitor\",\r\n                NormalizedName = \"VISITOR\"\r\n            },\r\n            new IdentityRole\r\n            {\r\n                Name = \"Administrator\",\r\n                NormalizedName = \"ADMINISTRATOR\"\r\n            }\r\n        );\r\n    }\r\n}<\/pre>\n<p>Also, we have to include this class in the <code>ApplicationDbContext<\/code> class and override the <code>OnModelCreating<\/code> method:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"9-14\">public class ApplicationDbContext : ApiAuthorizationDbContext&lt;ApplicationUser&gt;\r\n{\r\n    public ApplicationDbContext(\r\n        DbContextOptions options,\r\n        IOptions&lt;OperationalStoreOptions&gt; operationalStoreOptions) : base(options, operationalStoreOptions)\r\n    {\r\n    }\r\n\r\n    protected override void OnModelCreating(ModelBuilder builder)\r\n    {\r\n        base.OnModelCreating(builder);\r\n        \r\n        builder.ApplyConfiguration(new RoleConfiguration());\r\n    }\r\n}<\/pre>\n<p>After that, we are going to create our migration files and execute them to update the database:<\/p>\n<p><code>Add-Migration RolesAdded -o Data\/Migrations<\/code><\/p>\n<p><code>Update-Database<\/code>.<\/p>\n<p>As you can see, when we create new migration files, we use the <code>-o<\/code> flag to specify the output folder.<\/p>\n<p>Finally, since we have a single user in the database, let&#8217;s attach an admin role to that user:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">INSERT INTO AspNetUserRoles \r\nVALUES ('UserId','Administrator RoleId')<\/pre>\n<p>Of course, you will use your id values for the existing user and the Administrator role.<\/p>\n<h2 id=\"implementing-roles\">Implementing Roles in a Blazor WebAssembly Hosted Application<\/h2>\n<p>Now that we have roles configured and placed in the database, we can use that to protect our pages and actions.<\/p>\n<p>Let&#8217;s first modify the <code>FetchData<\/code> component to allow the Administrator role only:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"5\">@page\u00a0\"\/fetchdata\" \r\n@using\u00a0Microsoft.AspNetCore.Authorization \r\n@using\u00a0Microsoft.AspNetCore.Components.WebAssembly.Authentication \r\n@using\u00a0BlazorWasmHostedAuth.Shared \r\n@attribute\u00a0[Authorize(Roles\u00a0=\u00a0\"Administrator\")] \r\n@inject\u00a0HttpClient\u00a0Http<\/pre>\n<p>Then, we can do the same thing for the <code>WeatherForecastController<\/code>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"1\">[Authorize(Roles\u00a0=\u00a0\"Administrator\")] \r\n[ApiController] \r\n[Route(\"[controller]\")] \r\npublic\u00a0class\u00a0WeatherForecastController\u00a0:\u00a0ControllerBase<\/pre>\n<p>What we want to do now is to modify the user registration logic to include the Visitor role as soon as we register a new user. To do that, we have to include the <code>Register.cshtml<\/code> and <code>Register.cshtml.cs<\/code> files in our project (add a new scaffolded item). We did the same thing in the <a href=\"https:\/\/code-maze.com\/authentication-in-blazor-webassembly-hosted-applications\" target=\"_blank\" rel=\"noopener noreferrer\">previous article<\/a> with the Account\/Login page (<a href=\"https:\/\/code-maze.com\/authentication-in-blazor-webassembly-hosted-applications\/#customizing\" target=\"_blank\" rel=\"noopener\">Customizing Components<\/a> section), so in the same way, we can include the Account\/Register page.<\/p>\n<p>Once we have the Register page in our project, we can open the <code>Register.cshtml.cs<\/code> file and modify the <code>OnPostAsync<\/code> method to include the Visitor role for newly created users:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"4\">...\r\nelse\r\n{\r\n    await _userManager.AddToRoleAsync(user, \"Visitor\");\r\n    await _signInManager.SignInAsync(user, isPersistent: false);\r\n    return LocalRedirect(returnUrl);\r\n}<\/pre>\n<p>Okay.<\/p>\n<p>Let&#8217;s start the app, register a new user, try to click Fetch data, and inspect the result:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/15-User-withour-neccessary-roles.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-56737\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/15-User-withour-neccessary-roles.png\" alt=\"User withour neccessary roles in blazor webassembly hosted apps\" width=\"504\" height=\"119\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/15-User-withour-neccessary-roles.png 504w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/15-User-withour-neccessary-roles-300x71.png 300w\" sizes=\"auto, (max-width: 504px) 100vw, 504px\" \/><\/a><\/p>\n<p>We can see that the user with the Visitor role can&#8217;t access this page.<\/p>\n<p>If we do the same with the Administrator user (the one we already have in the database), we will see the same response. Well, that&#8217;s not what we expect.<\/p>\n<p>To see the reason for that, let&#8217;s remove the <code>Roles<\/code> property from the <code>[Authorize]<\/code> attribute in both <code>FetchData<\/code> (client project) and <code>WeatherForecastController<\/code> (server project) files.<\/p>\n<p>Also, we are going to add a bit more code to the <code>FetchData<\/code> page to show user claims:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">&lt;h2&gt;Claims&lt;\/h2&gt;\r\n&lt;AuthorizeView&gt;\r\n    &lt;ul&gt;\r\n        @foreach (var claim in context.User.Claims)\r\n        {\r\n            &lt;li&gt;&lt;b&gt;@claim.Type&lt;\/b&gt;: @claim.Value&lt;\/li&gt;\r\n        }\r\n    &lt;\/ul&gt;\r\n&lt;\/AuthorizeView&gt;<\/pre>\n<p>At this point, we can start the app, log in with the admin user, and navigate to the FetchData page:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/16-Claims-without-roles-in-Blazor-WebAssembly-Hosted-applicaitons.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-56738\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/16-Claims-without-roles-in-Blazor-WebAssembly-Hosted-applicaitons.png\" alt=\"Claims without roles in Blazor WebAssembly Hosted applicaitons\" width=\"483\" height=\"302\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/16-Claims-without-roles-in-Blazor-WebAssembly-Hosted-applicaitons.png 483w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/16-Claims-without-roles-in-Blazor-WebAssembly-Hosted-applicaitons-300x188.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/16-Claims-without-roles-in-Blazor-WebAssembly-Hosted-applicaitons-400x250.png 400w\" sizes=\"auto, (max-width: 483px) 100vw, 483px\" \/><\/a><\/p>\n<p>We can see there is no Role claim, and that&#8217;s the reason why both Administrator and Visitor can&#8217;t access the page.<\/p>\n<p>Now we can return the <code>Roles<\/code> property in both files.<\/p>\n<h3>Adding Roles to the Claims<\/h3>\n<p>To solve our problem with a role claim, we have to include it in the claim list. To do that, we are going to modify the <code>ConfigureServices<\/code> method in the <code>Startup<\/code> class <strong> or the Program class in .NET 6 and above <\/strong>(the code we are adding is the same for .NET 5 or .NET 6 and above):<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\" data-enlighter-highlight=\"2-7\">services.AddIdentityServer()\r\n    .AddApiAuthorization&lt;ApplicationUser, ApplicationDbContext&gt;(opt =&gt; \r\n    {\r\n        opt.IdentityResources[\"openid\"].UserClaims.Add(\"role\");\r\n        opt.ApiResources.Single().UserClaims.Add(\"role\");\r\n    });\r\nJwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove(\"role\");<\/pre>\n<p>Here we are using the <code>Action<\/code> delegate parameter of the <code>AddApiAuthorization<\/code> method to configure additional options. We add the role claim to user claims collection for both Identity resources and API resources. Also, we prevent the default mapping for roles in the JWT token handler.<\/p>\n<p>Now if we start the app, and log in as the administrator, we will be able to access the FetchData page and we will see the role claim in the claims list. Of course, we won&#8217;t be able to do that with the Visitor user.<\/p>\n<p>Additionally, if we don&#8217;t want to show the FetchData link for the non-administrator users, we can modify the <code>NavMenu.razor<\/code> file:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"html\">&lt;AuthorizeView Roles=\"Administrator\"&gt;\r\n    &lt;Authorized&gt;\r\n        &lt;li class=\"nav-item px-3\"&gt;\r\n            &lt;NavLink class=\"nav-link\" href=\"fetchdata\"&gt;\r\n                &lt;span class=\"oi oi-list-rich\" aria-hidden=\"true\"&gt;&lt;\/span&gt; Fetch data\r\n            &lt;\/NavLink&gt;\r\n        &lt;\/li&gt;\r\n    &lt;\/Authorized&gt;\r\n&lt;\/AuthorizeView&gt;<\/pre>\n<p>Once we log in as a Visitor, we won&#8217;t be able to see the page link:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/17-Hidden-Menu-Item-for-users-with-different-roles.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-56739\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/17-Hidden-Menu-Item-for-users-with-different-roles.png\" alt=\"Hidden Menu Item for users with different roles\" width=\"821\" height=\"339\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/17-Hidden-Menu-Item-for-users-with-different-roles.png 821w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/17-Hidden-Menu-Item-for-users-with-different-roles-300x124.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/17-Hidden-Menu-Item-for-users-with-different-roles-768x317.png 768w\" sizes=\"auto, (max-width: 821px) 100vw, 821px\" \/><\/a><\/p>\n<h2 id=\"supporting-multiple-roles\">Supporting Multiple Roles<\/h2>\n<p>Before we implement logic to support multiple roles, let&#8217;s add a new role for our admin user:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">INSERT INTO AspNetUserRoles \r\nVALUES ('UserId','Visitor RoleId')<\/pre>\n<p>Now, we can start the app, and log in as the Administrator:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/18-Multiple-roles-in-Blazor-WebAssembly-Hosted-not-supported.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-56743\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/18-Multiple-roles-in-Blazor-WebAssembly-Hosted-not-supported.png\" alt=\"Multiple roles in Blazor WebAssembly Hosted not supported\" width=\"847\" height=\"338\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/18-Multiple-roles-in-Blazor-WebAssembly-Hosted-not-supported.png 847w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/18-Multiple-roles-in-Blazor-WebAssembly-Hosted-not-supported-300x120.png 300w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/18-Multiple-roles-in-Blazor-WebAssembly-Hosted-not-supported-768x306.png 768w\" sizes=\"auto, (max-width: 847px) 100vw, 847px\" \/><\/a><\/p>\n<p>What we can see is that we are missing the FetchData menu even though our user should be able to see it.<\/p>\n<p>So, where is the problem?<\/p>\n<p>The problem is that IdentityServer sends multiple roles as a JSON array in a single role claim: <code>role: [\"Administrator\", \"Visitor\"]<\/code>. So, what we need to do is to create a way to split this array into multiple role claims with a single role as a value.<\/p>\n<p>To do that, we are going to create a new factory class on the client-side and modify it:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">public class CustomUserFactory : AccountClaimsPrincipalFactory&lt;RemoteUserAccount&gt;\r\n{\r\n    public CustomUserFactory(IAccessTokenProviderAccessor accessor)\r\n        : base(accessor)\r\n    {\r\n    }\r\n\r\n    public async override ValueTask&lt;ClaimsPrincipal&gt; CreateUserAsync(\r\n        RemoteUserAccount account,\r\n        RemoteAuthenticationUserOptions options)\r\n    {\r\n        var user = await base.CreateUserAsync(account, options);\r\n        var claimsIdentity = (ClaimsIdentity)user.Identity;\r\n\r\n        if (account != null)\r\n        {\r\n            MapArrayClaimsToMultipleSeparateClaims(account, claimsIdentity);\r\n        }\r\n\r\n        return user;\r\n    }\r\n\r\n    private void MapArrayClaimsToMultipleSeparateClaims(RemoteUserAccount account, ClaimsIdentity claimsIdentity)\r\n    {\r\n        foreach (var prop in account.AdditionalProperties)\r\n        {\r\n            var key = prop.Key;\r\n            var value = prop.Value;\r\n            if (value != null &amp;&amp;\r\n                (value is JsonElement element &amp;&amp; element.ValueKind == JsonValueKind.Array))\r\n            {\r\n                claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(prop.Key));\r\n                var claims = element.EnumerateArray()\r\n                    .Select(x =&gt; new Claim(prop.Key, x.ToString()));\r\n                claimsIdentity.AddClaims(claims);\r\n            }\r\n        }\r\n    }\r\n}<\/pre>\n<p>So, we create a new class that inherits from the\u00a0<code>AccountClaimsPrincipalFactory<\/code> class and overrides the <code>CreateUserAsync<\/code> method. We use the <code>AccountClaimsPrincipalFactory<\/code> class to enable a default implementation for converting a <code>RemoteUserAccount<\/code> into a <code>ClaimsPrincipal<\/code>. In the overridden <code>CreateUserAsync<\/code> method, we extract the <code>ClaimsIdentity<\/code> from the created user and call the <code>MapArrayClaimsToMultipleSeparateClaims<\/code> method. In this method, we iterate through every property from the account&#8217;s <code>AdditionalProperties<\/code> collection and if we find the value and that value is a JSON array, we map each element of the array as a separate claim.<\/p>\n<p>Finally, we have to register this custom factory in the <code>Program<\/code> class:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"csharp\">builder.Services.AddApiAuthorization()\r\n    .AddAccountClaimsPrincipalFactory&lt;CustomUserFactory&gt;();<\/pre>\n<p>Excellent.<\/p>\n<p>Now, we can test our solution.<\/p>\n<p>First of all, as soon as we log in as Administrator, we can see the FetchData menu. Once we navigate there, we can see the content and both roles:<\/p>\n<p><a href=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/19-Multiple-roles-included-in-the-claims-list.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-56744\" src=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/19-Multiple-roles-included-in-the-claims-list.png\" alt=\"Multiple roles included in the claims list\" width=\"489\" height=\"358\" srcset=\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/19-Multiple-roles-included-in-the-claims-list.png 489w, https:\/\/code-maze.com\/wp-content\/uploads\/2020\/12\/19-Multiple-roles-included-in-the-claims-list-300x220.png 300w\" sizes=\"auto, (max-width: 489px) 100vw, 489px\" \/><\/a><\/p>\n<p>So, that&#8217;s all it takes to handle multiple roles for a single user.<\/p>\n<h2 id=\"conclusion\">Conclusion<\/h2>\n<p>In this article, we have learned:<\/p>\n<ul>\n<li>How to use ASP.NET Core Identity and Migrations to create roles in the database<\/li>\n<li>How to implement roles in Blazor WebAssembly Hosted applications<\/li>\n<li>The way to handle multiple roles for a single user<\/li>\n<\/ul>\n<p>In the next article, we are going to learn about <a href=\"https:\/\/code-maze.com\/google-authentication-in-blazor-webassembly-hosted-applications\/\" target=\"_blank\" rel=\"noopener\">external Google authentication in Blazor WebAssembly Hosted<\/a> applications.<\/p>\n<p>Until then.<\/p>\n<p>All the best.<\/p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article, we are going to learn how to use Roles in Blazor WebAssembly Hosted applications for an additional level of security for both Blazor-Client pages and Blazor-Server controllers. If you want to learn more about Blazor WebAssembly, we strongly suggest visiting our\u00a0Blazor WebAssembly series of articles, where you can read about Blazor WebAssembly [&hellip;]<\/p>\n","protected":false},"author":3,"featured_media":57149,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"","_et_pb_old_content":"","_et_gb_content_width":"","footnotes":""},"categories":[683,684,12],"tags":[685,828,829,415],"class_list":["post-56700","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blazor","category-blazor-webassembly","category-csharp","tag-blazor","tag-blazor-webassembly-hosted","tag-role-based-authrorization","tag-roles","et-has-post-format-content","et_post_format-et-post-format-standard"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.7 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Using Roles in Blazor WebAssembly Hosted Applications - Code Maze<\/title>\n<meta name=\"description\" content=\"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Using Roles in Blazor WebAssembly Hosted Applications - Code Maze\" \/>\n<meta property=\"og:description\" content=\"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\" \/>\n<meta property=\"og:site_name\" content=\"Code Maze\" \/>\n<meta property=\"article:published_time\" content=\"2021-01-27T07:00:03+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2022-05-24T22:06:36+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1100\" \/>\n\t<meta property=\"og:image:height\" content=\"620\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Marinko Spasojevi\u0107\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@https:\/\/twitter.com\/CodeMazeBlog\" \/>\n<meta name=\"twitter:site\" content=\"@CodeMazeBlog\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Marinko Spasojevi\u0107\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":[\"Article\",\"BlogPosting\"],\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\"},\"author\":{\"name\":\"Marinko Spasojevi\u0107\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\"},\"headline\":\"Using Roles in Blazor WebAssembly Hosted Applications\",\"datePublished\":\"2021-01-27T07:00:03+00:00\",\"dateModified\":\"2022-05-24T22:06:36+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\"},\"wordCount\":1104,\"commentCount\":8,\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png\",\"keywords\":[\"Blazor\",\"Blazor WebAssembly Hosted\",\"Role-Based Authrorization\",\"roles\"],\"articleSection\":[\"Blazor\",\"Blazor WebAssembly\",\"C#\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\",\"url\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\",\"name\":\"Using Roles in Blazor WebAssembly Hosted Applications - Code Maze\",\"isPartOf\":{\"@id\":\"https:\/\/code-maze.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png\",\"datePublished\":\"2021-01-27T07:00:03+00:00\",\"dateModified\":\"2022-05-24T22:06:36+00:00\",\"description\":\"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.\",\"breadcrumb\":{\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png\",\"width\":1100,\"height\":620,\"caption\":\"Using Roles in Blazor WebAssembly Hosted Apps\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/code-maze.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Using Roles in Blazor WebAssembly Hosted Applications\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/code-maze.com\/#website\",\"url\":\"https:\/\/code-maze.com\/\",\"name\":\"Code Maze\",\"description\":\"Learn. Code. Succeed.\",\"publisher\":{\"@id\":\"https:\/\/code-maze.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/code-maze.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/code-maze.com\/#organization\",\"name\":\"Code Maze\",\"url\":\"https:\/\/code-maze.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png\",\"width\":3511,\"height\":3510,\"caption\":\"Code Maze\"},\"image\":{\"@id\":\"https:\/\/code-maze.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/CodeMazeBlog\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533\",\"name\":\"Marinko Spasojevi\u0107\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/code-maze.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"contentUrl\":\"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg\",\"caption\":\"Marinko Spasojevi\u0107\"},\"description\":\"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.\",\"sameAs\":[\"https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/\",\"https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog\"],\"url\":\"https:\/\/code-maze.com\/author\/marinko\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Using Roles in Blazor WebAssembly Hosted Applications - Code Maze","description":"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/","og_locale":"en_US","og_type":"article","og_title":"Using Roles in Blazor WebAssembly Hosted Applications - Code Maze","og_description":"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.","og_url":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/","og_site_name":"Code Maze","article_published_time":"2021-01-27T07:00:03+00:00","article_modified_time":"2022-05-24T22:06:36+00:00","og_image":[{"width":1100,"height":620,"url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png","type":"image\/png"}],"author":"Marinko Spasojevi\u0107","twitter_card":"summary_large_image","twitter_creator":"@https:\/\/twitter.com\/CodeMazeBlog","twitter_site":"@CodeMazeBlog","twitter_misc":{"Written by":"Marinko Spasojevi\u0107","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":["Article","BlogPosting"],"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#article","isPartOf":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/"},"author":{"name":"Marinko Spasojevi\u0107","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533"},"headline":"Using Roles in Blazor WebAssembly Hosted Applications","datePublished":"2021-01-27T07:00:03+00:00","dateModified":"2022-05-24T22:06:36+00:00","mainEntityOfPage":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/"},"wordCount":1104,"commentCount":8,"publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"image":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png","keywords":["Blazor","Blazor WebAssembly Hosted","Role-Based Authrorization","roles"],"articleSection":["Blazor","Blazor WebAssembly","C#"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/","url":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/","name":"Using Roles in Blazor WebAssembly Hosted Applications - Code Maze","isPartOf":{"@id":"https:\/\/code-maze.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage"},"image":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage"},"thumbnailUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png","datePublished":"2021-01-27T07:00:03+00:00","dateModified":"2022-05-24T22:06:36+00:00","description":"In this article we are going to learn about using roles in Blazor WebAssembly Hosted applications and how to support multiple roles.","breadcrumb":{"@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#primaryimage","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2021\/01\/Using-Roles-in-Blazor-WebAssembly-Hosted-Apps.png","width":1100,"height":620,"caption":"Using Roles in Blazor WebAssembly Hosted Apps"},{"@type":"BreadcrumbList","@id":"https:\/\/code-maze.com\/using-roles-in-blazor-webassembly-hosted-applications\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/code-maze.com\/"},{"@type":"ListItem","position":2,"name":"Using Roles in Blazor WebAssembly Hosted Applications"}]},{"@type":"WebSite","@id":"https:\/\/code-maze.com\/#website","url":"https:\/\/code-maze.com\/","name":"Code Maze","description":"Learn. Code. Succeed.","publisher":{"@id":"https:\/\/code-maze.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/code-maze.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/code-maze.com\/#organization","name":"Code Maze","url":"https:\/\/code-maze.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/Code-Maze-Only-Logo-Transparent-HRez.png","width":3511,"height":3510,"caption":"Code Maze"},"image":{"@id":"https:\/\/code-maze.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/CodeMazeBlog"]},{"@type":"Person","@id":"https:\/\/code-maze.com\/#\/schema\/person\/d6fa06e66820968d19b39fb63cff2533","name":"Marinko Spasojevi\u0107","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/code-maze.com\/#\/schema\/person\/image\/","url":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","contentUrl":"https:\/\/code-maze.com\/wp-content\/uploads\/2020\/01\/marinko-1x1-3-150x150.jpg","caption":"Marinko Spasojevi\u0107"},"description":"Hi, my name is Marinko Spasojevic. Currently, I work as a full-time .NET developer and my passion is web application development. Just getting something to work is not enough for me. To make it just how I like it, it must be readable, reusable, and easy to maintain. Prior to being an author on the CodeMaze blog, I had been working as a professor of Computer Science for several years. So, sharing knowledge while working as a full-time developer comes naturally to me.","sameAs":["https:\/\/www.linkedin.com\/in\/marinko-spasojevic\/","https:\/\/x.com\/https:\/\/twitter.com\/CodeMazeBlog"],"url":"https:\/\/code-maze.com\/author\/marinko\/"}]}},"_links":{"self":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/56700","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/comments?post=56700"}],"version-history":[{"count":4,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/56700\/revisions"}],"predecessor-version":[{"id":70585,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/posts\/56700\/revisions\/70585"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media\/57149"}],"wp:attachment":[{"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/media?parent=56700"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/categories?post=56700"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/code-maze.com\/wp-json\/wp\/v2\/tags?post=56700"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}