JForum论坛单点登录的几种实现方式 (CAS和Cookie)
JForum论坛单点登录的几种实现方式 (CAS和Cookie)
王保政
Email:baozhengw@netease.com
2007-8-4
一、用CAS实现Jforum的单点登录
(一)CAS客户端应用的web.xml配置
CAS和jforum的安装过程本文就不介绍了,下面是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 recognized,html源文件内容:
<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配置单点登录
Jforum的WEB-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/
(三)当把jforum的web.xml的CAS 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.ServiceTicketValidator是casclient.jar中的类。
(四)当Jforum的web.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%3A%2F%2Flocalhost%3A8000%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%3A%2F%2Flocalhost%3A8000%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%3Dlist,CAS登录后(我的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;
<
- 上一篇: TP中可通过字段映射隐藏数据表的字段名
- 下一篇: yii带条件搜索分页
