nighty

折腾的年华
posts - 37, comments - 143, trackbacks - 0, articles - 0

JForum集成--用户重名的一种解决方案

Posted on 2009-10-14 17:41 寒武纪 阅读(2146) 评论(1)  编辑  收藏 所属分类: 系统集成
     JForum做为一个成熟的开源BBS论坛解决方案,提供了非常方便的SSO集成接口。它的主页上和网上都有许多介绍如何用SSO方式进行集成的办法。这里不罗列,google可以找到许多资料,主要描述一下如何解决用户名重名的一种方式。目前使用的JForum版本是2.1.8

     简单地介绍一下采用的SSO方式。由于应用上需要一个BBS,找了JForum做为一个子系统,集成到现成的一个管理系统当中,管理系统本身有一套完全的身份权限认证方案,由于系统的安全要求不是特别严格,所以采了最直接和最省事的方式:Cookie写入。即在管理系统登录时,把用户信息写入Cookie,JForum从Cookie中读取用户信息进行登录。
     为JForum项目添加一个SSO接口的扩展类CookieSSO,主要实现authenticateUser(RequestContext request)方法。方法大体如下:
    
public String authenticateUser(RequestContext request) {
        String userId 
= null;
        Cookie c 
= ControllerUtils.getCookie("ehrbbsuserid");
        
if(c!=null){
            userId 
= c.getValue();
        }

        logger.info(
"单点登录BBS用户ID为:" + userId);
        
return userId;
    }
    就是从Cookie中读取在管理系统中放入的username。但是这里写的是:ehrbbsuserid,主要是这个变量名来区分传过来的内容的不同。

    按照正常的方式就是从管理系统把一个用户的username传过来。然后在这里取出,return给调用方法进行验证。在实际项目中,问题就出在这里了
     举例说有二个用户名字都叫:李四,那么当二个李四都同时登录时,JForum的验证方式就会出问题!它认不清到底是哪个李四,数据库查询时只按第一个来!
     仔细看一下jforum的数据库表设计,jforum_user这个表没有display_user_name类似的字段,它就是把username做为显示在页面上的用户名,如果不做集成,把它单独做为一个BBS时,username既是登录的用户名,也是显示在页面上的用户名。主要原因我想大概就是老外的思维方式跟中国人的不太一样。中国人登录的时候用英文,显示的时候还有一个昵称或是中文名等。
     所以把它集成的时候,用Cookie传送一个username给JForum时就得用中文(而且重名的概率很大)。我们再跟进一个它的代码,看是谁调用了SSO接口的这个方法:
    结果发现是类:net.jforum.ControllerUtils的checkSSO(UserSession userSession)方法
   
/**
     * Checks for user authentication using some SSO implementation
     * 
@param userSession UserSession
     
*/

    
protected void checkSSO(UserSession userSession)
    
