UTF-8编码的j_security_check用户名在Tomcat域中被错误地解码为Latin-1

时间:2014-12-15 12:28:44

标签: tomcat utf-8 character-encoding j-security-check

我正在研究在登录表单中引入带有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)上。

1 个答案:

答案 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>