-
-
Notifications
You must be signed in to change notification settings - Fork 304
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a Blazor Hybrid sample using GitHub authentication
- Loading branch information
1 parent
9ebebb6
commit e313185
Showing
21 changed files
with
469 additions
and
11 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
<Application x:Class="Sorgan.BlazorHybrid.Client.App" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:local="clr-namespace:Sorgan.BlazorHybrid.Client" | ||
StartupUri="MainWindow.xaml"> | ||
</Application> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using System.Windows; | ||
|
||
namespace Sorgan.BlazorHybrid.Client; | ||
|
||
public partial class App : Application | ||
{ | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
@using OpenIddict.Client; | ||
@using System.Security.Claims; | ||
@using System.Threading | ||
@using System.Windows | ||
@using static OpenIddict.Abstractions.OpenIddictExceptions | ||
@using static OpenIddict.Abstractions.OpenIddictConstants | ||
@inject OpenIddictClientService service; | ||
|
||
<div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);"> | ||
<button disabled="@IsButtonDisabled" style="font-size: large" @onclick="LoginAsync">Log in using GitHub</button> | ||
</div> | ||
|
||
@code | ||
{ | ||
private bool IsButtonDisabled; | ||
|
||
public async Task LoginAsync() | ||
{ | ||
// Disable the login button to prevent concurrent authentication operations. | ||
IsButtonDisabled = true; | ||
|
||
try | ||
{ | ||
using var source = new CancellationTokenSource(delay: TimeSpan.FromSeconds(90)); | ||
|
||
try | ||
{ | ||
// Ask OpenIddict to initiate the authentication flow (typically, by starting the system browser). | ||
var result = await service.ChallengeInteractivelyAsync(new() | ||
{ | ||
CancellationToken = source.Token | ||
}); | ||
|
||
// Wait for the user to complete the authorization process. | ||
var principal = (await service.AuthenticateInteractivelyAsync(new() | ||
{ | ||
CancellationToken = source.Token, | ||
Nonce = result.Nonce | ||
})).Principal; | ||
|
||
MessageBox.Show($"Welcome, {principal.FindFirst(ClaimTypes.Name)!.Value}.", | ||
"Authentication successful", MessageBoxButton.OK, MessageBoxImage.Information); | ||
} | ||
|
||
catch (OperationCanceledException) | ||
{ | ||
MessageBox.Show("The authentication process was aborted.", | ||
"Authentication timed out", MessageBoxButton.OK, MessageBoxImage.Warning); | ||
} | ||
|
||
catch (ProtocolException exception) when (exception.Error is Errors.AccessDenied) | ||
{ | ||
MessageBox.Show("The authorization was denied by the end user.", | ||
"Authorization denied", MessageBoxButton.OK, MessageBoxImage.Warning); | ||
} | ||
|
||
catch | ||
{ | ||
MessageBox.Show("An error occurred while trying to authenticate the user.", | ||
"Authentication failed", MessageBoxButton.OK, MessageBoxImage.Error); | ||
} | ||
} | ||
|
||
finally | ||
{ | ||
// Re-enable the login button to allow starting a new authentication operation. | ||
IsButtonDisabled = false; | ||
} | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
<Window x:Class="Sorgan.BlazorHybrid.Client.MainWindow" | ||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
xmlns:blazor="clr-namespace:Microsoft.AspNetCore.Components.WebView.Wpf;assembly=Microsoft.AspNetCore.Components.WebView.Wpf" | ||
xmlns:local="clr-namespace:Sorgan.BlazorHybrid.Client" | ||
mc:Ignorable="d" | ||
Title="MainWindow" Height="450" Width="800"> | ||
<Grid> | ||
<blazor:BlazorWebView HostPage="wwwroot\index.html" Services="{DynamicResource services}"> | ||
<blazor:BlazorWebView.RootComponents> | ||
<blazor:RootComponent Selector="#app" ComponentType="{x:Type local:Login}" /> | ||
</blazor:BlazorWebView.RootComponents> | ||
</blazor:BlazorWebView> | ||
</Grid> | ||
</Window> |
15 changes: 15 additions & 0 deletions
15
samples/Sorgan/Sorgan.BlazorHybrid.Client/MainWindow.xaml.cs
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
using System; | ||
using System.Windows; | ||
using Dapplo.Microsoft.Extensions.Hosting.Wpf; | ||
|
||
namespace Sorgan.BlazorHybrid.Client; | ||
|
||
public partial class MainWindow : Window, IWpfShell | ||
{ | ||
public MainWindow(IServiceProvider provider) | ||
{ | ||
InitializeComponent(); | ||
|
||
Resources.Add("services", provider); | ||
} | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
using System.IO; | ||
using System.Windows; | ||
using Dapplo.Microsoft.Extensions.Hosting.Wpf; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using Sorgan.BlazorHybrid.Client; | ||
|
||
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] | ||
|
||
var host = new HostBuilder() | ||
// Note: applications for which a single instance is preferred can reference | ||
// the Dapplo.Microsoft.Extensions.Hosting.AppServices package and call this | ||
// method to automatically close extra instances based on the specified identifier: | ||
// | ||
// .ConfigureSingleInstance(options => options.MutexId = "{6FBAFC6B-528A-4CB7-A99A-B5DDF5812943}") | ||
// | ||
.ConfigureLogging(options => options.AddDebug()) | ||
.ConfigureServices(services => | ||
{ | ||
services.AddDbContext<DbContext>(options => | ||
{ | ||
options.UseSqlite($"Filename={Path.Combine(Path.GetTempPath(), "openiddict-sorgan-blazorhybrid-client.sqlite3")}"); | ||
options.UseOpenIddict(); | ||
}); | ||
|
||
services.AddOpenIddict() | ||
|
||
// Register the OpenIddict core components. | ||
.AddCore(options => | ||
{ | ||
// Configure OpenIddict to use the Entity Framework Core stores and models. | ||
// Note: call ReplaceDefaultEntities() to replace the default OpenIddict entities. | ||
options.UseEntityFrameworkCore() | ||
.UseDbContext<DbContext>(); | ||
}) | ||
|
||
// Register the OpenIddict client components. | ||
.AddClient(options => | ||
{ | ||
// Note: this sample uses the authorization code and refresh token | ||
// flows, but you can enable the other flows if necessary. | ||
options.AllowAuthorizationCodeFlow() | ||
.AllowRefreshTokenFlow(); | ||
|
||
// Register the signing and encryption credentials used to protect | ||
// sensitive data like the state tokens produced by OpenIddict. | ||
options.AddDevelopmentEncryptionCertificate() | ||
.AddDevelopmentSigningCertificate(); | ||
|
||
// Add the operating system integration. | ||
options.UseSystemIntegration(); | ||
|
||
// Register the System.Net.Http integration and use the identity of the current | ||
// assembly as a more specific user agent, which can be useful when dealing with | ||
// providers that use the user agent as a way to throttle requests (e.g Reddit). | ||
options.UseSystemNetHttp() | ||
.SetProductInformation(typeof(Program).Assembly); | ||
|
||
// Register the Web providers integrations. | ||
// | ||
// Note: to mitigate mix-up attacks, it's recommended to use a unique redirection endpoint | ||
// address per provider, unless all the registered providers support returning an "iss" | ||
// parameter containing their URL as part of authorization responses. For more information, | ||
// see https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.4. | ||
options.UseWebProviders() | ||
.AddGitHub(options => | ||
{ | ||
options.SetClientId("2388b26eab831adab80d") | ||
// Note: GitHub doesn't allow creating public clients and requires using a client secret. | ||
.SetClientSecret("5115eeb4c840aeaaa19f7be7ea8b13b992dca765") | ||
// Note: GitHub doesn't support the recommended ":/" syntax and requires using "://", but allows | ||
// using a dynamic/random port that will be dynamically chosen by the OpenIddict system integration. | ||
.SetRedirectUri("http://localhost/callback/login/github"); | ||
}); | ||
}); | ||
|
||
// Register the worker responsible for creating the database used to store tokens | ||
// and adding the registry entries required to register the custom URI scheme. | ||
// | ||
// Note: in a real world application, this step should be part of a setup script. | ||
services.AddHostedService<Worker>(); | ||
|
||
services.AddWpfBlazorWebView(); | ||
}) | ||
.ConfigureWpf(options => | ||
{ | ||
options.UseApplication<App>(); | ||
options.UseWindow<MainWindow>(); | ||
}) | ||
.UseWpfLifetime() | ||
.Build(); | ||
|
||
await host.RunAsync(); |
23 changes: 23 additions & 0 deletions
23
samples/Sorgan/Sorgan.BlazorHybrid.Client/Sorgan.BlazorHybrid.Client.csproj
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Razor"> | ||
|
||
<PropertyGroup> | ||
<OutputType>WinExe</OutputType> | ||
<TargetFramework>net8.0-windows</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
<UseWPF>true</UseWPF> | ||
<RootNamespace>Sorgan.BlazorHybrid.Client</RootNamespace> | ||
<EnableDefaultApplicationDefinition>false</EnableDefaultApplicationDefinition> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Dapplo.Microsoft.Extensions.Hosting.Wpf" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Components.WebView.Wpf" /> | ||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" /> | ||
<PackageReference Include="Microsoft.Extensions.Hosting" /> | ||
<PackageReference Include="OpenIddict.Client.SystemIntegration" /> | ||
<PackageReference Include="OpenIddict.Client.SystemNetHttp" /> | ||
<PackageReference Include="OpenIddict.Client.WebIntegration" /> | ||
<PackageReference Include="OpenIddict.EntityFrameworkCore" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.EntityFrameworkCore; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
|
||
namespace Sorgan.BlazorHybrid.Client; | ||
|
||
public class Worker : IHostedService | ||
{ | ||
private readonly IServiceProvider _provider; | ||
|
||
public Worker(IServiceProvider provider) | ||
=> _provider = provider; | ||
|
||
public async Task StartAsync(CancellationToken cancellationToken) | ||
{ | ||
using var scope = _provider.CreateScope(); | ||
|
||
var context = scope.ServiceProvider.GetRequiredService<DbContext>(); | ||
await context.Database.EnsureCreatedAsync(cancellationToken); | ||
} | ||
|
||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; | ||
} |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
@using Microsoft.AspNetCore.Components.Web |
25 changes: 25 additions & 0 deletions
25
samples/Sorgan/Sorgan.BlazorHybrid.Client/wwwroot/Index.html
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
|
||
<head> | ||
<meta charset="utf-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>OpenIddict Sorgan Blazor Hybrid client</title> | ||
<base href="/" /> | ||
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /> | ||
<link href="css/app.css" rel="stylesheet" /> | ||
<link href="Sorgan.BlazorHybrid.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="_framework/blazor.webview.js"></script> | ||
</body> | ||
|
||
</html> |
48 changes: 48 additions & 0 deletions
48
samples/Sorgan/Sorgan.BlazorHybrid.Client/wwwroot/css/app.css
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
html, body { | ||
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | ||
} | ||
|
||
h1:focus { | ||
outline: none; | ||
} | ||
|
||
a, .btn-link { | ||
color: #0071c1; | ||
} | ||
|
||
.btn-primary { | ||
color: #fff; | ||
background-color: #1b6ec2; | ||
border-color: #1861ac; | ||
} | ||
|
||
.valid.modified:not([type=checkbox]) { | ||
outline: 1px solid #26b050; | ||
} | ||
|
||
.invalid { | ||
outline: 1px solid red; | ||
} | ||
|
||
.validation-message { | ||
color: red; | ||
} | ||
|
||
#blazor-error-ui { | ||
background: lightyellow; | ||
bottom: 0; | ||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); | ||
display: none; | ||
left: 0; | ||
padding: 0.6rem 1.25rem 0.7rem 1.25rem; | ||
position: fixed; | ||
width: 100%; | ||
z-index: 1000; | ||
} | ||
|
||
#blazor-error-ui .dismiss { | ||
cursor: pointer; | ||
position: absolute; | ||
right: 0.75rem; | ||
top: 0.5rem; | ||
} |
Oops, something went wrong.