SSO 基于Cookie+fliter实现单点登录 实例解析(一)

接上文,SSO的理论讲解,接下来实践实践!


1、使用Cookie解决单点登录

       技术点:

       1、设置Cookie的路径为setPath("/").即Tomcat的目录下都有效

       2、设置Cookie的域setDomain(".itcast.com");即bbs.itcast.com,或是mail.itcast.com有效。即跨域。

       3、设置Cookie的时间。即使用户不选择在几天内自动登录,也应该保存Cookie以保存在当前浏览器没有关闭的情况下有效。

       4、使用Filter自动登录。


实现步骤

1:首先要准备出几个虚拟主机并配置hosts文件,即本机DNS修改本机的C:\Windows\System32\drivers\etc下的hosts文件。


<span style="font-size:18px;"><span style="font-size:18px;"># localhost name resolution is handled within DNS itself.
#	127.0.0.1        localhost
#	::1             localhost

127.0.0.1       localhost
127.0.0.1       www.bbs.itcast.cn
127.0.0.1       www.news.itcast.cn
127.0.0.1       www.news.com
127.0.0.1       www.bbs.com
127.0.0.1       www.server.com
</span></span>

增加几个Host节点,通过Cookie实现自动登录,必须配置的虚拟主页满足xxx.itcast.cn,即主域名必须保持一致。


一般web应用中一般部署在web.xml文件中,单点退出相关配置如下:

<span style="font-size:18px;"><span style="font-size:18px;"><filter>
		<filter-name>CAS Authentication Filter</filter-name>
		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
		<init-param>
		<!--到哪去登录-->
			<param-name>casServerLoginUrl</param-name>
			<param-value>http://www.server.com:8080/login</param-value>
		</init-param>
		<init-param>
		<!--我是谁-->
			<param-name>serverName</param-name>
			<param-value>http://www.bbs.com:8080</param-value>
		</init-param>
		<init-param>
			<param-name>renew</param-name>
			<param-value>false</param-value>
		</init-param>
		<init-param>
			<param-name>gateway</param-name>
			<param-value>false</param-value>
		</init-param>
	</filter>
	
	<filter>
		<filter-name>CAS Validation Filter</filter-name>
		<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
		<init-param>
			<param-name>casServerUrlPrefix</param-name>
			<param-value>http://www.server.com:8080</param-value>
		</init-param>
		<init-param>
			<param-name>serverName</param-name>
			<param-value>http://www.bbs.com:8080</param-value>
		</init-param>
		
		
		<!--
		<init-param>
			<param-name>proxyCallbackUrl</param-name>
			<param-value>https://localhost:8443/mywebapp/proxyCallback</param-value>
		</init-param>
		<init-param>
			<param-name>proxyReceptorUrl</param-name>
			<param-value>/mywebapp/proxyCallback</param-value>
		</init-param>
		-->
	</filter>
	
	<filter>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
	</filter>
	
	<filter>
		<filter-name>CAS Assertion Thread Local Filter</filter-name>
		<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
	</filter>

	<!-- ************************* -->

<!-- Sign out not yet implemented -->
<!-- 
	<filter-mapping>
		<filter-name>CAS Single Sign Out Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
-->

	<filter-mapping>
		<filter-name>CAS Authentication Filter</filter-name>
		<url-pattern>/protected/*</url-pattern>
	</filter-mapping>

	<filter-mapping>
		<filter-name>CAS Validation Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	 
	<filter-mapping>
		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Assertion Thread Local Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<filter-mapping>
		<filter-name>CAS Validation Filter</filter-name>
		<url-pattern>/proxyCallback</url-pattern>	
	</filter-mapping>
	
	<!--  *********************** -->

<!-- Sign out not yet implemented -->
<!-- 
	<listener>
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
	</listener>
-->

	<!--  *********************** -->

	<welcome-file-list>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list></span></span>

说明:我们看到单点退出的相关类结构,web.xml配置了单点退出的相关类(1个监听器SingleSignOutHttpSessionListener,2个过滤器SingleSignOutFilter,SimpleServerLogoutHandler)。

      

       实现利用了session存储机制,SessionStoreManager是个单例类,用于管理session的存储、删除;SessionMappingStorage是session的存储、删除的执行者,可以看到实际存储的结构是一个artifactId、sessionId为名值对的HashMap表;监听器SingleSignOutHttpSessionListener的作用是session销毁时,调用session管理单例类SessionStoreManager进行session的删除销毁;

        SingleSignOutFilter的作用有2个:一个是在单点访问拦截安全资源时调用单例类SessionStoreManager存储session,另一个是在单点退出时调用单例类SessionStoreManager删除session;SimpleServerLogoutHandler的作用是将客户端的退出请求转发到SSO服务器端,集中处理做各个子系统的单点退出。


2、先在bbs(或是mail)虚拟目录下,开发一个可以自动登录的程序,使用Filter:

<span style="font-size:18px;"><span style="font-size:18px;">1、登录的主页如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
  <head>
  </head>
  <body>
    	<p>在同一台服务器上,多个站点自动登录....>>:<%=session.getId()%></p>
    	<c:if test="${empty sessionScope.user}">
    		<form name="f" method="post" action="<c:url value='/login'/>">
				Name:<input type="text" name="name"/><br/>
				Pwd:<input type="text" name="pwd"/><br/>
				<input type="checkbox" name="chk" value="7">一周内自动登录<br/>
				<input type="submit" value="登录"/>   		
    		</form>
    	</c:if>
    	<c:if test="${not empty sessionScope.user}">
    		欢迎你:${user}。<a href="<c:url value='/loginout'/>">安全退出</a>
    	</c:if>
    	<br/>
    	相关站点:(只要在一边登录成功,即可以自动登录到另一个程序)<br/>
    	<a href="http://mail.itcast.com:7777">mail.itcast.com</a><br/>
    	<a href="http://bbs.itcast.com:7777">bbs.itcast.com</a><br/>
  </body>
</html>
</span></span>

2、登录的Servlet程序如下:

<span style="font-size:18px;"><span style="font-size:18px;">/**
 * 用户登录
 */
