目录:
- OpenID 与 OAuth2 基础知识
- Blazor wasm Google 登录
- Blazor wasm Gitee 码云登录
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例2-登录信息组件wasm
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例3-服务端管理组件
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例4 - 部署服务端/独立WASM端授权
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例5 - Blazor hybird app 端授权
- Blazor SSR/WASM IDS/OIDC 单点登录授权实例5 - Winform 端授权
源码
建立winform项目
安装包 IdentityModel.OidcClient 以及 Microsoft.Web.WebView2 , 项目使用x64运行
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="IdentityModel.OidcClient" Version="5.2.1" />
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.2210.55" />
</ItemGroup>
</Project>
拖放一个TextBox控件
Form1.cs 代码
using IdentityModel.OidcClient;
using System.Text;
using WinFormsWebView2;
namespace WinFormsOIDC;
public partial class Form1 : Form
{
static string authority = "https://localhost:5001/";
//static string authority = "https://ids2.app1.es/"; //真实环境
static string api = $"{authority}WeatherForecast";
static string clientId = "Blazor5002";
OidcClient _oidcClient;
public Form1()
{
InitializeComponent();
string redirectUri = string.Format($"http://localhost/authentication/login-callback");
string redirectLogoutUri = string.Format($"http://localhost/authentication/logout-callback");
var options = new OidcClientOptions
{
Authority = authority,
ClientId = clientId,
RedirectUri = redirectUri,
PostLogoutRedirectUri = redirectLogoutUri,
Scope = "BlazorWasmIdentity.ServerAPI openid profile",
Browser = new WinFormsWebView()
};
_oidcClient = new OidcClient(options);
Login();
}
private async void Login()
{
LoginResult loginResult;
try
{
loginResult = await _oidcClient.LoginAsync();
}
catch (Exception exception)
{
Output.Text = $"Unexpected Error: {exception.Message}";
return;
}
if (loginResult.IsError)
{
MessageBox.Show(this, loginResult.Error, "Login", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
var sb = new StringBuilder(128);
foreach (var claim in loginResult.User.Claims)
{
sb.AppendLine($"{claim.Type}: {claim.Value}");
}
if (!string.IsNullOrWhiteSpace(loginResult.RefreshToken))
{
sb.AppendLine();
sb.AppendLine($"refresh token: {loginResult.RefreshToken}");
}
if (!string.IsNullOrWhiteSpace(loginResult.IdentityToken))
{
sb.AppendLine();
sb.AppendLine($"identity token: {loginResult.IdentityToken}");
}
if (!string.IsNullOrWhiteSpace(loginResult.AccessToken))
{
sb.AppendLine();
sb.AppendLine($"access token: {loginResult.AccessToken}");
}
Output.Text = sb.ToString();
}
}
}
添加一个类 WinFormsWebView.cs
代码
using IdentityModel.OidcClient.Browser;
using Microsoft.Web.WebView2.WinForms;
namespace WinFormsWebView2;
public class WinFormsWebView : IBrowser
{
private readonly Func<Form> _formFactory;
private BrowserOptions? _options;
public WinFormsWebView(Func<Form> formFactory)
{
_formFactory = formFactory;
}
public WinFormsWebView(string title = "Authenticating ...", int width = 1024, int height = 768)
: this(() => new Form
{
Name = "WebAuthentication",
Text = title,
Width = width,
Height = height
})
{ }
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken token = default)
{
_options = options;
using (var form = _formFactory.Invoke())
{
using (var webView = new WebView2()
{
Dock = DockStyle.Fill
})
{
var signal = new SemaphoreSlim(0, 1);
var browserResult = new BrowserResult
{
ResultType = BrowserResultType.UserCancel
};
form.FormClosed += (o, e) =>
{
signal.Release();
};
webView.NavigationStarting += (s, e) =>
{
if (IsBrowserNavigatingToRedirectUri(new Uri(e.Uri)))
{
e.Cancel = true;
browserResult = new BrowserResult()
{
ResultType = BrowserResultType.Success,
Response = new Uri(e.Uri).AbsoluteUri
};
signal.Release();
form.Close();
}
};
try
{
form.Controls.Add(webView);
webView.Show();
form.Show();
// Initialization
await webView.EnsureCoreWebView2Async(null);
// 删除现有的 Cookie,这样以前的登录就不会被记住, 以免影响测试, 反之去掉这行,就可以保持登录
//webView.CoreWebView2.CookieManager.DeleteAllCookies();
// Navigate
webView.CoreWebView2.Navigate(_options.StartUrl);
await signal.WaitAsync();
}
finally
{
form.Hide();
webView.Hide();
}
return browserResult;
}
}
}
private bool IsBrowserNavigatingToRedirectUri(Uri uri)
{
return uri.AbsoluteUri.StartsWith(_options?.EndUrl);
}
}