天天看点

JForum单点登录问题解决

一.目标:

实现SSO (Single Sign On) :单点登陆。

一般来说,两个不同系统的整合的难点部分,便是需要解决单点登陆问题。

对于我们已有的WEB应用中的用户,若该用户已经登陆,并通过 联结迁移到JForum页面时,JForum要能够识别该用户已经登陆(不需要二次登陆)才不会让用户感到别扭(对用户来说,就好像使用的是同一个系统似的)。

但由于分属于2个不同的系统,所以它们之间不能共用同一套Session,这就需要使用一种特殊的机制来实现它们之间的互相通信。

好在,JForum为我们考虑到了这一点,它提供了灵活的SSO接口与配置机制,我们只需要简单地实现一个SSO类,同时在JForum的配置文件中加以配置即可。

二.JForum SSO机制的原理

- 当一个用户访问JForum时,JForum便会检查是否配置SSO,如果配置了SSO,JForum便会调用authenticateUser()方法。该方法简单地返回username或null。

- 若返回了一个不为空的username时,JForum将会检查是否匹配JForum数据库的userid。

- 若没有匹配的userid,JForum将动态加以创建

- JForum设置该user为登陆状态

- 若返回了一个null,则设置为“Anonymous”

- 若一个“Anonymous”用户试图访问权限以外的页面,JForum将根据SSO的设置导航到登陆页面,同时传递给一个登陆成功后应该迁移到的地址参数给login页面。

三.JForum SSO的实现

上面,我们大致了解了一下JForum的SSO机制的原理。根据SSO机制的原理,我们已经知道该怎么实现SSO。

1,需要实现一个SSO类,该类需要取得从另外一个系统登陆进来的用户信息。

一种最简单的方法是使用Cookie来实现。让已有的WEB应用在用户登陆时写入Cookie信息,然后JForum的SSO实现类中将该Cookie取出即可。

另外,还可以使用web-service,文件的写入等等方式来实现。反正一个最基本的原则是:用户登陆时写入用户信息,然后在JForum一方能取出相同信息即可。

2,配置JForum。

四.JForum SSO的配置

(1)实现net.jforum.sso接口

  编写CookieUserSSO类

package net.jforum.sso;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;

import javax.servlet.http.Cookie;
import net.jforum.ControllerUtils;
import net.jforum.JForumExecutionContext;
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;

public class CookieUserSSO implements SSO {
	static final Logger logger = Logger.getLogger(CookieUserSSO.class.getName());

	public String authenticateUser(RequestContext request) {
		// login cookie set by my web LOGIN application
		Cookie myCookie = ControllerUtils.getCookie("jforumSSOCookieNameUser");      
		String username = null;

		if (myCookie != null) {
			try {
				username = URLDecoder.decode(myCookie.getValue(), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}
      if (myCookie == null || username.trim().equals("")) {      
          //JForumExecutionContext.setRedirect(SystemGlobals.getValue(ConfigKeys.SSO_REDIRECT));      
          return null; // no cookie found      
      }
		System.out.println("cookie_name1="+myCookie.getName());   
		System.out.println("cookie value1="+username);
		return username; // return username for jforum
		// jforum will use this name to regist database or set in HttpSession
	}

	public boolean isSessionValid(UserSession userSession, RequestContext request) {
		 Cookie cookieNameUser = ControllerUtils.getCookie("jforumSSOCookieNameUser"); 		// cookie
		String remoteUser = null;

		if (cookieNameUser != null) {
			try {
				// jforum username
				remoteUser = URLDecoder.decode(cookieNameUser.getValue(), "UTF-8");
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			}
		}

		if (remoteUser == null && userSession.getUserId() != SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {
			// user has since logged out
			return false;
		} else if (remoteUser != null
				&& userSession.getUserId() == SystemGlobals.getIntValue(ConfigKeys.ANONYMOUS_USER_ID)) {
			// anonymous user has logged in
			return false;
		} else if (remoteUser != null && !remoteUser.equals(userSession.getUsername())) {
			// not the same user (cookie and session)
			return false;
		}
		return true; // myapp user and forum user the same. valid user.
	}
}
           

(2)修改SystemGlobals.properties中的配置:

    修改SystemGlobals.properties文件中的一下属性的内容:

    authentication.type = sso(代表启用sso)

    sso.implementation = net.jforum.sso.CookieUserSSO(启用sso后每次url跳转都会到这个类)

    sso.redirect = http://www.123.com/login.jsp //可根据实际的登录页面地址进行修改

    cookie.name.user =jforumUserInfo  //web项目中保存的cookie名称,可根据实际情况修改

(3)修改web.xml:

添加自己的servlet:

    <servlet>

        <servlet-name>cookieServlet</servlet-name>

        <servlet-class>net.jforum.CookieServlet</servlet-class>

    </servlet>  

 <servlet-mapping>

        <servlet-name>cookieServlet</servlet-name>

        <url-pattern>/cookieServlet</url-pattern>

    </servlet-mapping>

(4)添加cookieServlet.java

package net.jforum;


import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;


/**
 * @author jianghai
 * @version 
 */
public class CookieServlet extends HttpServlet
{
	/** 
	 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
	 */
	public void init(ServletConfig config) throws ServletException
	{
		super.init(config);
	}
	
	/** 
	 * @see javax.servlet.http.HttpServlet#service(javax.servlet.ServletRequest, javax.servlet.ServletResponse)
	 */
	public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		String username = request.getParameter("username");
		System.out.println(username);
		if(StringUtils.isNotEmpty(username)){
			//String tt = URLDecoder.decode(username, "utf-8");
			//这里不解码了,因为cookie中不能直接保存中文
			Cookie cookie = new Cookie("jforumSSOCookieNameUser", username);
            cookie.setMaxAge(-1);   //负值表示浏览器关闭时cookie被删除,零值则是要删除该Cookie。
            cookie.setPath("/");
            response.addCookie(cookie);
            
		}else{
			Cookie cookie = new Cookie("jforumSSOCookieNameUser", "");
			cookie.setMaxAge(0); // delete the cookie.
			cookie.setPath("/"); //设置目录为根路径使cookie共享
			response.addCookie(cookie);
		}
		String callback = request.getParameter("callback");
		
		PrintWriter out = null;
		try {
			response.setCharacterEncoding("utf-8");	
			out=response.getWriter();
			out.print(callback+"([ { name:'John',age:'19'},{ name:'joe',age:'20'}] );");
			out.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}finally{
			out.close();
		}
	}
}
           

(5)处理你自己的web项目的登录和注销逻辑

//退出bbs
function exitSystem(){
	window.location.href=('/logout');
	var url = "http://127.0.0.1:8080";
	url += "/JForum/cookieServlet?username=";
	url += "&callback=?";
	$.getJSON(url, function(json){ 
		console.info(json[0].name); 
	}); 
}
//登录bbs
function loginBBS(){
	var username = $("#userName").val();//获取登录名
	
	var url = "http://127.0.0.1:8080";
	url += "/JForum/cookieServlet?username="+encodeURI(encodeURI(username));
	url += "&callback=?";
	$.getJSON(url, function(json){ 
		console.info(json[0].name); 
	});
}
           

这里是通过jsonp技术实现跨越请求

继续阅读