Last active
October 4, 2024 08:54
-
-
Save vertonghenb/65fe177b04f13037c83e745fefa123a9 to your computer and use it in GitHub Desktop.
Blazor Authorization with Auth0
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @page "/add-weather" | |
| @using Shared | |
| @inject HttpClient Http | |
| @inject NavigationManager NavigationManager | |
| @attribute [Authorize(Roles = "Administrator")] | |
| <PageTitle>Add Weather Data</PageTitle> | |
| <h3>Add Weather Data</h3> | |
| <EditForm Model="forecast" OnValidSubmit="Add"> | |
| <div class="form-group"> | |
| <label>Date</label> | |
| <InputDate class="form-control" @bind-Value="forecast.Date" /> | |
| </div> | |
| <div class="form-group"> | |
| <label>Temperature (C)</label> | |
| <InputNumber class="form-control" @bind-Value="forecast.TemperatureC" /> | |
| </div> | |
| <div class="form-group"> | |
| <label>Summary</label> | |
| <InputSelect class="form-control" @bind-Value="forecast.Summary"> | |
| <option value="">Select</option> | |
| <option value="Freezing">Freezing</option> | |
| <option value="Bracing">Bracing</option> | |
| <option value="Chilly">Chilly</option> | |
| <option value="Cool">Cool</option> | |
| <option value="Mild">Mild</option> | |
| <option value="Warm">Warm</option> | |
| <option value="Balmy">Balmy</option> | |
| <option value="Hot">Hot</option> | |
| <option value="Sweltering">Sweltering</option> | |
| <option value="Scorching">Scorching</option> | |
| </InputSelect> | |
| </div> | |
| <button class="btn btn-primary mt-2" type="submit">Add Weather</button> | |
| </EditForm> | |
| @code { | |
| private WeatherForecast forecast = new(); | |
| protected override void OnInitialized() | |
| { | |
| base.OnInitialized(); | |
| forecast.Date = DateOnly.FromDateTime(DateTime.Now); | |
| } | |
| private async Task Add() | |
| { | |
| var response = await Http.PostAsJsonAsync<WeatherForecast>("api/weatherforecast", forecast); | |
| response.EnsureSuccessStatusCode(); | |
| NavigationManager.NavigateTo("weather"); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Microsoft.AspNetCore.Components.WebAssembly.Authentication; | |
| using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal; | |
| using System.Security.Claims; | |
| using System.Text.Json; | |
| namespace Client.Auth; | |
| public class ArrayClaimsPrincipalFactory<TAccount> : AccountClaimsPrincipalFactory<TAccount> where TAccount : RemoteUserAccount | |
| { | |
| public ArrayClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor) | |
| : base(accessor) | |
| { } | |
| // when a user belongs to multiple roles, Auth0 returns a single claim with a serialised array of values | |
| // this class improves the original factory by deserializing the claims in the correct way | |
| public async override ValueTask<ClaimsPrincipal> CreateUserAsync(TAccount account, RemoteAuthenticationUserOptions options) | |
| { | |
| var user = await base.CreateUserAsync(account, options); | |
| var claimsIdentity = (ClaimsIdentity)user.Identity!; | |
| if (account != null) | |
| { | |
| foreach (var kvp in account.AdditionalProperties) | |
| { | |
| var name = kvp.Key; | |
| var value = kvp.Value; | |
| if (value != null && | |
| value is JsonElement element && element.ValueKind == JsonValueKind.Array) | |
| { | |
| claimsIdentity.RemoveClaim(claimsIdentity.FindFirst(kvp.Key)); | |
| var claims = element.EnumerateArray() | |
| .Select(x => new Claim(kvp.Key, x.ToString())); | |
| claimsIdentity.AddClaims(claims); | |
| } | |
| } | |
| } | |
| return user; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| @page "/" | |
| <PageTitle>Home</PageTitle> | |
| <AuthorizeView> | |
| <Authorized> | |
| @foreach (var claim in context.User.Claims) | |
| { | |
| <p>@claim.Type - @claim.Value</p> | |
| } | |
| </Authorized> | |
| <NotAuthorized> | |
| Please login to see all the claims, <a href="authentication/login">Log in</a> | |
| </NotAuthorized> | |
| </AuthorizeView> | |
| <AuthorizeView Roles="Administrator"> | |
| Only Administrators can see this. | |
| </AuthorizeView> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * @param {Event} event - Details about the user and the context in which they are logging in. | |
| * @param {PostLoginAPI} api - Interface whose methods can be used to change the behavior of the login. | |
| */ | |
| exports.onExecutePostLogin = async (event, api) => { | |
| const claimName = 'http://schemas.microsoft.com/ws/2008/06/identity/claims/role' | |
| if (event.authorization) { | |
| api.idToken.setCustomClaim(claimName, event.authorization.roles); | |
| api.accessToken.setCustomClaim(claimName, event.authorization.roles); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Microsoft.AspNetCore.Components.Web; | |
| using Microsoft.AspNetCore.Components.WebAssembly.Hosting; | |
| using Client; | |
| using Client.Auth; // 👈 | |
| using Microsoft.AspNetCore.Components.WebAssembly.Authentication; // 👈 | |
| var builder = WebAssemblyHostBuilder.CreateDefault(args); | |
| builder.RootComponents.Add<App>("#app"); | |
| builder.RootComponents.Add<HeadOutlet>("head::after"); | |
| builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); | |
| builder.Services.AddCascadingAuthenticationState(); | |
| builder.Services.AddOidcAuthentication(options => | |
| { | |
| builder.Configuration.Bind("Auth0", options.ProviderOptions); | |
| options.ProviderOptions.ResponseType = "code"; | |
| options.ProviderOptions.PostLogoutRedirectUri = builder.HostEnvironment.BaseAddress; | |
| options.ProviderOptions.AdditionalProviderParameters.Add("audience", builder.Configuration["Auth0:Audience"]!); | |
| // 👇 | |
| }).AddAccountClaimsPrincipalFactory<ArrayClaimsPrincipalFactory<RemoteUserAccount>>(); | |
| // 👆 | |
| await builder.Build().RunAsync(); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using Microsoft.AspNetCore.Authorization; | |
| using Microsoft.AspNetCore.Mvc; | |
| using Shared; | |
| namespace Server.Controllers; | |
| [ApiController] | |
| [Route("api/[controller]")] | |
| [Authorize] | |
| public class WeatherForecastController : ControllerBase | |
| { | |
| private static readonly string[] Summaries = new[] | |
| { | |
| "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" | |
| }; | |
| private static readonly List<WeatherForecast> forecasts = new(); | |
| static WeatherForecastController() | |
| { | |
| forecasts.AddRange(Enumerable.Range(1, 5).Select(index => new WeatherForecast | |
| { | |
| Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)), | |
| TemperatureC = Random.Shared.Next(-20, 55), | |
| Summary = Summaries[Random.Shared.Next(Summaries.Length)] | |
| })); | |
| } | |
| [HttpGet] | |
| public IEnumerable<WeatherForecast> GetForecasts() | |
| { | |
| return forecasts; | |
| } | |
| [HttpPost] | |
| [Authorize(Roles = "Administrator")] // 👈 | |
| public WeatherForecast CreateForecast(WeatherForecast forecast) | |
| { | |
| forecasts.Add(forecast); | |
| return forecast; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment