我正在尝试使用Ruby on Rails构建Web服务.用户通过HTTP Basic Auth进行身份验证.我想在用户名和密码中允许任何有效的UTF-8字符.
问题是浏览器在将它们发送到我的服务之前在基本身份验证凭据中修改了字符.为了测试,我使用'カタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナカタカナ'作为我的用户名(不知道它意味着什么 - AFAIK它是我们的QA家伙想出的一些随机字符 - 请原谅我,如果它有点冒犯).
如果我把它看作一个字符串,并做username.unpack("H*")将其转换为十六进制,我得到:"3e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a83e28ba3e28fb3e28ba3e38a8"这似乎是对适合32个汉字字符(3个字节元/ 6个十六进制数字).
如果我使用通过HTTP Basic auth进入的用户名执行相同的操作,我会得到:'bafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaacbafbbaac'.它显然要短得多.使用Firefox Live HTTP Headers插件,这是发送的实际标头:
Authorization: Basic q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o6q7+ryqu/q8qrv6vKq7+ryqu/q8qrv6vKq7+ryqu/q8o=
看起来像'bafbba ...'字符串,高低字节交换(至少当我将其粘贴到Emacs中时,基本64解码,然后切换到hexl模式).这可能是用户名的UTF16表示,但我没有任何东西可以将其显示为除了胡言乱语之外的任何东西.
Rails将内容类型标头设置为UTF-8,因此浏览器应该以该编码发送.我获得了表单提交的正确数据.
问题出现在Firefox 3.0.8和IE 7中.
那么......是否有一些神奇的功能让网络浏览器通过HTTP Basic Auth发送UTF-8字符?我在接收端处理错误了吗?HTTP Basic Auth是否不适用于非ASCII字符?
我想在用户名和密码中允许任何有效的UTF-8字符.
放弃所有的希望.基本身份验证和Unicode不混合.
如何将非ASCII字符编码为基本认证用户名:base64ing之前的密码令牌没有标准(*).因此,每个浏览器都会做出不同
Opera使用UTF-8;
IE使用系统的默认代码页(除了它永远不会是UTF-8之外你无法知道),并且使用Windows猜测一个看起来有点像的随机字符,默默地修改不符合它的字符.一个你想要的或者可能不是'秘方;
Mozilla只使用字符代码点的低字节,它具有编码到ISO-8859-1的效果,并且无法挽回地破坏非8859-1字符... 除了在执行XMLHttpRequests时,在这种情况下它使用UTF-8;
Safari和Chrome编码为ISO-8859-1,并且在使用非8859-1字符时根本无法发送授权标头.
*:有些人解释标准说:
它应该始终是ISO-8859-1,因为它是包含直接包含在头文件中的原始8位字符的默认编码;
它应该以某种方式使用RFC2047规则进行编码.
但是这些提议都没有包含在base64编码的auth令牌中,并且HTTP规范中的RFC2047引用实际上根本不起作用,因为'原子上下文明确禁止它可能使用的所有地方"RFC2047本身的规则,即使HTTP标头尊重RFC822系列的规则和扩展,它们也没有.
总结:呃.除了Opera以外,在标准或浏览器中修复这一点几乎没有希望.这只是推动人们远离HTTP基本身份验证的另一个因素,有利于非标准和不易访问的基于cookie的身份验证方案.真惭愧.
这是一个众所周知的缺点,即基本身份验证不支持非ISO-8859-1字符.
已知一些UAs使用UTF-8(Opera会想到),但也没有互操作性.
据我所知,除了定义处理所有Unicode的新身份验证方案之外,没有办法解决这个问题.并部署它.