Acegi中文登录帐号问题的解决方案

来源:互联网 发布:linux安装cacti 编辑:程序博客网 时间:2024/04/29 09:23

                                                             Acegi中文登录帐号问题的解决方案

Acegi登陆使用中文帐号名登陆时会抛出异常,下面我贴出的JSP页面上抛出的错误信息(只贴出有分析价值的一部分):

root cause

java.lang.IllegalArgumentException: 张三
        org.apache.tomcat.util.http.ServerCookie.maybeQuote(ServerCookie.java:276)
        org.apache.tomcat.util.http.ServerCookie.appendCookieValue(ServerCookie.java:209)
        org.apache.coyote.tomcat5.CoyoteResponse.addCookie(CoyoteResponse.java:950)
        org.apache.coyote.tomcat5.CoyoteResponseFacade.addCookie(CoyoteResponseFacade.java:291)
        javax.servlet.http.HttpServletResponseWrapper.addCookie(HttpServletResponseWrapper.java:102)

 

分析异常的原因,应该是底层的ServerCookie试图增加一个值为张三的cookie导致的异常,(cookiename肯定不能为中文,这个“张三”应该为value值,但value应该可以是中文的(我用的GBK编码,查看ServerCookie.java好象是用了isToken方法来验证这个cookievalue)),另外这个cookieacegi框架中如何传递给ServerCookie的很让人困惑。

我按cookie单词查找了acegi(1.0.5版本)sourcecode,没有发现acegi中有增加中文cookie的地方,以下是跟cookie相关的类:

SavedRequest.java,SavedRequestAwareWrapper.java,RememberMeServices.java,TokenBasedRememberMeServices.java,我的acegi配置文件中没有配置rememberme相关的过滤器,所以cookie应该和rememberme类没关系,下面是我配置的acegi的过滤器:

/**=httpSessionContextIntegrationFilter,casProcessingFilter,logoutFilter,concurrentSessionFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,anonymousProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor

我在org.acegisecurity.util.FilterChainProxy类的VirtualFilterChain子类中删除session,cookie,

发现java.lang.IllegalArgumentException: 张三 的异常仍然存在,于是我怀疑到是否认证之后,org.apache.tomcat.util.http.ServerCookie是从request.getUserPrincipal().getName()中获取登陆名试图加入到cookie中的,request.getUserPrincipal().getName()返回的是张三,即中文登陆帐号,此值的赋值方式也非常奇怪,在org.acegisecurity.wrapper.SecurityContextHolderAwareRequestFilter.java中,有一句:

                 request = (HttpServletRequest) constructor.newInstance(new Object[] {request, portResolver});

 

在此句之前使用request.getUserPrincipal().getName()会抛出异常,因为getUserPrincipal()是空的,在执行了constructor.newInstance之后再运行request.getUserPrincipal().getName(),发现此句能获得登陆帐号“张三”,不知道这个newInstance是什么原理,怎么会自动地填充了principal信息(看来我的servletAPI原理了解的比较有限)

一个简单的让acegi支持中文帐号登陆的方式就是在org.acegisecurity.ui.webapp.AuthenticationProcessingFilter中将从页面获得的登陆id进行替换,替换为中文对应的英文id,这种方式经测试是可行的,而且绕过了上面提到的cookie的问题,

具体实现就是首先获得页面的中文登陆帐号,然后从数据库的登陆帐号表中找到这个中文帐号(可以使用登陆帐号表的用户名称作为中文帐号),然后找到中文帐号对应的英文帐号,例如根据“张三”找到”zhangsan”,经过测试后,这种方式完全可行!参考下面AuthenticationProcessingFilter更改后的代码:

 

    String username = obtainUsername(request);

    String password = obtainPassword(request);

     //使用替代方案,如果不支持中文登陆帐号,可建立一个中文帐号-英文帐号对照表,根据中文帐号替换为英文帐号,按英文帐号登录

        String userid = "";

        try

        {

        if(username!=null&&username.trim().length()>0)

        {

             userid = ServiceLocator.getDBSupportService().findSingleValueBySql("select user_id from eas_login_user where user_name='"+username+"'", null).toString();

        }

        }

        catch(Exception ex)

        {

        System.out.println("查询用户错误!");

        }

        if(userid==null)userid="";

       

        if (username == null) {

            username = "";

        }

 

        if (password == null) {

            password = "";

        }

        username=userid; //将中文登陆帐号替换为英文帐号

        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);

AuthenticationProcessingFilter是获取页面登录用户帐号和口令的入口点,所以在这里替换后,后面的生成AuthenticationPrincipal信息都按照替换后的英文登陆帐号处理。

 

这种替换帐号的方式固然可行,不过cookie的问题还有很有继续研究的必要,这有助于我们从更深的层次了解servlet容器的原理。

 

                                                                          王保政

Msn:baozhengw999@hotmail.com

QQ:29803446

Email:baozhengw@netease.com