Credential Management API是截至目前(17年3月)仍在W3C草案阶段的标准,它允许网站开发者将用户认证信息(如用户名和密码)存储在浏览器中,从而可以让用户在一个设备登录后在其他设备上被自动登录,而无需再填写认证信息。在2016年4月份Chrome发布了一个W3C Credential Management API的最初实现。

关于Credential Management API的具体使用方法,读者可以参见Google Developers官方网站。本文将针对Google Developers网站的信息作出几点补充,并假设你已经阅读过Google Developers的内容。

Q:可以提供翻译吗?
A:翻译官方文档不是一件好事情,尤其是可能过期或者变更的官方文档。翻译大多情况下会造成提供错误信息的问题。我建议大家永远直接阅读原文官方文档。

Credential Management 是什么

它允许开发者用JavaScript将用户的认证信息存储在浏览器中。浏览器通过后台将这些信息同步到其他设备上。当用户在其他设备访问时,开发者可以在需要的时候从浏览器中取出用户的认证信息,并提交给服务器从而为用户自动登录。在自动登录的过程中,用户不需要填写任何表格,甚至不需要执行任何动作。

下图是用Chrome实现跨端登录的一个例子。

图一:Chrome实现跨端登录的一个例子

用户认证信息可以是用户名密码。对于社交网站登录的用户,认证信息可以是Facebook或者Google这类的认证授权(Token)提供方。

Credential Management不是什么

  1. 它不是一种新的认证方式
  2. 它不是代替网站存储用户认证信息的地方

浏览器兼容性

具体的浏览器兼容性请参见Caniuse。在这里值得提出的是,Caniuse在我写本文时将Chrome 51到56标记为支持Credential Management API。但是实际上在Chrome 51~56中,跨子域名之间无法互相使用存储的用户认证信息。( 见我给Caniuse提交的修改

这也就是说,在57之前版本的Chrome里面,在login.example.com里面存储的认证信息是无法在www.example.com里面或者mobile.example.com获取的。

图二:Chrome 57之前版本的跨子域名问题

值得注意的是,在截至今天的标准草案中,标准并未要求浏览器支持跨子域名的认证信息共享。但既然Chrome选择在57中支持,我们可以合理认为在57之前版本中存在的是bug。也因为如此,在其他浏览器中,跨子域名认证信息共享不是被保证的。

另外,若想要在不同子域名获取用户认证信息,浏览器将强制要求弹出弹窗通知用户。即便如此,用户也只需要点击一下便可登录,而无须输入用户名密码。

我针对这个问题给此草案提出了修改建议,希望它们强制要求跨子域名共享。若你有兴趣参与讨论,请在 这个链接 中加入。

强制使用fetch API

正如你在官方文档可能阅读到的,在图一的第五步中,你必须使用fetch API来提交用户的认证信息。

Credential Management API将用户的认证信息包装在一个Credential对象中(一般是子类PasswordCredential或者FederatorCredential)。Credential对象会将敏感信息,例如用户的密码,保存成一个似有属性例如[[password]]。这种属性在JavaScript是无法直接访问的,只有浏览器本身才能访问。我相信这样做的原因是因为隐藏的跨域攻击问题。

Credential Management API通过修改fetch API的实现,让fetch API能够访问上述的私有属性,然后发送给服务器。

安全性

Credential Management API必须在HTTPS Scheme加密的URL下面执行。这是传统登录页面都会应该的功能。

另外一点安全性考虑是跨站脚本攻击(XSS)。若恶意用户对网站进行脚本注入,他可以通过重载navigator.credentials.store来获取用户的敏感信息。虽说密码等信息是私有属性,但仍有一些可以通过脚本获取的属性,例如用户名和邮箱可能被窃取。

图三:跨站脚本攻击

目前的草案标准并未要求浏览器强制禁止对Credential Management API的重载。对此我的建议是强制要求实现这个限制,请在 这里 参与讨论。

仍然需要按需使用

Credential Management API尚在草案阶段,很多浏览器尚未支持。但webkit已经开始针对Credential Management API的开发,因此有很大的希望这一功能将来能被标准化。

在实现的时候,我们其实并不应该在每个页面都尝试让用户自动登录。只应该在用户必须要登录的时候,尝试自动登录。例如在结账的时候,若用户不登录就无法扣款,此时可以在跳转到登录页面(或者弹窗)前,尝试自动登录。

若用户仅仅是在读一篇文章的时候就被自动登录,第一是没有必要的,第二是可能引起用户的疑惑(当unmediatedfalse的时候,用户会被提示将被自动登录)。

感谢阅读

这篇文章将会被根据标准的变动而不定期改动。

这篇文章被收录在我的《将PWA作为功能来开发(Building Progressive Web App as a Feature)》系列中,若你希望之后收到整个系列的最终稿,可以在文章下方订阅我的邮件专栏。