我已经为我的网页登录实现了一个标准的开箱即用的ASP.NET核心身份验证解决方案,其中用户凭据存储在云上的SQL Server数据库中。这很好,没有问题。
然而,我还有一个桌面WPF应用程序,它应该使用与Web应用程序相同的身份验证基础设施,因为它们都将由相同的用户使用,并且应该能够使用相同的凭据。因此,这个想法是,当用户试图登录到WPF桌面应用程序时,他们被重定向到浏览器中的一个简单的登录网页,输入他们的凭据,并在成功登录时接收JWT访问令牌,然后可以由桌面应用程序用于进一步的操作。
我已经在多个现代Windows桌面应用程序中看到了这样的流程(至少,我怀疑他们使用这样的流程),但是我很难理解如何将此获取的访问令牌从登录Web应用程序正确传输到我的桌面应用程序。目前我所能做的就是将用户引导到登录页面:
Process.Start(new ProcessStartInfo { FileName = @"https://www.myapplogin.com/", UseShellExecute = true });
但从这里我没有合理的想法如何让我的桌面应用程序了解登录已经成功并继续进行。
有人能在这里描述一个潜在的工作流程来完成这一点吗(最好是代码示例)?
1条答案
按热度按时间mpbci0fu1#
巧合的是,我刚刚用我的WPF应用程序完成了类似的东西。
我的解决方案是使用CEFSharp(Chromium Embedded Framework)打开一个基于Web的登录页面的窗口,然后在登录页面中包含JavaScript代码,如果是桌面应用程序登录,则通过互操作调用.NET代码来提供JWT。
下面是我所做的一步一步的分解(当然这不是唯一的方法):
WPF项目
1.在项目中包含CEFSharp for WPF。(你也可以使用WebView 2,但这更复杂的分布和某些原因是不包括默认的Windows安装)。
1.要登录用户,请打开一个包含
ChromiumWebBrowser
控件的模式窗口。将URL设置为您的Web应用程序将使用的同一登录页面。对于样式,这是我使用的(确保包括您自己的取消/关闭按钮):1.您还需要提供一个登录页面的JavaScript代码能够访问的.NET类(下面将详细介绍)。我们称之为
LoginInterop
。在某些时候(例如,当模态打开时),您需要使用以下命令注册该类的示例:_browser.JavascriptObjectRepository.Register("loginInterop", new LoginInterop());
1.在
LoginInterop
中包含一个方法,例如ProvideJwt(string jwt)
。登录页面的Javascript(在CEF中运行时)将能够调用此方法并在登录后提供JWT。(下面有更多内容)。此方法还应关闭对话框。Web项目
我建议在你的主登录页面路由中包含一个查询选项,如
desktop=true
-然后在设置ChromiumWebBrowser.Address
时在WPF端设置这个选项。您的客户端脚本将使用此信息来确定它位于CEF浏览器而不是普通的Chrome浏览器中。在这一点上,事情变得非常依赖于您的具体情况,但我假设在某个时候您的Web应用程序可以访问JWT客户端。(这意味着它不能仅仅是一个
HttpOnly
会话cookie)。如果它只使用cookie auth,则需要创建一个APIGET
端点,用于为JWT交换会话cookie(注意跨源漏洞)。一旦登录完成,并且客户端可以访问JWT --根据前面提到的查询标志,假设您在CEF内部--那么您就可以像这样调用.NET代码(仅供参考,这是Typescript;简单的JS会更简单一些):
(Note CEF camelcases方法名(当绑定时)。
另一个警告:CEFSharp for WPF
从字面上昨天我们发现,我们的一个用户有一个问题,显示CEF窗口,显然是由于他们的图形硬件和一些冲突与WPF。解决方案是添加:
在模态窗口类的某个地方。我不知道WebView 2是否有同样的问题。