Blazor SSR/WASM IDS/OIDC 单点登录授权实例5 - Winform 端授权

目录:

  1. OpenID 与 OAuth2 基础知识
  2. Blazor wasm Google 登录
  3. Blazor wasm Gitee 码云登录
  4. Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务
  5. Blazor SSR/WASM IDS/OIDC 单点登录授权实例2-登录信息组件wasm
  6. Blazor SSR/WASM IDS/OIDC 单点登录授权实例3-服务端管理组件
  7. Blazor SSR/WASM IDS/OIDC 单点登录授权实例4 - 部署服务端/独立WASM端授权
  8. Blazor SSR/WASM IDS/OIDC 单点登录授权实例5 - Blazor hybird app 端授权
  9. Blazor SSR/WASM IDS/OIDC 单点登录授权实例5 - Winform 端授权

源码

WinFormsOIDC

建立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);
    }
}

Enjoy!