public class LoginServlet extends HttpServlet{
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		doPost(req, resp);
	}
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		String nm = req.getParameter("name");
		String pwd = req.getParameter("pwd");
		String chk = req.getParameter("chk");	//是否选中了7天自动登录
		String forward = "/index.jsp";
		if(nm!=null && !nm.trim().equals("") && nm.startsWith("it")//用户名是it开始,且密码是pwd开始的可以登录
				&& pwd !=null && !pwd.trim().equals("") &&
				pwd.startsWith("pwd")){
			System.err.println("登录成功。。。。。");
			forward = "/jsps/welcome.jsp";
			//无论如何,都要设置cookie,如果没有选择自动登录,则只在当前页面的跳转时有效,否则设置有效期间为7天。
			Cookie cookie = new Cookie("autologin",nm+"@"+pwd);
			cookie.setPath("/"); 				//如果路径为/则为整个tomcat目录有用
			cookie.setDomain(".itcast.com");	//设置对所有*.itcast.com为后缀的域名效
			if(chk!=null){
				int time = 1*60*60*24*7;	//1秒*60=1分*60分=1小时*24=1天*7=7天
				cookie.setMaxAge(time);
			}
			resp.addCookie(cookie);
			req.getSession().setAttribute("user", nm);
		}else{
			System.err.println("登录不成功。。。。。。");
		}
		req.getRequestDispatcher(forward).forward(req, resp);
	}
}

</span></span>

3、自动登录的Filter程序如下:

<span style="font-size:18px;"><span style="font-size:18px;">/**
 * 自动登录
 */
public class AutoLogin implements Filter {
	public void destroy() {}
	public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
		System.err.println("开始自动登录验证.....");//此类中应该对登录的servlet直接放行。根据判断url决定。
		HttpServletRequest requ = (HttpServletRequest) req;
		HttpSession s = requ.getSession();
		if (s.getAttribute("user") != null) {//如果用户已经登录则直接放行
			System.err.println("用户已经登录,没有必须要再做自动登录。。。。");
		} else {
			Cookie[] cookies = requ.getCookies();
			if (cookies != null) {
				for (Cookie ck : cookies) {
					if (ck.getName().equals("autologin")) {// 是否是自动登录。。。。
						System.err.println("自动登录成功。。。。。");
						String val = ck.getValue();
						String[] vals = val.split("@");
						s.setAttribute("user", vals[0]);
					}
				}
			}
		}
		chain.doFilter(req, resp);
	}
	public void init(FilterConfig filterConfig) throws ServletException {}
}
</span></span>


4、正常退出的Servlet如下

<span style="font-size:18px;"><span style="font-size:18px;">/**
 * 安全退出删除Cookie
 */
public class LoginOutServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		HttpSession s = req.getSession();		//获取Session
		Cookie cookie = new Cookie("autologin","");//必须声明一个完全相同名称的Cookie
		cookie.setPath("/");//路径也要完全相同
		cookie.setDomain(".itcast.com");//域也要完全相同
		cookie.setMaxAge(0);//设置时间为0,以直接删除Cookie
		resp.addCookie(cookie);
		s.removeAttribute("user");
		System.err.println("安全退出。。。。。");
		resp.sendRedirect(req.getContextPath()+"/index.jsp");
	}
}
</span></span>


这种是基于最简单的方式实现的单点登录,效果图在下篇博客中的


使用基于CAS单点登录流程实例与效果图


下下篇

基于使用Shiro 和使用Spring security控制权限的方案

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值