Skip to content

Instantly share code, notes, and snippets.

@vertonghenb
Last active December 14, 2022 15:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save vertonghenb/77c5c6baa4c5d7ab31a2e35c65f8dfbf to your computer and use it in GitHub Desktop.
Save vertonghenb/77c5c6baa4c5d7ab31a2e35c65f8dfbf to your computer and use it in GitHub Desktop.
Authenticated Weather Station
@using System.Net.Http
@using System.Net.Http.Json
// πŸ‘‡
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Authorization
// πŸ‘†
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using WeatherStation.Client
@using WeatherStation.Client.Shared
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@inject NavigationManager Navigation
@inject SignOutSessionStateManager SignOutManager
<AuthorizeView>
<Authorized>
Hello, @context.User.Identity.Name!
<a href="#" @onclick="BeginSignOut">Log out</a>
</Authorized>
<NotAuthorized>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>
@code{
private async Task BeginSignOut(MouseEventArgs args)
{
await SignOutManager.SetSignOutState();
Navigation.NavigateTo("authentication/logout");
}
}
<CascadingAuthenticationState> // πŸ‘ˆ
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
// πŸ‘‡
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
<p>Determining session state, please wait...</p>
</Authorizing>
<NotAuthorized>
<h1>Sorry</h1>
<p>You're not authorized to reach this page. You need to log in.</p>
</NotAuthorized>
</AuthorizeRouteView>
// πŸ‘†
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</CascadingAuthenticationState> // πŸ‘ˆ
{
"Auth0": {
"Authority": "https://<YOUR_AUTH0_DOMAIN>",
"ClientId": "<YOUR_CLIENT_ID>"
}
}
@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using Microsoft.Extensions.Configuration
@inject NavigationManager Navigation
@inject IConfiguration Configuration
<RemoteAuthenticatorView Action="@Action">
<LogOut>
@{
Logout();
}
</LogOut>
</RemoteAuthenticatorView>
@code {
[Parameter] public string Action { get; set; }
private void Logout()
{
var authority = Configuration["Auth0:Authority"];
var clientId = Configuration["Auth0:ClientId"];
Navigation.NavigateTo($"{authority}/v2/logout?client_id={clientId}");
}
}
{
"Auth0": {
"Authority": "https://**********.eu.auth0.com",
"ClientId": "Pbwsbr9N1s*************************",
"Audience": "<YOUR_API_IDENTIFIER>" // πŸ‘ˆ Remove this comment btw, since JSON cannot parse this 😒
}
}
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication; // πŸ‘ˆ
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using WeatherStation.Client;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
// πŸ‘‡
builder.Services.AddHttpClient("WeatherAPI", client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();
builder.Services.AddScoped(sp => sp.GetRequiredService<IHttpClientFactory>()
.CreateClient("WeatherAPI"));
// πŸ‘†
builder.Services.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Auth0", options.ProviderOptions);
options.ProviderOptions.ResponseType = "code";
options.ProviderOptions.AdditionalProviderParameters.Add("audience", builder.Configuration["Auth0:Audience"]);
});
await builder.Build().RunAsync();
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using WeatherStation.Client;
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.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Auth0", options.ProviderOptions);
options.ProviderOptions.ResponseType = "code";
options.ProviderOptions.AdditionalProviderParameters.Add("audience", builder.Configuration["Auth0:Audience"]); // πŸ‘ˆ
});
await builder.Build().RunAsync();
@page "/fetchdata"
@using WeatherStation.Shared
@inject HttpClient Http
@attribute [Authorize] // πŸ‘ˆ
<PageTitle>Weather forecast</PageTitle>
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>WeatherStation</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="WeatherStation.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">Loading...</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">πŸ—™</a>
</div>
<!-- πŸ‘‡ -->
<script src="_content/Microsoft.AspNetCore.Components.WebAssembly.Authentication/AuthenticationService.js"></script>
<!-- πŸ‘† -->
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<AccessControl /> // πŸ‘ˆ
<a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using WeatherStation.Client;
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.AddOidcAuthentication(options =>
{
builder.Configuration.Bind("Auth0", options.ProviderOptions);
options.ProviderOptions.ResponseType = "code";
});
// πŸ‘†
await builder.Build().RunAsync();
{
"Auth0": {
"Authority": "https://<YOUR_AUTH0_DOMAIN>",
"ApiIdentifier": "<YOUR_API_IDENTIFIER>"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
using Microsoft.AspNetCore.Authentication.JwtBearer; // πŸ‘ˆ
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// πŸ‘‡
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.Authority = builder.Configuration["Auth0:Authority"];
options.Audience = builder.Configuration["Auth0:ApiIdentifier"];
});
// πŸ‘†
builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
// πŸ‘‡ Always after UseRouting()
app.UseAuthentication();
app.UseAuthorization(); // Authorization ALWAYS after Authentication, both after UseRouting(); 😷
// πŸ‘†
app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");
app.Run();
using Microsoft.AspNetCore.Mvc;
using WeatherStation.Shared;
namespace WeatherStation.Server.Controllers;
[ApiController]
[Route("[controller]")]
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 = 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]
public WeatherForecast CreateForecast(WeatherForecast forecast)
{
forecasts.Add(forecast);
return forecast;
}
}
using Microsoft.AspNetCore.Authorization; // πŸ‘ˆ
using Microsoft.AspNetCore.Mvc;
using WeatherStation.Shared;
namespace WeatherStation.Server.Controllers;
[ApiController]
[Route("[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 = 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]
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