`

单点登陆02(现实篇)

阅读更多

     要做个单点登陆的例子,要有以下: 1 用户身份认证服务器   2 两个应用系统。用户身份认证系统是提供认证功能和登陆功能的,应用系统是模拟跨域访问。项目结构如下图所示:

    其中有三个项目: Client Client2 Server Client Client2 是应用系统用于模拟跨域访问的;而 Server 系统是用户身份验证的。三个都是 Web 工程。既然是 web 工程,那么众所周知 Web 协议(也就是 HTTP )是一个无状态的协议。服务器是如何记录和保持登陆信息呢?

     浏览器访问一次服务器,就和服务器建立一次 Sockect 连接当服务器响应完毕时,就会断口连接。第二次访问的时候模式一样。为了保存信息软件师们发明了两个东西: Session Cookie Session 是保持在服务端的会话信息, Cookie 是持久化在客户端的会话信息。浏览器每次访问 Web 站点时都把此站点相应的 Cookie 信息发送给服务器,服务器从 Cookie 中取相应的字段( sessionId ),然后根据字段在服务器的缓存中查找相应的 Session ,如果没查到则 Request 对象会自动新建一个 Session 对象。这些是基础没有这些知识很难理解如何实现 SSO 的。

首先建好上面三个工程,然后各自建相应的过滤器和页面(源码 )可以先下载下来导入 Eclipse 中,启动 Tomcat 服务器。

    第一: client 端的 AuthFilter 代码

package org.hundsun.sso.filter.auth;


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


//登陆验证
public class AuthFilter implements Filter {

	private String casUrl;

	private String CASSERVER_URL;
	
	private String SERVER_NAME;
	
	private String VARERVER_URL;
	
	private ConnectionUtil connectionUtil;
	
	public void init(FilterConfig config) throws ServletException {
		CASSERVER_URL=config.getInitParameter("casServer");
		SERVER_NAME=config.getInitParameter("serverName");
		VARERVER_URL=config.getInitParameter("varServer");
		connectionUtil = new ConnectionUtil();
		casUrl = new StringBuffer().append(CASSERVER_URL).append("?serverName=").append(SERVER_NAME).toString();
		System.out.println(casUrl);
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws java.io.IOException, ServletException {
		HttpServletResponse response_ = (HttpServletResponse) response;
		HttpServletRequest request_ = (HttpServletRequest) request;
		//获得Ticket
		String ticket = request.getParameter("ticket");
		//转跳状态
		boolean doFilter = false;
		
		String CAS_USRR=(String)request_.getSession().getAttribute("CAS_USRR");
		
		//如果已经登陆
		if ( CAS_USRR!= null&&!"".equals(CAS_USRR)){
			System.out.println("用户已经登录,转发用户请求");
			System.out.println("CAS_USRR:"+CAS_USRR);
			doFilter = true;
		}
		else
		{
			System.out.println("用户没有登录,验证用户ticket");
			System.out.println("ticket详细如:"+ticket);
			//Ticket不为空
			String userName = null;
			//解析用户信息
			if (ticket != null && (userName = connectionUtil.getUserName(ticket)) != null) {
				System.out.println("验证用户ticket成功!");
				request_.getSession().setAttribute("CAS_USRR", userName);	
				doFilter = true;
			}else{
				System.out.println("验证用户ticket失败或ticket为空!");
			}
		}		
		if(doFilter)
			chain.doFilter(request, response);
		else {
			//转跳到CAS服务器
			System.out.println("用户没有登录且没携带ticket,转跳到CAS服务器登录验证!");
			System.out.println("ticket验证地址:"+casUrl);
			response_.sendRedirect(casUrl);
		}
			
	}

	public void destroy() {
	}
	
	private class ConnectionUtil {
		public String getUserName(String ticket) {
			HttpURLConnection connection = null;
			BufferedReader bfReader = null;
			String userName = null;
			try
			{
				//连接CAS验证服务器
				System.out.println("连接CAS验证服务器!ticket:"+ticket);
				String url=VARERVER_URL + "?ticket=" + ticket;
				System.out.println("验证服务器URL:"+url);
				connection = (HttpURLConnection) new URL(url).openConnection();
				connection.connect();
				bfReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
				//获得解密后的用户名
				userName = bfReader.readLine();
				System.out.println("CAS验证服务器还回结果(userName):"+userName);
			}
			catch(Exception e)
			{
				throw new RuntimeException(e);
			}
			finally
			{
				try
				{
					if(bfReader!=null)bfReader.close();
					if(connection!=null)connection.connect();
				}
				catch(Exception e)
				{
					throw new RuntimeException(e);
				}
			}
			return userName;
		}
	}
}

  这个是 client 端的验证用户是否登陆已经是否含有 tickect 信息的过滤器。

  在上面的代码需要用到的参数在 web.xml 配置了,具体如下:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
	http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
	
	<filter>
		<filter-name>autoFilter</filter-name>
		<filter-class>org.hundsun.sso.filter.auth.AuthFilter</filter-class>
		<init-param>
		<param-name>casServer</param-name>
		<param-value>http://127.0.0.1:8888/Server/login</param-value>
		<description>认证服务器地址</description>
		</init-param>
	    <init-param>
		<param-name>varServer</param-name>
		<param-value>http://127.0.0.1:8888/Server/server</param-value>
		<description>服务器地址</description>
		</init-param>
		<init-param>
		<param-name>serverName</param-name>
		<param-value>http://127.0.0.1:8888/Client/welcome.jsp</param-value>
		<description>跳转页面</description>
		</init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>autoFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
 

其次也就是用户验证服务,有 LoginServer ValidationServer 两个 Servlet LoginServer 是检验用户 cookies 中是否含有 tickect ,然后重定向到验证服务中,而 ValidationServer 就是验证服务。 认证服务的配置信息在 web.xml 中:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
	http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<listener>
		<listener-class>org.hundsun.sso.listener.KeyListener</listener-class>
	</listener>

	<servlet>
		<servlet-name>LoginServer</servlet-name>
		<servlet-class>org.hundsun.sso.service.LoginServer</servlet-class>
	</servlet>
	
	<servlet>
		<servlet-name>ValidationServer</servlet-name>
		<servlet-class>org.hundsun.sso.service.ValidationServer</servlet-class>
	</servlet>

	<servlet-mapping>
		<servlet-name>LoginServer</servlet-name>
		<url-pattern>/login</url-pattern>
	</servlet-mapping>
	
	<servlet-mapping>
		<servlet-name>ValidationServer</servlet-name>
		<url-pattern>/server</url-pattern>
	</servlet-mapping>
	

</web-app>

 LoginServer 代码:

public class LoginServer extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// 发出请求的Client
		String serverName = request.getParameter("serverName");
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies)
			{
				if (cookie.getName().equals("CAS")) {
					// 生成Ticket
					String ticket = "CAS" + ":" + cookie.getValue();
					String url = new StringBuffer().append(serverName).append("?ticket=").append(ticket).toString();
					response.sendRedirect(url);
					return;
				}
			}
		}
		
		request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
		return;
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}

 ValidationServer 代码:

import org.hundsun.sso.utiil.RSAUtil;
//验证服务
public class ValidationServer extends HttpServlet {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		String ticket = request.getParameter("ticket");
		String serverName = request.getParameter("serverName");
		String name = request.getParameter("name");
		String pass = request.getParameter("pass");
		
		//优先验证ticket信息
		if(ticket!=null)
		{
			try {
				System.out.println("收的的ticket为:"+ticket);
				String[] result = ticket.split(":");
				
				//验证服务器信息和密码
				System.out.println("验证密码:"+result[0]);
				System.out.println("验证信息:"+result[1]);
				response.getWriter().print(result[1]);
				return;
			} catch (Exception e) {
				throw new RuntimeException(e);
			}
		}
		//验证表单登录信息
		else
		{
			System.out.println("name:"+name);
			System.out.println("pass"+pass);
				
			//登陆成功后将信息保存到Cookie
			Cookie cookie = new Cookie("CAS", name);
			cookie.setMaxAge(-1);
			response.addCookie(cookie);

			String url = new StringBuffer().append(serverName).append("?ticket=").append("CAS" + ":" + name).toString();
			response.sendRedirect(url);
			return;
		}
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		this.doGet(request,response);
	}
}

 以上是代码,具体的流程序列图如:

运行下可以实现了传说中的 SSO 了。

 

  • 大小: 201.3 KB
  • 大小: 29.2 KB
0
1
分享到:
评论
3 楼 罗春桉 2011-02-26  
2 楼 hailiang0901 2010-12-09  
rainyear 写道
海亮你这个代码中,好像有点问题,tomcat访问时,显示URL有不规则的字符串存在,我能不能发我一个完整版的代码。我的邮箱:rainyear@163.com

我再上传一份吧
1 楼 rainyear 2010-12-09  
海亮你这个代码中,好像有点问题,tomcat访问时,显示URL有不规则的字符串存在,我能不能发我一个完整版的代码。我的邮箱:rainyear@163.com

相关推荐

Global site tag (gtag.js) - Google Analytics