{
        
try {
            SSO sso 
= (SSO) Class.forName(SystemGlobals.getValue(ConfigKeys.SSO_IMPLEMENTATION)).newInstance();
            String username 
= sso.authenticateUser(JForumExecutionContext.getRequest());

            
if (username == null || username.trim().equals("")) {
                userSession.makeAnonymous();
            }

            
else {
                SSOUtils utils 
= new SSOUtils();

                
if (!utils.userExists(username)) {
                    SessionContext session 
= JForumExecutionContext.getRequest().getSessionContext();

                    String email 
= (String) session.getAttribute(SystemGlobals.getValue(ConfigKeys.SSO_EMAIL_ATTRIBUTE));
                    String password 
= (String) session.getAttribute(SystemGlobals.getValue(ConfigKeys.SSO_PASSWORD_ATTRIBUTE));

                    
if (email == null{
                        email 
= SystemGlobals.getValue(ConfigKeys.SSO_DEFAULT_EMAIL);
                    }


                    
if (password == null{
                        password 
= SystemGlobals.getValue(ConfigKeys.SSO_DEFAULT_PASSWORD);
                    }


                    utils.register(password, email);
                }


                
this.configureUserSession(userSession, utils.getUser());
            }

        }

        
catch (Exception e) {
            e.printStackTrace();
            
throw new ForumException("Error while executing SSO actions: " + e);
        }

    }
     在这里明显的,它是通过username去确定这个人是否存在?再继续跟进代码就会发现最后调用了Dao的selectUserByName方法。

     解决的思路:修改JForum的数据库表,并更改代码和页面文件是不科学的,工作量大,而且风险比较高!那么就继续把username用来保存中文名称,它的user_id是一个自增的数字序列。在管理系统的用户表中,扩展一个字段bbs_user_id,用来保存在JForum中的用户id,这个字段就肯定是唯一的,在管理系统登录时,把这个bbs_user_id查询出来,放到Cookie中。在JForum验证时,不再使用它推荐的返回username方式,而是返回它的user_id值。
     那么回到最上面的CookieSSO类的代码,这里返回的String其实是jforum_user表中user_id字段。为了匹配,那么net.jforum.ControllerUtils的checkSSO(UserSession userSession)方法也要改!改为下面的方式:
  
protected void checkSSO(UserSession userSession)
    
{
        
try {
            SSO sso 
= (SSO) Class.forName(SystemGlobals.getValue(ConfigKeys.SSO_IMPLEMENTATION)).newInstance();
            String username 
= sso.authenticateUser(JForumExecutionContext.getRequest());

            
if (username == null || username.trim().equals("")) {
                userSession.makeAnonymous();
            }

            
else {
//                SSOUtils utils = new SSOUtils();
                /* 重构为按userId验证身份 */
//                if (!utils.userExists(username)) {
//                    SessionContext session = JForumExecutionContext.getRequest().getSessionContext();
//
//                    String email = (String) session.getAttribute(SystemGlobals.getValue(ConfigKeys.SSO_EMAIL_ATTRIBUTE));
//                    String password = (String) session.getAttribute(SystemGlobals.getValue(ConfigKeys.SSO_PASSWORD_ATTRIBUTE));
//
//                    if (email == null) {
//                        email = SystemGlobals.getValue(ConfigKeys.SSO_DEFAULT_EMAIL);
//                    }
//
//                    if (password == null) {
//                        password = SystemGlobals.getValue(ConfigKeys.SSO_DEFAULT_PASSWORD);
//                    }
//
//                    utils.register(password, email);
//                }
                /* 新添加的代码 */
                UserDAO dao 
= DataAccessDriver.getInstance().newUserDAO();
                User user 
= dao.selectById(Integer.parseInt(username));
                
//                this.configureUserSession(userSession, utils.getUser());
                this.configureUserSession(userSession, user);
            }

        }

        
catch (Exception e) {
            e.printStackTrace();
            
throw new ForumException("Error while executing SSO actions: " + e);
        }

    }

    这样就可以解决认证的问题!同时又保证username可以是中文的,而且重名也无所谓。

    附加:查看它的SQL配置文件,发现有selectUserByName这样的方法,通过用户名来查找用户,起初怕是它在某些模块中使用了。后来详细查看,发现它只使用在后台管理(即admin模块)中的用户管理。这个页面提供了一个按用户名来查找用户的功能,所以也是非常合理的!


刚进场的时候戏就落幕

Feedback

# re: JForum集成--用户重名的一种解决方案  回复  更多评论   

2009-10-21 21:50 by liuxin
请问:
JFORUM 1.2.8已经將SyntaxHighlighter納入支援 ,为什么我下载JFORUM.WAR ,测试就没有出现类似JAVAEEYE这样的
程式碼語法高亮呢?
我注意了一下:点击javaeye的页面源码,可以看到页面有类似<pre name="code" class="java"> 的代码,
我用JFORUM.WAR 测试的页面没有生成类似的代码 ,倒是在HEADER.HTML 页有这样的定义: <#assign hasCodeBlock = hasCodeBlock?default(false)/>,在bottom.HTML <#if hasCodeBlock><#include "highlighter_js.htm"/>
但是在JAVA 中只有net.jforum.view.forum.common.PostCommon private static void processText(Post post)
boolean hasCodeBlock = false; ... if (hasCodeBlock) {JForumExecutionContext.getTemplateContext().put("hasCodeBlock", hasCodeBlock);}

请问我在JAVA 代码中怎么改动才能够实现页面程式碼語法高亮呢?
期待你的帮助
我的EMAIL:liuxinsudi@163.com

只有注册用户登录后才能发表评论。


网站导航: