Identitity4和OidcClient的授权代码流

时间:2019-12-13 13:41:24

标签: identityserver4 identitymodel oidc-client

对于Winforms Desktop应用程序,我将在PKCE中使用授权代码流。作为身份提供者,我使用IdentityServer并作为客户端库OicdClient。 下一步,我必须确定要用于用户登录的浏览器:

对于SystemBrowser来说,该流程是简单/清晰的实现。 对于扩展WebBrowser来说,某些用户可能没有SystemBrowser。但是WebBrowser是较旧的IE版本吗?并允许用于安全身份验证吗?

尽管如此,我还是尝试了“扩展的WebBrowser”示例,并尝试将其与自己的IS4服务器集成到我的原型环境中。因此,我需要对代码流和重定向有所了解。 我已经使用纯.Net类实现了此授权代码流,但是使用OicdClient会使我有点困惑(一开始就像黑盒子一样)。

我的问题是重定向如何与此库一起工作,谁负责重定向,谁负责接收代码重定向(以交换访问令牌)?

代码流具有以下步骤(没有诸如clientID,PKCE ...之类的详细信息):

  1. 向IS4发送代码请求
  2. 带有登录页面的IS4响应(显示在浏览中)
  3. 成功登录后,IS4发送带有代码的重定向URL
  4. 一个HttpListener收到带有代码的重定向,并且
  5. 使用代码向IS4发送请求以获取访问令牌

使用OidcClient并使用Automatic Mode:

var options = new OidcClientOptions
{
    Authority = "https://demo.identityserver.io",
    ClientId = "native",
    RedirectUri = redirectUri,
    Scope = "openid profile api",
    Browser = new SystemBrowser()
};

var client = new OidcClient(options);
var result = await client.LoginAsync();

这对我来说是不可思议的。只有对LoginAsync()的调用才能使它起作用...

重要的一点似乎是带有IBrowser接口的选项的Browser属性及其此方法的实现:

    public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken)
    {
            using (var listener = new LoopbackHttpListener(Port, _path))
            {
                OpenBrowser(options.StartUrl);
                try
                {
                    var result = await listener.WaitForCallbackAsync();
                    if (String.IsNullOrWhiteSpace(result))
                    {
                        return new BrowserResult { ResultType = BrowserResultType.UnknownError, Error = "Empty response." };
                    }
                    return new BrowserResult { Response = result, ResultType = BrowserResultType.Success };
                }
                catch (TaskCanceledException ex)
                { ....}
            }
        }

如果我尝试映射到流程步骤:

  1. 登录页面:OpenBrowser(options.StartUrl);
  2. 重定向将由IS4完成吗?示例中的SystemBrowser不会执行此操作。
  3. 接收代码:等待listener.WaitForCallbackAsync();

1和5可能是由OicdClient完成的。该示例相当清楚,需要确认重定向是由IS4完成的。

另一个示例Extended WebBrowser

中的实现
public async Task<BrowserResult> InvokeAsync(BrowserOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            using (var form = _formFactory.Invoke())
            using (var browser = new ExtendedWebBrowser()
            {
                Dock = DockStyle.Fill
            })
            {
                var signal = new SemaphoreSlim(0, 1);

                var result = new BrowserResult
                {
                    ResultType = BrowserResultType.UserCancel
                };

                form.FormClosed += (o, e) =>
                {
                    signal.Release();
                };

                browser.NavigateError += (o, e) =>
                {
                    e.Cancel = true;

                    if (e.Url.StartsWith(options.EndUrl))
                    {
                        result.ResultType = BrowserResultType.Success;
                        result.Response = e.Url;
                    }
                    else
                    {
                        result.ResultType = BrowserResultType.HttpError;
                        result.Error = e.StatusCode.ToString();
                    }

                    signal.Release();
                };

                browser.BeforeNavigate2 += (o, e) =>
                {
                    var b = e.Url.StartsWith(options.EndUrl);
                    if (b)
                    {
                        e.Cancel = true;
                        result.ResultType = BrowserResultType.Success;

                        result.Response = e.Url;

                        signal.Release();
                    }
                };

                form.Controls.Add(browser);
                browser.Show();

                System.Threading.Timer timer = null;

                form.Show();
                browser.Navigate(options.StartUrl);

                await signal.WaitAsync();
                if (timer != null) timer.Change(Timeout.Infinite, Timeout.Infinite);

                form.Hide();
                browser.Hide();

                return result;
            }
        }
  1. 完成者:browser.Navigate(options.StartUrl);
  2. 通过IS4重定向
  3. 在事件句柄中接收代码:NavigateError ???

这有什么问题吗? 在IS4上,AccountController.Login被调用 调用/连接/授权/回调?与redirect_uri。 但是,BeforeNavigate2并没有做到这一点。相反,出现NavigateError事件,结果设置为:

result.ResultType = BrowserResultType.Success;
result.Response = e.Url; 

1 个答案:

答案 0 :(得分:1)

当前的最佳实践是使用用户的默认Web浏览器,而不是嵌入浏览器组件。至于如何实现-由于无法使用这种方法拦截浏览器导航事件,因此您需要实现一个HTTP侦听器,该侦听器可以接受来自identityserver4实现的POST请求。

已阅读以下内容:https://auth0.com/blog/oauth-2-best-practices-for-native-apps/

此RFC:https://tools.ietf.org/html/rfc8252