我正在研究在登录表单中引入带有Latin-1字符的用户名的问题。 用户名包含字符á。 我调查了我所在的服务器部分:
公共类MyRealm扩展RealmBase实现Realm { public Principal authenticate(String username,String password){ ...这里实施的实际身份验证 } }
如果我打印出字节:username.getBytes() 我看到那个角色有:C3 83 C2 A1 通常,UTF8编码中的字符á应具有:C3 A1。 如果我再次以UTF8编码,我得到:C3 83 C2 A1,我的软件打印出来。
我在网络中检查了用C3 A1正确发送了用户名。 登录页面表单的源代码是:
<form name="loginForm" action="j_security_check" method="post" enctype="application/x-www-form-urlencoded">
<table>
<tr>
<td colspan="2" align="right">Secure connection:
<input type="checkbox" name="checkbox" class="style5" onclick="javascript:httpHttps();"></td>
</tr>
<tr>
<td class="style5">Login:</td>
<td><input type="text" name="j_username" autocomplete="off" style="width:150px" /></td>
</tr>
所以我认为在客户端没有任何错误(2次UTF8转换)。 如果我在authenticate()函数中从UTF8解码两次用户名,那么身份验证工作正常, 但我害怕将此解决方案应用于我的问题
我应该在Realm的authenticate(String username,String password)函数中查找用户名的这种编码? 服务器端运行在带有httpd-2.2.15和tomcat6-6.0.24的linux(RedHat)上。
答案 0 :(得分:2)
在您的示例中,您的表单使用%编码向Tomcat发送'á'的UTF-8字符(因此通过网络它是%C3%A1)。但是,Tomcat会将其解释为Latin1,这是POST的默认编码。
所以Tomcat会将C3A1存储为'Ã',因为C3是'Ã'而A1是拉丁1编码的'¡'。
当你要求username.getBytes()时,它将创建一个UTF-8编码的字节数组,因此它在UTF-8字符集中查找“Ô的两个字符,即C383 C2A1。
详细描述此问题的常见问题解答和建议的解决方案: http://wiki.apache.org/tomcat/FAQ/CharacterEncoding#Q3
更改server.xml中FormAuthenticator的Valve以指定characterEncoding="UTF-8"
<Context path="/YourSercureApp">
<Valve
className="org.apache.catalina.authenticator.FormAuthenticator"
disableProxyCaching="false"
characterEncoding="UTF-8" />
</Context>