`

单点登陆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

相关推荐

    详解可跨域的单点登录(SSO)实现方案【附.net代码】

    文章首先回顾了传统单站点登录的机制,即通过session和cookie记录用户登录状态,然后通过SSO的定义、应用场景以及业务需求来说明单点登录解决的现实问题。文章详细阐述了实现可完全跨域SSO的必要条件和功能实现,...

    五年级下册语文第二单元看图作文三篇.doc

    8. **虚拟现实与教育**:未来的教育可能会结合虚拟现实技术,使学生能够更直观地参与到像足球比赛这样的场景中,增强学习体验。 9. **社交媒体与分享**:技术使得学生可以更容易地分享他们的作品,得到反馈,促进...

    青岛版数学二年级下册单元知识点.pdf

    根据提供的文件内容,本篇将详细阐述青岛版数学二年级下册的单元知识点。 第*单元讲授的是有余数的除法,涵盖了有余数除法的意义、余数与除数之间的关系,以及竖式计算方法。有余数的除法指的是在将物体平均分配时...

    新型冠状病毒疫情防控个人现实表现事迹材料五篇.pdf

    以下是从文档中提取的相关知识点: 1. **党员的担当精神**:党员在疫情防控中起到了核心作用,他们如同战斗堡垒,积极行动,展现出了强烈的使命意识和责任担当。南方医院的医护人员、警察以及社区工作者等都在前线...

    2019年八年级语文上册第二单元知识点总结新人教版20200415185

    在本篇知识点总结中,我们将对这些重要知识点进行梳理,以便更好地理解教材内容,提升我们的语文素养。 首先,鲁迅的《阿长与&lt;山海经&gt;》选自其著名的散文集《朝花夕拾》。鲁迅先生是中国现代文学的重要奠基人之一,...

    计算机系统分析员论文第一篇

    为了实现这一目标,文章强调了选用面向对象方法的原因,这种方法能更好地捕捉现实世界的需求,并通过一个引进人才评估系统的例子说明其优越性。同时,文章还讨论了需求分析中使用多种工具和方法的重要性,以及正确...

    基于模型的设计-MCU篇 514_ 44.4M 高清书签版

    但是,我可以根据标题中的关键信息“基于模型的设计-MCU篇 514_ 44.4M 高清书签版”提供一些关于模型设计、MCU(微控制器单元)及其相关知识点的详细解释。 ### 基于模型的设计 **模型设计** 是一种工程设计方法论...

    2016七年级语文下册第七单元小专题写作解读一篇寓言素材新版语文版

    写作技巧方面,举例论证和联系社会是提升学生写作能力的两个关键点。通过引用具体的历史人物和现实生活的例子,学生能够更生动、更具体地展示自己的观点和论据。同时,将寓言与国家大事结合起来,不仅能够拓宽学生的...

    (新人教版)九年级语文上册第四单元15短文两篇习题课件.ppt

    在【部分内容】中,提到了一些与阅读和学习方法相关的知识点: 1. **词语解释**: - "yí xiá jié jiáo chǎn ɡāo" (筹藻):这个词语在古代汉语中指的是修饰文辞,使文章更加华丽生动。 - "滞使心情愉快":...

    2020秋八年级语文上册第四单元16散文二篇我为什么而活着教案新人教版

    【知识点解析】 这篇《我为什么而活着》是英国著名哲学家、数学家伯特兰·罗素的一篇散文,选自人教版八年级语文上册第四单元,旨在引导学生品味散文中的情理交融,揣摩深层含义,提升阅读与理解能力。罗素在文中...

    2019_2020学年八年级物理上册第6章质量和密度单元双基双测B卷提升篇含解析教科版20200208367

    本篇文章将深入解读《2019-2020学年八年级物理上册第6章质量和密度单元双基双测B卷提升篇》中的核心知识点,并通过解析每一题目的细节,帮助学生更好地掌握与运用这些基础物理知识。 首先,我们从质量和密度的基本...

    高一数学知识点总结集锦15篇.docx

    高一数学知识点总结集锦15篇 本文总结了高一数学的重要知识点,包括函数及其表示、集合的概念和表示、函数的定义域和值域、集合的分类等。 高一数学学问点总结 1 函数及其表示 函数是数学中一个基本概念,通过...

    2014届最新高考英语一轮单元复习 精品阅读理解提升文章精选一百篇(19)

    针对这一需求,市场上出现了“2014届最新高考英语一轮单元复习 精品阅读理解提升文章精选一百篇(19)”等系列资源,这些阅读材料不仅被设计用于提升学生的英语能力,而且巧妙地结合了现实世界的问题情境,让学生在...

    2014届最新高考英语一轮单元复习 精品阅读理解提升文章精选一百篇(70)

    在高考英语阅读理解的复习中,这篇关于“Escape Valve”的文章提供了一个社会现象的讨论点,让学生在学习语言的同时,也能思考人际关系和生活态度的问题。这种结合现实话题的文章有助于提高学生的批判性思维和分析...

    河南省武陟县八年级语文上册第三单元第10课短文两篇教材解析清单新人教版

    【知识点详解】 1. 文章结构与主题分析: - 《答谢中书书》:文章以“山川之美,古来共谈”为总起,展现了古代文人对自然之美的共同热爱,随后通过描绘一系列自然景观,如山峰、水流、动植物等,构建出一幅宁静而...

    关于理想的发言稿2篇.doc

    这篇文档包含了两篇关于理想的发言稿,主要探讨了理想与现实、家庭与工作的平衡以及教师职业道德的议题。以下是这两篇发言稿中提炼出的关键知识点: 1. **理想与奉献**:发言稿提到了劳模们的无私奉献精神,尤其是...

    基于模型的设计——MCU篇

    由于直接提供文档扫描的OCR结果无法确保其准确性和连贯性,且由于指令要求不得提供OCR扫描内容,我将以给定的文件信息为基础,根据标题和描述生成相关知识点。 标题“基于模型的设计——MCU篇”指的是关于微控制器...

Global site tag (gtag.js) - Google Analytics