ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Windows Hello登录集成指南:从UserConsentVerifier到踩坑排查

Windows Hello登录集成指南:从UserConsentVerifier到踩坑排查 平时被问得最多的一个功能需求大概就是给我们的工具加个Windows Hello登录。之前一个老同事来找我说他们内网的小工具每次打开都要输一遍账号密码非常烦想做成Windows Hello刷脸或PIN验证双击打开验证一下直接进。我本来以为这是一个简单调用结果前后折腾了大半天不光是写代码的事还撞上了网上频繁出现的安装程序输入密码后什么也不显示、抱歉出现问题、使用administrator登录Windows Hello这几个典型坑。这篇文章就把我这个简单示例从原理到代码再到问题排查的完整过程写一遍希望对同样在船上的人有帮助。1. 为什么要把应用登录从密码换成Windows Hello1.1 Windows Hello不是人脸识别那么简单Windows Hello这个名字看起来像是一个摄像头人脸识别开关实际它是一整套本地身份验证体系支持PIN、人脸、指纹和虹膜。很多人以为它只是把密码换成了生物特征这个理解不够准确。密码的核心问题在于它是一串可传输的密钥服务器要存密码的哈希客户端要把密码送出去验证整个过程存在被拦截、被撞库、被社工的风险。Windows Hello的逻辑完全不同它把验证变成了证明你有一把放在本机的私钥。设备上通过TPM或者受支持的硬件生成一对公私钥私钥保存在本机安全硬件里公钥可以注册到应用或服务端。你要登录的时候系统用PIN或生物特征解锁私钥然后对随机挑战进行签名服务端用公钥验签。整个过程没有密码在网络上传送服务器也不需要存储可逆的密码信息。1.2 核心价值不用存密码本地私钥说了算这个设计的价值我拿生活场景打个比方以前你进小区大门物业那里存了你家钥匙的复印件拿复印件配一把就能开门现在物业不存钥匙只登记了你家锁具的特征。你回家的时候锁具现场证明我就是这把锁的主人物业只需要验证你的证明是否有效。Windows Hello就是这种思路。数据由用户自己掌握攻击者就算拿到应用服务器上的用户表也拿不到和Windows Hello私钥相关的任何敏感信息因为他没有用户手里的那台设备。这个思路给应用开发带来的直接影响是你可以不再设计用户名密码的登录表单不必担心密码策略合规也不必在自己的数据库里维护一堆密码哈希。尤其是内网工具如果认证服务器不在手边或者根本不想为一个小工具专门搭一套账号系统Windows Hello这种系统自带的本机登录确认就成了很划算的替代。1.3 我的场景一个需要登录的内网小工具回到我那个需求。老同事他们的工具是C#写的桌面程序平时安装好之后第一次打开要输入内网LDAP账号密码连接认证服务器验证通过之后才能加载主界面。这个流程有两个痛点一是每次打开都要输密码尤其一天要切换多个工具窗口的时候很烦二是密码会残留在内存和日志里安全审计不好看。他们的诉求很简单只要当前Windows账户已经完成了Windows Hello设置PIN或人脸、指纹都行应用打开时就弹一个Windows Hello验证框验证通过视为登录成功不再向认证服务器发密码。这个场景非常适合直接调用系统提供的UserConsentVerifier API因为这里不需要真正注册密钥到企业内部服务器只需要本机用户验证。如果要做真正的企业级无密码登录那需要Windows Hello for Business走证书或密钥注册流程那是另一套体系后面我会提一嘴边界但这个简单示例就先不展开。2. 一个最简单的示例用UserConsentVerifier调用Windows Hello2.1 环境准备UWP、WinUI还是传统桌面这里第一个选择是项目类型。很多教程一上来就引导你创建UWP项目这没问题但现实里大量内部工具都是WPF或者WinForms写的不可能为了加一个登录功能就重写整个界面。好消息是从.NET Core 3.x开始传统桌面应用也可以直接调用Windows Runtime API关键是正确设置目标框架。我在WPF项目中做了如下配置TargetFrameworknet8.0-windows10.0.19041.0/TargetFramework UseWPFtrue/UseWPF注意后面的windows10.0.19041.0是Windows SDK版本号19041对应Windows 10 2004。这样项目就会自动引用Windows SDK中的WinRT API不需要额外安装UWP模板也不需要把程序打包成MSIX。如果需要更完整的Windows App SDK支持也可以换成net8.0-windows10.0.19041.0加上Microsoft.WindowsAppSDK包但就本例而言不需要。配置好之后在代码里直接引用using Windows.Security.Credentials.UI;就能访问UserConsentVerifier类。这个类所在的命名空间属于Windows SDK你不需要额外引入第三方库在NuGet里也不用额外加包前提是你用的.NET版本和我一样是6以上且TargetFramework带windows后缀。2.2 核心代码验证用户身份下面是完整的验证逻辑放在一个独立的服务类里using System; using System.Threading.Tasks; using Windows.Security.Credentials.UI; public class WindowsHelloService { public async Taskbool VerifyAsync(string prompt) { var availability await UserConsentVerifier.CheckAvailabilityAsync(); if (availability ! UserConsentVerifierAvailability.Available) { Console.WriteLine($Windows Hello 不可用: {availability}); return false; } var result await UserConsentVerifier.RequestVerificationAsync(prompt); return result UserConsentVerifierVerificationResult.Verified; } }CheckAvailabilityAsync这一步是关键。别看它简单很多人在这一步省掉第一次直接调用RequestVerificationAsync结果在没有设置PIN的机器上直接得到一个错误提示体验很糟糕。先检查可用性根据不同的返回值做不同的引导这是正规做法。返回值有几种情况返回值含义建议处理AvailableWindows Hello可用正常调用验证DeviceNotPresent当前设备没有支持Windows Hello的硬件提示用户该设备不支持NotConfiguredForUser用户尚未设置PIN/人脸引导用户去设置打开Windows Hello设置页DisabledByPolicy被组策略或企业策略禁用提示联系管理员RequestVerificationAsync弹出系统验证界面用户可以选择输入PIN、刷脸或者按指纹。验证过程由系统接管应用拿不到PIN或生物数据只收到一个结果枚举。这一点对安全非常关键你的应用不碰任何敏感凭据也就没有泄露面。在界面上调用时这样写private async void LoginButton_Click(object sender, RoutedEventArgs e) { var service new WindowsHelloService(); bool ok await service.VerifyAsync(请验证你的身份以登录WinTool); if (ok) { MessageBox.Show(验证成功欢迎回来); } else { MessageBox.Show(验证失败); } }注意这里的else不代表一定是用户放弃了也可能是系统暂时不可用。真实场景下不要只显示验证失败这四个字最好把具体原因也展示出来这一部分我在第5节会专门讲。2.3 注册和删除Windows Hello凭据有朋友会问用户没设置过Windows Hello应用能不能直接引导他注册这里有个边界要讲清楚。Windows Hello的注册入口在系统设置里在Windows 10和11上是设置 账户 登录选项 PIN或人脸应用不能静默替用户注册也不能直接读取用户的生物数据。应用能做的只有两件事一是查可用性和状态二是请求验证。如果你需要应用引导用户去设置可以调用系统设置URISystem.Diagnostics.Process.Start(new ProcessStartInfo { FileName ms-settings:signinoptions, UseShellExecute true });这句代码会直接打开登录选项设置页用户可以自己去设置PIN或人脸。这是目前比较合规、也比较不容易踩坑的引导方式。在调用UserConsentVerifier之前把设置页打开用户设置完PIN回来再点一次登录按钮基本就能顺利走通。2.4 为什么选UserConsentVerifier而不是KeyCredentialManager写Windows Hello相关功能时一定会看到两个API一个是UserConsentVerifier另一个是KeyCredentialManager。我在这篇示例里选前者原因很简单UserConsentVerifier是一个快速验证API它的作用是让用户证明自己的身份适合本地应用解锁、确认交易、登录等场景实现成本低代码几乎可以只用上面那几行。KeyCredentialManager则偏向于创建和管理密钥凭据适合应用想要拥有一对绑定当前用户和当前设备的密钥并把公钥注册到自己服务器上做签名验证的场景。如果你的目标是真正的无密码登录服务端需要验签那应该去看KeyCredentialManager和Windows Hello for Business而不是这个简单示例。3. 安装程序输入密码后什么也不显示我踩过的坑和完整排查链路3.1 问题复现我在测试机上部署这个工具时遇到了一个和代码本身无关的鬼问题。双击安装包系统弹出UAC窗口输入管理员密码点击是之后UAC窗口消失安装界面始终不出现屏幕上就像什么都没发生过。这个现象在网上一搜就是windows hello 安装程序输入密码后什么也不显示很多用户指着这个骂Windows Hello。我当时的反应也是先怀疑是不是Hello相关驱动把系统搞出毛病了后来冷静下来排查发现根本不是一回事。首先说结论这个问题的根源绝大多数不是Windows Hello本身而是UAC提权后安装程序的主进程没有正常启动。它和Windows Hello产生关联是因为很多新电脑在登录界面会提示你设置PIN如果你没设置系统在某些情况下会让一些依赖Hello组件的安装流程卡住。所以排查时我们要把Windows Hello的系统配置情况和安装包本身的问题分开处理。3.2 排查链路第一步确认Windows Hello是否已设置既然是Windows Hello相关的话题第一步先把Hello的状态摸清楚。打开设置 账户 登录选项看看PIN、人脸、指纹是否有设置。如果一切正常这一步通常看不到问题但没有设置PIN的机器上很多和安全相关的组件会处于一种未初始化状态可能导致后续安装程序里的某个组件出现异常。如果发现没有设置PIN可以先设置一个PIN再重跑安装包。很多时候问题就这么简单消失了因为安装程序可能在尝试初始化Windows Hello相关的组件比如需要用Hello完成设备加密或凭据写入结果系统里完全没配置于是它就没继续。这里有个非常容易踩的细节在登录选项页面里即使你看见人脸和指纹下面写着此选项当前不可用也不要急着下结论说硬件不支持。你需要先设置好PIN人脸和指纹的设置入口才会启用。Windows Hello的逻辑是PIN是基础人脸和指纹建立在PIN之上。我自己就遇到过一位同事一直以为笔记本没有IR摄像头因为他打开摄像头应用拍不到人脸实际上驱动没装好登录选项页也把整个人脸区域灰掉了。3.3 排查链路第二步检查组策略是否禁用了PIN或生物识别如果设置好了PIN还是老样子那就检查策略。按WinR输入gpedit.msc进入本地组策略编辑器在计算机配置 管理模板 Windows组件 Windows Hello for Business下重点看使用Windows Hello for Business和配置取消PIN登录这两条。如果策略被设成已禁用那么即使设置页显示可以设置PIN实际调用时也会失败。企业域环境中这个更明显管理员通过策略统一关闭了非域账户的Hello功能。当时我排查到这一步才想起来测试机之前加过域域策略里确实有关闭Hello的条目虽然那台机器后来退了域本地策略模板里的痕迹还在导致行为很诡异。解决办法倒不复杂在组策略编辑器里把相关项改为未配置然后命令行执行gpupdate /force强制刷新策略再重启一次系统。如果是域环境里的机器建议直接联系管理员因为本地的修改很可能被下一次组策略刷新覆盖。3.4 排查链路第三步账户类型与登录选项冲突接下来检查当前登录账户类型。Windows有一个让人抓狂的限制内置Administrator账户也就是名字就叫Administrator的那个管理员账户不能使用Windows Hello。很多人在装大型软件时临时启用了内置Administrator来安装输入密码后UAC通过了安装程序却没反应。这是因为某些安装程序会在UAC之后尝试使用Windows Hello API来处理后续的凭据比如检查当前账户是否支持Hello来做动态账号状态更新遇到内置Administrator就直接失败了安装程序又没有正确处理这个失败于是界面直接被吞掉。遇到这种情况最好的做法是换一个普通的本地管理员账户来安装不要用内置Administrator。具体的账户创建方法在第4节会给出因为我自己就是一开始图省事用内置Administrator测试结果白折腾一个多小时换账户之后五分钟内所有问题都消失了。3.5 排查链路第四步驱动与摄像头问题最后一类常见出问题的地方是硬件驱动。人脸识别依赖IR摄像头指纹需要指纹模块。很多笔记本有IR摄像头但有独立的摄像头开关或隐私挡板驱动没装好时Windows Hello在人脸设置里会直接提示找不到摄像头。指纹模块有些老设备在Windows 10升级到Windows 11后驱动不兼容状态异常。这些都会让应用调用Windows Hello时出现什么也不显示的假象。解决办法是去设备管理器里看生物识别设备和照相机下有没有黄色感叹号有的话更新驱动同时在设置里测试设置Windows Hello来确认系统本身的Hello功能是否正常。系统层面能正常设置和登录但你的应用调用时不行那问题才在你自己代码里否则先解决系统层。这也是我建议所有人做Hello开发时先做一个系统排查清单的原因省得到最后怀疑自己的代码逻辑有问题其实系统层就是坏的。4. 抱歉出现问题错误与管理员账户的限制4.1 用Administrator登录时为什么Windows Hello不可用抱歉出现问题这个对话框我在调试时见到了不止一次。最典型的一次是我用内置Administrator账户登录系统然后运行我的验证按钮点下去之后弹出的就是这个错误。为什么内置Administrator不行原因是Windows Hello需要把用户凭据和用户的配置文件生成绑定关系而内置Administrator是一个特殊的账户它默认禁用、没有关联的Microsoft账户或域账户体系系统出于安全考虑不允许对这个账户建立Hello凭据。从设计上微软是希望所有操作都在普通账户下进行Administrator只做紧急恢复和高级维护。你要验证这一点很简单切到普通管理员账户去设置里设置PIN一切正常切回内置Administrator仍然提示不能设置。这不是故障是设计如此。很多教程里提到的启用内置Administrator的做法在Windows 10 1803之后已经是半个坑了因为新版本对这个账户的限制越来越多很多现代应用的安全功能都会绕过它。4.2 如何正确绕过这个限制创建一个标准管理员账户如果你确实需要在一个支持Windows Hello的环境里做开发和测试不要想方设法去破解内置Administrator的限制而是创建一个新的本地管理员账户。操作步骤设置 账户 家庭和其他用户 将其他人添加到这台电脑选择我没有这个人的登录信息 添加一个没有Microsoft帐户的用户输入本地账户名和密码创建完成后把这个账户改成管理员开始菜单搜索计算机管理在本地用户和组里把新账户加入Administrators组注销切到新账户登录再设置PIN完成Windows Hello注册这套流程做完新账户可以正常调用Windows Hello内置Administrator继续留着应急两边互不影响。我建议所有做Windows Hello开发的人都建这样一个专用测试账户不要在Administrator下面碰运气。这个做法也能解释为什么网上搜使用administrator 登陆windows hello时回答几乎都是请使用其他账户因为它就是一个受保护的系统内置账户。4.3 0x80070490及其他怪异的系统级因素排查抱歉出现问题时如果事件查看器里看到一条无法识别的错误还需要检查几个系统底层因素。一个常见的是系统时间严重偏离导致TPM签名验证的随机挑战对不上。另一个常见的是TPM本身被禁用或者在BIOS中被关闭。检查方法WinR输入tpm.msc看TPM状态是否为已准备就绪可以使用。如果显示不支持TPM或找不到TPM那Windows Hello的人脸和PIN功能都会出问题。另外Windows 11的某些批量镜像为了跳过硬件检查被修改过TPM相关组件也会出现这类错误。这些系统级问题排查起来很繁琐但我给你的建议是先把CheckAvailabilityAsync的返回值打印出来。它返回的枚举往往比用户界面上的错误提示更接近根因。比如返回SecurityStatusNotSupported时基本可以断定是TPM或安全设备状态异常而不是代码问题。如果你用RequestVerificationAsync直接打系统可能只弹一个模糊的抱歉出现问题窗口根因全藏在事件查看器的日志里门槛一下子高了很多。5. 把示例变成真正可用的登录功能还需要补哪些课5.1 验证结果与安全级别不能只看真/假上面那个简单的bool返回在示例里能跑但真实应用里不能这么草率。一个严谨的登录模块需要处理多种结果至少包括结果处理动作Verified进入主界面CanceledByUser无关登录不刷新状态NotConfiguredForUser引导去系统设置设置PINDeviceNotPresent降级到传统密码登录DisabledByPolicy显示管理员联系方式尤其是在企业内网工具里NotConfiguredForUser是最常见的因为很多同事没有单独给自己的电脑设过PIN。你不能直接在错误提示里抛一堆枚举而是要给出一个友好的指引。我的做法是检测到未配置时在界面上写一段话系统未检测到Windows Hello凭据点击这里去设置点击后打开ms-settings:signinoptions页面并预留一个使用密码登录的替代选项。这样用户不至于卡死在一个新功能上。5.2 错误处理与用户引导实测有效的四个注意点第一每次调用验证前都做CheckAvailabilityAsync不要缓存结果。有些笔记本在电源状态下会动态切换摄像头驱动还有外接显示器带IR摄像头的情况可用性很可能在运行中变化不值得为了省一次调用去冒这个风险。第二验证框弹出后你的应用主窗口不要直接失焦。有些应用在弹出Hello验证时忘记处理Deactivate事件导致验证框弹出后主窗口被系统收编用户看着像什么也不显示。如果你的界面在主窗口失去激活时自动隐藏一定要在调用RequestVerificationAsync期间禁用这个行为。这个坑我在调试WPF程序时踩过一次当时验证窗口一直没弹出来我还以为是API调用有问题后来才发现是自定义窗口在Deactivated事件里把自己隐藏了。第三对于连续多次失败的场景不要无缝重试否则用户很容易被Windows的防暴力破解策略锁住接下来连PIN都暂时失效了。我做过一次实测连续错误三次以后系统提示要等一会儿后来在带TPM的设备上还会触发更长的冷却时间。因此你的登录按钮在连续失败两次后最好进入10秒钟的禁用状态算是给系统一点保护也降低用户的焦虑。第四验证成功以后要主动清理内存里的登录状态。Windows Hello验证通过获得的只是一个本次验证成功的事实不要把这个事实当作从不失效的token存起来。如果应用需要后续多个操作都经过身份确认建议每次操作前都重新请求一次验证或者结合应用自己的会话超时机制。比如你的工具打开5分钟后没有操作可以让它自动锁屏下一次操作时再调用一次Windows Hello验证。这样比单纯依赖操作系统的锁屏策略更贴近应用自身的业务安全边界。5.3 从桌面小工具延伸到大环境Windows Hello for Business最后提一嘴进阶方向。如果你所在的团队有Azure AD或者本地域的完整基础架构可以考虑直接部署Windows Hello for BusinessWHFB把Hello凭据提升为企业级无密码登录方案。那时候就不是在应用里调用UserConsentVerifier了而是由系统和域控制器协商证书或密钥应用通过服务端的密钥签名验证来完成登录。好处是用户体验一致且支持从设备登录到应用登录的整个链路。代价是需要规划证书模板、域控制器的证书注册策略、设备条件访问等等适合运维能力比较完整的团队去做。对于大多数内部工具还是先把我上面这个简单示例跑通把用户引导和错误处理做好这样实际产生的收益已经远超输入密码的老路子。我自己的体会是Windows Hello这个功能门槛不在调用API而在处理它是你电脑上的一部分这件事。系统策略、驱动、账户类型、TPM状态任何一环出问题结果都一样弹不出来、报错、没反应。先花十分钟把系统层的状态排查清楚再写代码你会少掉很多头发。
返回列表