`
luotuoass
  • 浏览: 639341 次
文章分类
社区版块
存档分类
最新评论

JForum论坛单点登录的几种实现方式 (CAS和Cookie)

 
阅读更多

JForum论坛单点登录的几种实现方式 (CASCookie)

王保政

Email:baozhengw@netease.com

<chsdate isrocdate="False" islunardate="False" day="4" month="8" year="2007" w:st="on"><span lang="EN-US"><font face="Times New Roman" size="3">2007-8-4</font></span></chsdate>

一、CAS实现Jforum的单点登录

()CAS客户端应用的web.xml配置

CASjforum的安装过程本文就不介绍了,下面是jforum配置CAS服务器连接需要在web.xml中添加的配置:

<filter>

<filter-name>CASFilter</filter-name>

<filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>

<init-param>

<param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>

<param-value>https://localhost:8443/cas/login</param-value>

</init-param>

<init-param>

<param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>

<param-value>https://localhost:8443/cas/proxyValidate</param-value>

</init-param>

<init-param>

<param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>

<param-value>localhost:8000</param-value>

</init-param>

</filter>

<filter-mapping>

<filter-name>CASFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

一开始我调试jforum的单点登录的时候,首先在地址栏输入http://localhost:8000/cas/login?service=http://localhost:8000/jforum/user.jsp

(其中user.jsp是我自己添加JSP页面做测试用 ),在CAS页面输入用户名和口令确认后,页面自动跳转到http://localhost:8000/jforum/user.jsp?ticket= ticket=ST-5-Ih4fJNYyWlhFfywfeOwuVAFZn1vKOOVAgpD-20

Ticket是生成的票据,然后用这个ticket做参数访问:

https://localhost:8443/cas/serviceValidate?service= http://localhost:8000/jforum/user.jsp&ticket= ST-5-Ih4fJNYyWlhFfywfeOwuVAFZn1vKOOVAgpD-20

如果成功,返回的页面中出现登录成功的用户名,打开html源文件,内容为:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationSuccess>

<cas:user>admin</cas:user>

</cas:authenticationSuccess>

</cas:serviceResponse>

如果失败,页面显示ticket 'ST-2-4ffpnvHKv1NH5So7uWvFdVNrbHsaPAfROXx-20' not recognizedhtml源文件内容:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationFailure code='INVALID_TICKET'>

ticket 'ST-2-4ffpnvHKv1NH5So7uWvFdVNrbHsaPAfROXx-20' not recognized

</cas:authenticationFailure>

</cas:serviceResponse>

(二)Jforum配置单点登录

JforumWEB-INF/config目录下有一个SystemGlobals.properties文件,配置SSO需要更改此文件的几个配置参数:

authentication.type = sso

#CasUserSSO类用于CAS单点登录,下面将讲述此类的代码

sso.implementation = com.iss.common.sso.CasUserSSO

#CasCookieSSO是基于Cookie的一个简单的单点登录,代码见下文

#sso.implementation = com.iss.common.sso.CasCookieSSO

#下面的redirect我也不太清楚具体有什么用

sso.redirect = https://localhost:8443/cas/

(三)当把jforumweb.xmlCAS filter注释掉以后,使用下面的JSP通过CAS单点登录票据验证的一个示例,其中URL应带service参数,如:

http://localhost:8000/cas/login?service=http://localhost:8000/jforum/testsso.jsp

登录CAS成功后,返回的页面url带有一个ticket参数,见下面的返回URL:

http://localhost:8000/jforum/testsso.jsp?ticket=ST-5-VbM7tdMPeLD1WlH2ZGnocVGTbAY73ff4y17-20

Tomcat控制台显示下面的输出说明票据认证通过:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationSuccess>

<cas:user>admin</cas:user>

</cas:authenticationSuccess>

</cas:serviceResponse>

下面是testsso.jsp:

<%@ page contentType="text/html;charset=GBK"%>

<%@ page import="java.util.*"%>

<%@ page import="net.jforum.context.RequestContext"%>

<%@ page import="net.jforum.entities.UserSession"%>

<%@ page import="net.jforum.util.preferences.ConfigKeys"%>

<%@ page import="net.jforum.util.preferences.SystemGlobals"%>

<%@ page import="org.apache.log4j.Logger"%>

<%@ page import="net.jforum.sso.*"%>

<%@ page import="java.io.*"%>

<%@ page import="edu.yale.its.tp.cas.client.*"%>

<%

String username = null;

String errorCode = null;

String errorMessage = null;

String xmlResponse = null;

String ticket = request.getParameter("ticket");

System.out.println("获取的ticket:"+ticket);

ServiceTicketValidator sv = new ServiceTicketValidator();

if(ticket != null)

{

try

{

sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate");

sv.setServiceTicket(ticket);

sv.setService("http://localhost:8000/jforum/testsso.jsp");

sv.validate();

xmlResponse = sv.getResponse();

if (sv.isAuthenticationSuccesful())

{

username = sv.getUser();

System.out.println("认证成功,获得的用户名为:");

System.out.println(username);

}

else

{

errorCode = sv.getErrorCode();

errorMessage = sv.getErrorMessage();

System.out.println("认证失败!!!!!!!!!!!");

}

}

catch (Exception exc)

{

System.out.println(exc.getMessage());

}

}

%>

edu.yale.its.tp.cas.client.ServiceTicketValidatorcasclient.jar中的类。

()Jforumweb.xml中不配置CAS Filter时,如何实现单点登录类?

这种情况类似于(),但问题是如何在Java类中实现单点登录,而不是在jsp中实现。

我从网上找到一个名为CasUserSSO.java的程序,并按步骤(二)的说明将此类作为单点登录类配置,但编译运行后,在浏览器地址栏输入http://localhost:8000/cas/login?service=http://localhost:8000/jforum/user.jsp

(user.jsp是我自己写的一个显示简单输出的jsp文件, http://localhost:8000/jforum/user.jsp是我在CasUserSSO.java里面作为service参数的),CAS登录成功后Tomcat控制台没有显示单点登录的认证信息,好象CasUserSSO没有调用到,于是我修改了CasUserSSO.java,

sv.setService("http://localhost:8000/jforum/user.jsp")改为sv.setService(java.net.URLEncoder.encode(http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

重新编译运行后,地址栏中输入http://localhost:8000/cas/login?service= http%<chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3A</chmetcnv>%<chmetcnv w:st="on" unitname="F" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0">2F</chmetcnv>%2Flocalhost%<chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3A</chmetcnv>8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist

注意service等号右面的必须是java.net.URLEncoder.encode转换后的字符串(http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list转换后的字符串为http%<chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3A</chmetcnv>%<chmetcnv w:st="on" unitname="F" sourcevalue="2" hasspace="False" negative="False" numbertype="1" tcsc="0">2F</chmetcnv>%2Flocalhost%<chmetcnv w:st="on" unitname="a" sourcevalue="3" hasspace="False" negative="False" numbertype="1" tcsc="0">3A</chmetcnv>8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist)

注意地址栏中service后不要带空格,在地址栏输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3DlistCAS登录后(我的jforum配的超级管理员帐号是admin/123),出现jforum页面,这说明CAS单点登录成功!!!

Tomcat控制台显示:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationSuccess>

<cas:user>admin</cas:user>

</cas:authenticationSuccess>

</cas:serviceResponse>

请大家一定要注意,在地址栏中service=后面的URL必须是encode转换后的,因为开始没转换,我还以为是CasUserSSO写的有问题,网上下载的CasUserSSO中的

sv.setCasValidateUrl("https://localhost:8443/cas/login");我认为是有问题的,会出现一个很奇怪的异常,显示信息为org.xml.sax.SAXParseException: The reference to entity "ticket" must end with the ';' delimiter.我改为:

sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate")则不会出现这个问题。见下面的CasUserSSO.java:

package com.iss.common.sso;

import net.jforum.context.RequestContext;

import net.jforum.entities.UserSession;

import net.jforum.util.preferences.ConfigKeys;

import net.jforum.util.preferences.SystemGlobals;

import org.apache.log4j.Logger;

import net.jforum.sso.*;

import java.util.*;

import java.net.*;

import edu.yale.its.tp.cas.client.*;

public class CasUserSSO implements SSO

{

static final Logger logger = Logger.getLogger(CasUserSSO.class.getName());

public String authenticateUser(RequestContext request)

{

String username = null;

String errorCode = null;

String errorMessage = null;

String xmlResponse = null;

// 开始setServiceTicket单点登录代码

String ticket = request.getParameter("ticket");

logger.info("获取的ticket:"+ticket);

ServiceTicketValidator sv = new ServiceTicketValidator();

if(ticket != null)

{

try

{

logger.info("ticket为非空!!!!!!!!!!!!!!!!!");

sv.setCasValidateUrl("https://localhost:8443/cas/serviceValidate");

//sv.setCasValidateUrl("https://localhost:8443/cas/login");

System.out.println(java.net.URLEncoder.encode("http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

sv.setService(java.net.URLEncoder.encode("http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list"));

sv.setServiceTicket(ticket);

logger.info("开始验证............");

sv.validate();

xmlResponse = sv.getResponse();

//System.out.println(xmlResponse);

if (sv.isAuthenticationSuccesful())

{

username = sv.getUser();

logger.info("认证成功,获得的用户名为:");

logger.info(username);

}

else

{

errorCode = sv.getErrorCode();

errorMessage = sv.getErrorMessage();

logger.info("认证失败!!!!!!!!!!!");

}

}

catch (Exception exc)

{

System.out.println(exc.getMessage());

}

}

// 结束setServiceTicket单点登录代码

/* System.out.println("开始获取用户名。。。");

username = (String)request.getSessionContext().getAttribute("edu.yale.its.tp.cas.client.filter.user");

System.out.println(username);

System.out.println("结束获取用户名。。。");

logger.info("登录用户为:"+username);*/

return username;

}

public boolean isSessionValid(UserSession userSession,RequestContext request)

{

ServiceTicketValidator sv = new ServiceTicketValidator();

String remoteUser =sv.getUser();

logger.info("RemoteUser");

logger.info(remoteUser);

//user has since logged out

if (remoteUser == null && userSession.getUserId() != SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID))

{

return false;

}

// user has since logged in

else if (remoteUser != null && userSession.getUserId() == SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID))

{

return false;

}

// user has changed user

else if (remoteUser != null && !remoteUser.equals(userSession.getUsername()))

{

return false;

}

return true;

}

}

通过http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist登录成功后(admin/123),jforum显示的页面为admin的已登录页面,如果这时在当前浏览器输入配置了CAS的其他web应用,其他web应用不会弹出cas登录页面,因为cas已经登录过了。我做了一个测试,首先

打开一个新的浏览器窗口,输入一个配置了CASweb应用地址,如http://localhost:8000/cms

,弹出cas登录窗口,输入admin/123,登录成功,这时候再输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist,仍然出来一个CAS登录窗口,这好象不是我们所希望的,那么只好再把jforumweb.xml中的CAS过滤器配置好。

()Jforumweb.xml中配置了CAS Filter时,如何实现单点登录类?

现在我们按()的说明配置好CAS Filter,重启tomcat,再次输入http://localhost:8000/cas/login?service=http%3A%2F%2Flocalhost%3A8000%2Fjforum%2Fforums%2Fjforum.page%3Fmodule%3Dforums%26action%3Dlist,反而后台报出认证失败的错误,Tomcat的控制台输出:

<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>

<cas:authenticationFailure code='INVALID_TICKET'>

ticket 'ST-8-DWSSawgxWPwjjJwkScbIOqDcqR6eTUdZhwi-20' not recogni

zed

</cas:authenticationFailure>

</cas:serviceResponse>

难道上面的CasUserSSO.javaServiceTicketValidator的那段代码只适用于未配置CAS Filter的情况?还是因为配置了CAS Filter后,CAS自动做了ticket的验证后丢掉了ticket?所以CasUserSSO中取到的ticket已经过期?这个问题我没想明白,大家如果有清楚的话可以交流一下。

我现在想到一个问题,既然配了Cas Filter后,那么CAS登录后在session里有用户信息,为什么不直接从session中取呢?见上面的CasUserSSO.java,注释掉// 开始setServiceTicket单点登录代码和// 结束setServiceTicket单点登录代码之间的代码,使用下面的代码获得用户名:

username = (String)request.getSessionContext().getAttribute("edu.yale.its.tp.cas.client.filter.user ");

这样岂不更直接!其中CAS登录成功后,配置了CAS FilterWeb应用的session都可以通过edu.yale.its.tp.cas.client.filter.user取得用户名,然后我们重新编译CasUserSSO.java,并启动tomcat,

这时再按下面的过程测试一下单点登录,首先新打开一个浏览器,输入http://localhost:8000/cms(Web应用已配置了CAS),CAS登录窗口输入admin/123cms应用的admin的口令和jforum的可以不同),登录成功后,再运行:

http://localhost:8000/jforum/forums/jforum.page?module=forums&action=list

不会再出来登录窗口了,此页面是系统管理员admin已登录的页面。

注意:如果CAS登录通过了一个jforum目前没有的帐户,则访问jforumjforum会自动在数据库表(jforum_users)中插入一条新的记录,换句话说就是能自动注册,如果其他Web应用需要和jforum集成的话,只要配好了单点登录,就不需要担心其他应用的用户在jforum中注册的问题(不过自动注册只填写帐号名,其他字段还需要用户自己维护,或者编程实现从另外的应用数据库中将用户详细信息与jforum中的用户相关信息进行同步)。

()使用Cookie实现单点等录

由于CAS的配置比较复杂。在实际的企业应用中部署CAS比较麻烦,有的企业的应用服务器是WebSphere的,因此还要解决CAS如何在Websphere部署的问题,同时CAS的用户认证接口还要进行开发,CAS的性能能否满足注册用户信息量很大的电子商务网站?已有系统如何与CAS集成?等等很多问题需要我们考虑,如果我们只需要将Jforum论坛和电子商务平台集成起来,可以考虑采用Cookie进行单点登录的认证(我们项目只要求登录电子商务页面后进入论坛不用再登录而不是相反),Cookie做单点登录的实现方式:

1)电子商务平台登录成功后(不是基于CAS的,把用户名写到名为bbsUserCookie)

(2)为保证安全性,Cookie只在电子商务应用服务器中有效(Jforum在同一应用服务器运行,cookie.setPAth(“/”)),并且CookieMaxAge设置为-1,就是浏览器关闭后Cookie自动失效,另外session失效时也删除名为bbsUserCookie)

所以控制层和JSP中可参考下面代码创建Cookie:

Cookie[] cookie1 = request.getCookies();

if(cookie1==null)

{

Cookie cookie = new Cookie("bbsUser", acegiUserName);

cookie.setMaxAge(-1); //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie

cookie.setPath("/");

response.addCookie(cookie);

}

else

{

for(int i=0; i< cookie1.length; i++)

{

String name = cookie1[i].getName();

String value = cookie1[i].getValue();

if(!name.equals("bbsUser")) //已存在cookie则不需要增加cookie,否则增加cookie

{

Cookie cookie = new Cookie("bbsUser", acegiUserName);

cookie.setMaxAge(-1); //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie

cookie.setPath("/"); //cookie只在同一应用服务器有效

response.addCookie(cookie);

}

}

}

浏览器关闭,上面的cookie失效,如果session失效,则失效跳转或login.jsp要清除cookie,代码:

//清除bbsUsercookie

Cookie cookie = new Cookie("bbsUser", "");

cookie.setMaxAge(0); //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie

cookie.setPath("/");

response.addCookie(cookie);

下面是在JForum中使用的CasCookieSSO.java,此代码从Cookie中读取名为bbsUserCookie作为用户名:

package com.iss.common.sso;

import net.jforum.context.RequestContext;

import net.jforum.entities.UserSession;

import net.jforum.util.preferences.ConfigKeys;

import net.jforum.util.preferences.SystemGlobals;

import org.apache.log4j.Logger;

import net.jforum.sso.*;

import java.util.*;

import java.net.*;

import javax.servlet.http.Cookie;

public class CasCookieSSO implements SSO

{

static final Logger logger = Logger.getLogger(CasUserSSO.class.getName());

public String authenticateUser(RequestContext request)

{

String username = null;

String errorCode = null;

String errorMessage = null;

String xmlResponse = null;

Cookie[] cookie = request.getCookies();

if(cookie == null)

{

//username = "guest";

}

else

{

for(int i=0; i< cookie.length; i++)

{

String name = cookie[i].getName();

String value = cookie[i].getValue();

if(name.equals("bbsUser"))

{

username = value;

break; //退出循环

}

}

}

logger.info("登录用户为:"+username);

return username;

}

public boolean isSessionValid(UserSession userSession,RequestContext request)

{

return false;

//说明:为什么在这里返回false,因为如果返回true的话,当cookie中的用户id变化后,再次访问jforum时,

//jforum仍记忆上次使用的用户ID,当其他应用改变登录用户后,不能根据cookie中的bbsUser变量切换为新的用户,将返回值设置为false后问题解决。所以这里推荐直接返回false

}

}

使用CasCookieSSO时,注意更改Jforum的配置文件,sso.implementation = com.iss.common.sso. CasCookieSSO

分享到:
评论

相关推荐

    Jforum二次开发实现SSO登陆(单点登录)

    实现了在一个网站实现多一个论坛的功能,在原网站登陆之后再Cookie保存一个值就可以实现单点登陆...我只是再原有网站可以实现单点登录到论坛.如果拿到资源不会用的也可以评论的时候带上QQ我会尽快联系。说出自己的问题

    jforum说明文档 源码解析 单点登录 jforum缓存

    jforum的开发文档,以及源码解析 数据库 重要配置文件和包,缓存 权限控制 单点登录

    JForum_SSO_-_JForum单点登陆原理与配置

    一般来说,两个不同系统的整合的难点部分,便是需要解决单点登陆问题。...但由于分属于2个不同的系统,所以它们之间不能共用同一套Session,这就需要使用一种特殊的机制来实现它们之间的互相通信。

    JForum3 jforum java 开源论坛 论坛

    JForum3 jforum java 开源论坛 论坛

    Jforum论坛数据库架构

    Jforum论坛数据库架构Jforum论坛数据库架构

    jforum开源的论坛文档

    jforum开源的论坛文档jforum开源的论坛文档jforum开源的论坛文档

    jforum论坛整合说明

    本文档是自己在做jforum二次开发过程中遇到的一些问题的总结。如果你做jforum整合,相信会给你帮助。

    jforum2论坛源码

    配合JMeter实战,搭建性能测试环境,可以搭配jmeter书籍作为测试环境使用,jforum2源码可二次开发

    jforum论坛图片资源

    用于配置中文jforum,里面包含各种语言的图片文件,将其中的zh_CN目录复制到jforum安装目录下的templates\default\images。就可以显示中文图片

    JForum论坛数据库表结构.rar

    1、附件关系表JFORUM_ATTACH 2 2、附件详细信息表JFORUM_ATTACH_DESC 2 3、附件配置限定关系表JFORUM_ATTACH_QUOTA 2 4、封锁表JFORUM_BANLIST 2 5、标识表JFORUM_BANNER 3 6、书签表JFORUM_BOOKMARKS 3 7、...

    利用JForum创建论坛

    利用开源JForum创建一个自己的论坛,相关软件,JDK、Tomcat、MySQL,开源的开发一个自己的论坛。

    Java论坛系统 JForum

    Java论坛系统 JForum

    java开源论坛jforum

    jforum 是一个非著名的java开源论坛,是学习mvc开放模式的最好例子之一,在这里,你可以体会到一些牛人非常巧妙的设计思想

    Jforum相关文档和PPT

    Jforum的配置、初始化流程 处理请求流程(mvc) 数据库访问实现 文件监控、缓存实现 、权限控制PPt简介

    jforum开源论坛 官方源代码(2.1.9)

    jforum开源论坛 官方源代码(2.1.9)

    jforum开发新东方教育论坛

    用jforum开发的一个教育论坛,有完整的开发流程

    JForum 2.1.9 源码包.zip

    JForum 是采用Java开发的功能强大且稳定...JForum 采用 FreeMarker 作为页面模板引擎,支持包括中文在内的二十几种语言。 JForum 最大的优点是采用 BSD 开源协议,你可以最大限度的进行任何修改和扩展,包括商业用途。

    JForum v2.1.9 源码版

    JForum 是采用Java开发的功能强大且稳定的...JForum 采用 FreeMarker 作为页面模板引擎,支持包括中文在内的二十几种语言。JForum 最大的优点是采用 BSD 开源协议,你可以最大限度的进行任何修改和扩展,包括商业用途。

    jforum功能说明

    JForum是著名的开源论坛,支持多达数十种的多国语言,其中包括简体中文。JForum功能强大,界面美观,加上代码结构清晰,而且采用的是BSD授权,不必担心不必要的版权纠纷。可以说JForum是论坛二次开发的绝佳选择。 ...

    jforum3 (官方运行文件)开源论坛

    jforum 3.0 官方运行文件,开源论坛

Global site tag (gtag.js) - Google Analytics