单点登录(Single Sign On),简称为SSO,SSO不仅在企业级开发很常用,在互联网中更是大行其道。随便举几个例子,比如我们登录新浪微博后,再访问新浪首页后,我们发现, 已经自动登录了;再比如我们登录CSDN后,可以写博客、逛论坛、下载资源等等。前者是完全跨域的单点登录,下文会讲,后者是共同父域下 (www.csdn.NET、blog.csdn.net、bbs.csdn.Net、passport.csdn.net)的单点登录,也就是本文的主要内容。
-------------------------1.同域名下的应用的单点登录-----------------------------------
思路:统一登录接口要根据其访问的地址设置登陆成功后跳转的页面。比如你在动物园在景点1被拦截了要求你买票你肯定是买一张通票然后继续访问景点1。具体的做法就是在登录表单中隐藏一个跳转的页面,然后在登录校验成功之后跳转到隐藏表单提交上来的跳转页面。
1.准备环境
将动态项目映射的项目名字去掉
在tomcat的conf文件夹下的server.xml配置:
<Context docBase="E:\tomcat\apache-tomcat-7.0.72\wtpwebapps\SSO_SameDomain" path="" reloadable="true" source="org.eclipse.jst.jee.server:SSO_SameDomain"/>
或者在eclipse中配置:
倒入struts2的jar包,配置web.xml中struts的过滤器。
2.统一登陆接口
登陆页面:(login.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content="qlq"> <meta name="Keywords" content=""> <meta name="Description" content="单点登录的界面"> <title>登录界面</title> </head> <body> <center> <h3>请登录</h3> <form action="" method="post"> 用户名:<input type="text" name="username"/> 密码:<input type="password" name="password"/> <input type="hidden" name="gotoUrl" value="${goroUrl}"/> <input type="submit" value="登录"/> </form> </center> </body> </html>
处理登陆的Action
访问主页的时候设置一个goroUrl,用于标记成功之后要重定向的页面(是demo1的主页还是demo2的主页)。登陆的时候带着gotoUrl访问登陆Action,成功之后跳转到goroUrl对应的页面
package SSOAction; import java.awt.image.VolatileImage; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; public class LoginAction extends ActionSupport { private String username; private String password; private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String execute() throws Exception { boolean OK = this.check(); if (OK) { Cookie cookie = new Cookie("sscookie", "sso"); // 设置cookie的作用范围是顶层(localhost),在localhost域下的应用可见 cookie.setPath("/"); HttpServletResponse response = ServletActionContext.getResponse(); // 增加cookie,未设置生命周期默认为一次会话 response.addCookie(cookie); return SUCCESS; } return null; } public boolean check() { if ("user".equals(username) && "123".equals(password)) return true; return false; } }
struts.xml配置登陆的Action
<package name="sso" namespace="/sso" extends="struts-default"> <action name="login" class="SSOAction.LoginAction"> <result name="success" type="redirect">${goroUrl}</result> </action> </package>
2.登陆校验接口
检查cookie中是否携带登陆信息
package utils; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class CheckCookie { public static boolean checkCookie(HttpServletRequest request) { Cookie cookies[] = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { // 验证是否存在cookie if ("ssocookie".equals(cookie.getName()) && "sso".equals(cookie.getValue())) return true; } } return false; } }
3. 编写demo1主页和demo2主页(struts2中Action的属性名字有get,Set方法属性会被放到值栈中)
demo1的主页:
Demo1Index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="/struts-tags" prefix="s" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>欢迎访问Demo1的主页</title> </head> <body>欢迎访问Demo1的主页,这是Demo1的主页。~~~~~~~~~~~~~~~~~~ <s:debug></s:debug> </body> </html>
处理登陆的Axtion,登陆之前先验证cookie,成功跳到demo1主页,失败将主页写到gotoUrl
package Demo1; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import utils.CheckCookie; /** * Demo1主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo1Action extends ActionSupport { private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); if (CheckCookie.checkCookie(request)) return SUCCESS; // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "/demo1/main.action"; return LOGIN; } }
demo2的主页:
Demo2Index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>欢迎访问Demo2的主页</title> </head> <body>欢迎访问Demo2的主页,这是Demo2的主页。 </body> </html>
处理登陆的Axtion,登陆之前先验证cookie,成功跳到demo2主页,失败将主页写到gotoUrl
package Demo2; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import utils.CheckCookie; /** * Demo2主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo2Action extends ActionSupport { private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); if (CheckCookie.checkCookie(request)) return SUCCESS; // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "/demo2/main.action"; return LOGIN; } }
struts.xml中配置主页
<package name="demo1" namespace="/demo1" extends="struts-default"> <action name="main" class="Demo1.Demo1Action"> <result name="success">/Demo1Index.jsp</result> <result name="login">/login.jsp</result> </action> </package> <package name="demo2" namespace="/demo2" extends="struts-default"> <action name="main" class="Demo2.Demo2Action"> <result name="success">/Demo2Index.jsp</result> <result name="login">/login.jsp</result> </action> </package>
4.启动tomcat测试
1. 访问: http://localhost:8080/demo1/main.action
查看项目源码:
2. 访问: http://localhost:8080/demo2/main.action
查看页面源码:
3.在demo2中登陆
4.刷新demo1.action(已经登陆成功)
5.查看cookie
6.调整3与4d顺序,先登录1,再刷新2,结果一样
-------------------------------------------------共同父域下的SSO------------------------------
0. 首先了解下域名的概念与结构:
域名就是对应于IP地址的用于在互联网上标识机器的有意义的字符串。
联网上的域名就相当于我们现实生活中的门牌号码一样,可以在纷繁芜杂的网络世界 里准确无误地把我们指引到我们要访问的站点。在互联网发展之初并没有域名,有的只是IP地址。IP地址就是一组类似这样的数字, 如:162.105.203.245。由于当时互联网主要应用在科研领域,使用者非常少,所以记忆这样的数字并不是非常困难。但是随着时间的推移,连入互 联网的电脑越来越多,需要记忆的IP地址也越来越多,记忆这些数字串变得越来越困难,于是域名应运而生。域名就是对应于IP地址的用于在互联网上标识机器 的有意义的字符串。例如CNNIC的域名WWW.CNNIC.NET.CN,比起IP地址而言就更形象也更容易记忆。
为了便于大家进一步了解域名的实质,有必要在这里谈谈域名的体系结构。从WWW.CNNIC.NET.CN 这个域名来看,它是由几个不同的部分组成的,这几个部分彼此之间具有层次关系。其中最后的.CN是域名的第一层,.NET是第二层,.CNNIC是真正的 域名,处在第三层,当然还可以有第四层,如:INNER.CNNIC.NET.CN,至此我们可以看出域名从后到前的层次结构类似于一个倒立的树型结构。 其中第一层的.CN叫做地理顶级域名。
目前互联网上的域名体系中共有三类顶级域名:一是地理顶级域名,共有243个国家和地区的代码。例如.CN 代表中国,.JP代表日本,.UK代表英国等等,另一类是类别顶级域名,共有7个:.COM(公司),.NET(网络机构),.ORG(组织机 构),.EDU(美国教育),.GOV(美国政府部门),.ARPA(美国军方),.INT(国际组织)。由于互联网最初是在美国发展起来的,所以最初的 域名体系也主要供美国使用,所以.GOV,.EDU,.ARPA虽然都是顶级域名,但却是美国使用的。只有.COM,.NET,.ORG成了供全球使用的 顶级域名。相对于地理顶级域名来说,这些顶级域名都是根据不同的类别来区分的,所以称之为类别顶级域名。随着互联网的不断发展,新的顶级域名也根据实际需 要不断被扩充到现有的域名体系中来。新增加的顶级域名是.BIZ(商业),.COOP(合作公司),.INFO(信息行业),.AERO(航空 业),.PRO(专业人士),.MUSEUM(博物馆行业),.NAME(个人)。
在这些顶级域名下,还可以再根据需要定义次一级的域名,如在我国的顶级域名.CN下又设立了.COM,.NET,.ORG,.GOV,.EDU以及我国各个行政区划的字母代表如.BJ代表北京,.SH代表上海等等。
1.准备工作:
修改C:\Windows\System32\drivers\etc\hosts文件,增加域名的映射
2.准备统一登录接口
login.JSP
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content="qlq"> <meta name="Keywords" content=""> <meta name="Description" content="单点登录的界面"> <title>登录界面</title> </head> <body> <center> <h3>请登录</h3> <form action="http://check.x.com:8080/sso/login.action" method="post"> 用户名:<input type="text" name="username" value="user"/> 密码:<input type="password" name="password" value="123"/> <input type="hidden" name="gotoUrl" value="${gotoUrl}"/> <input type="submit" value="登录"/> </form> </center> </body> </html>
处理登录的Action(设置cookie为父域下的所有应用可见)
package check.x.com; import java.awt.image.VolatileImage; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; public class LoginAction extends ActionSupport { private String username; private String password; private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String execute() throws Exception { boolean OK = this.check(); if (OK) { Cookie cookie = new Cookie("ssocookie", "sso"); // 设置cookie的作用范围是父域(.x.com) cookie.setDomain(".x.com"); // 斜杠代表设置到父域的顶层,也就是父域下的所有应用都可访问 cookie.setPath("/"); HttpServletResponse response = ServletActionContext.getResponse(); // 增加cookie,未设置生命周期默认为一次会话 response.addCookie(cookie); return SUCCESS; } return null; } public boolean check() { if ("user".equals(username) && "123".equals(password)) return true; return false; } }
struts.xml配置Action
<package name="sso" namespace="/sso" extends="struts-default"> <action name="login" class="check.x.com.LoginAction"> <result name="success" type="redirect">${gotoUrl}</result> </action> </package>
3.准备统一登录校验接口
在check.x.com中校验,首先根据demo1.x.com传来的cookieName和cookieValue进行校验,如果校验通过,通过response返回1,不通过返回0。
校验工具类
package check.x.com.utils; public class CheckCookie { public static boolean checkCookie(String cookieName, String cookieValue) { // 验证是否存在cookie if ("ssocookie".equals(cookieName) && "sso".equals(cookieValue)) return true; return false; } }
校验类:checkCookie()方法
package check.x.com; import java.awt.image.VolatileImage; import java.io.IOException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; import check.x.com.utils.CheckCookie; public class LoginAction extends ActionSupport { private String username; private String password; private String gotoUrl; private String cookieName; private String cookieValue; public String getCookieName() { return cookieName; } public void setCookieName(String cookieName) { this.cookieName = cookieName; } public String getCookieValue() { return cookieValue; } public void setCookieValue(String cookieValue) { this.cookieValue = cookieValue; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } @Override public String execute() throws Exception { boolean OK = this.check(); if (OK) { Cookie cookie = new Cookie("ssocookie", "sso"); // 设置cookie的作用范围是父域(.x.com) cookie.setDomain(".x.com"); // 斜杠代表设置到父域的顶层,也就是父域下的所有应用都可访问 cookie.setPath("/"); HttpServletResponse response = ServletActionContext.getResponse(); // 增加cookie,未设置生命周期默认为一次会话 response.addCookie(cookie); return SUCCESS; } return null; } public void checkCookie() throws IOException{ String result="0"; if(CheckCookie.checkCookie(cookieName, cookieValue)){ result="1"; } HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().print(result); response.getWriter().close(); } public boolean check() { if ("user".equals(username) && "123".equals(password)) return true; return false; } }
struts.xml中配置验证cookie的action(没有跳转页面,只是返回数据)
4.编写demo1的主页及处理的Action
Demo1Index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎访问Demo1的主页</title>
</head>
<body>欢迎访问Demo1的主页,这是Demo1的主页。~~~~~~~~~~~~~~~~~~
</body>
</html>
Demo1Action.java
package demo1.x.com; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Demo1主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo1Action extends ActionSupport { private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); Cookie cookies[] = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("ssocookie".equals(cookie.getName())) { String result = this.doGet("http://check.x.com:8080/sso/checkCookie.action", cookie.getName(), cookie.getValue()); if ("1".equals(result)) { return SUCCESS; } } } } // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "http://demo1.x.com:8080/demo1/main.action"; return LOGIN; } public String doGet(String url, String cookieName, String cookieValue) { // 用于接收返回的数据 StringBuffer sb = new StringBuffer(); // 创建一个连接的请求 HttpURLConnection httpURLConnection = null; try { // 包装请求的地址 URL urls = new URL(url + "?cookieName=" + cookieName + "&cookieValue=" + cookieValue); // 打开连接 httpURLConnection = (HttpURLConnection) urls.openConnection(); httpURLConnection.setRequestMethod("GET"); // 通过BufferReader读取数据 InputStream iStream = httpURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(iStream); BufferedReader bReader = new BufferedReader(inputStreamReader); String temp = null; while ((temp = bReader.readLine()) != null) { sb.append(temp); } // 关闭流(先开后关,后开先关) bReader.close(); inputStreamReader.close(); iStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (httpURLConnection != null) { // 关闭连接 httpURLConnection.disconnect(); } } return sb.toString(); } }
Demo2Index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>欢迎访问Demo2的主页</title> </head> <body>欢迎访问Demo2的主页,这是Demo2的主页。 </body> </html>
Demo2Action.java
package demo2.x.com; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Demo2主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo2Action extends ActionSupport { private String gotoUrl; public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); Cookie cookies[] = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("ssocookie".equals(cookie.getName())) { String result = this.doGet("http://check.x.com:8080/sso/checkCookie.action", cookie.getName(), cookie.getValue()); if ("1".equals(result)) { return SUCCESS; } } } } // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "http://demo2.x.com:8080/demo2/main.action"; return LOGIN; } public String doGet(String url, String cookieName, String cookieValue) { // 用于接收返回的数据 StringBuffer sb = new StringBuffer(); // 创建一个连接的请求 HttpURLConnection httpURLConnection = null; try { // 包装请求的地址 URL urls = new URL(url + "?cookieName=" + cookieName + "&cookieValue=" + cookieValue); // 打开连接 httpURLConnection = (HttpURLConnection) urls.openConnection(); httpURLConnection.setRequestMethod("GET"); // 通过BufferReader读取数据 InputStream iStream = httpURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(iStream); BufferedReader bReader = new BufferedReader(inputStreamReader); String temp = null; while ((temp = bReader.readLine()) != null) { sb.append(temp); } // 关闭流(先开后关,后开先关) bReader.close(); inputStreamReader.close(); iStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (httpURLConnection != null) { // 关闭连接 httpURLConnection.disconnect(); } } return sb.toString(); } }
struts.xml中配置
<package name="demo1" namespace="/demo1" extends="struts-default"> <action name="main" class="demo1.x.com.Demo1Action"> <result name="success">/Demo1Index.jsp</result> <result name="login">/login.jsp</result> </action> </package> <package name="demo2" namespace="/demo2" extends="struts-default"> <action name="main" class="demo2.x.com.Demo2Action"> <result name="success">/Demo2Index.jsp</result> <result name="login">/login.jsp</result> </action> </package>
5.启动tomcat进行测试:
1.访问:http://demo1.x.com:8080/demo1/main.action
查看页面源码
2.访问:http://demo2.x.com:8080/demo2/main.action
查看页面源码:
3.在demo1中登录:
查看网络
4.刷新demo2
-------------------------------完全跨域的SSO-----------------------------------
0.思路:
表单提交的时候 提交到本域,本域带着用户名与密码去验证服务器进行验证,验证通过的时候增加cookie,增加cookie的时候在页面中通过隐藏iframe通过增加cookie到本域与另一个域;验证cookie的时候也是本域带着cookie名字与值去验证服务器进行验证,验证服务器返回验证结果。
1.准备环境
修改C:\Windows\System32\drivers\etc\hosts文件,增加域名的映射
修改tomcat\conf\server.xml
2.编写同一登录接口
login.jsp(处理登录提交地址是在本域。然后本域带着用户名和密码向验证服务器提交请求)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content="qlq"> <meta name="Keywords" content=""> <meta name="Description" content="单点登录的界面"> <title>登录界面</title> </head> <body> <center> <h3>请登录</h3> <!-- 向当前本域提交登录申请,处理登录与cookie验证在其它域处理 --> <form action="/${path }/sso/login.action" method="post"> 用户名:<input type="text" name="username" value="user" /> 密码:<input type="password" name="password" value="123" /> <input type="hidden" name="gotoUrl" value="${gotoUrl}" /> <input type="submit" value="登录" /> </form> </center> </body> </html>
Demo1.action中处理登录请求:doLogin()方法----带着用户名与密码向验证服务器提交请求
package www.a.com; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Demo1主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo1Action extends ActionSupport { private String gotoUrl; private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { /* * HttpServletRequest request = ServletActionContext.getRequest(); * Cookie cookies[] = request.getCookies(); if (cookies != null) { for * (Cookie cookie : cookies) { if ("ssocookie".equals(cookie.getName())) * { String result = * this.doGet("http://check.x.com:8080/sso/checkCookie.action", * cookie.getName(), cookie.getValue()); if ("1".equals(result)) { * return SUCCESS; } } } } */ // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "http://demo1.x.com:8080/demo1/main.action"; return LOGIN; } /** * 登录方法 * * @return */ public String doLogin() { Map<String, Object> map = new HashMap<>(); map.put("username", username); map.put("password", password); String result = this.doGet("http://www.x.com/sso/doLogin.action", map); if ("1".equals(result)) { return SUCCESS; } return LOGIN; } /* * 验证方法 */ public String doGet(String url, Map<String, Object> map) { // 用于接收返回的数据 StringBuffer sb = new StringBuffer(); // 创建一个连接的请求 HttpURLConnection httpURLConnection = null; try { StringBuffer t_s = new StringBuffer(url).append("?"); for (Map.Entry<String, Object> entry : map.entrySet()) { t_s.append(entry.getKey() + "=" + entry.getValue() + "&"); } url = t_s.substring(0, t_s.length() - 1); // 包装请求的地址 URL urls = new URL(url); // 打开连接 httpURLConnection = (HttpURLConnection) urls.openConnection(); httpURLConnection.setRequestMethod("GET"); // 通过BufferReader读取数据 InputStream iStream = httpURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(iStream); BufferedReader bReader = new BufferedReader(inputStreamReader); String temp = null; while ((temp = bReader.readLine()) != null) { sb.append(temp); } // 关闭流(先开后关,后开先关) bReader.close(); inputStreamReader.close(); iStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (httpURLConnection != null) { // 关闭连接 httpURLConnection.disconnect(); } } return sb.toString(); } }
Demo2.action中处理登录请求:doLogin()方法----带着用户名与密码向验证服务器提交请求
package www.b.com; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Demo1主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo2Action extends ActionSupport { private String gotoUrl; private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } @Override public String execute() throws Exception { /* * HttpServletRequest request = ServletActionContext.getRequest(); * Cookie cookies[] = request.getCookies(); if (cookies != null) { for * (Cookie cookie : cookies) { if ("ssocookie".equals(cookie.getName())) * { String result = * this.doGet("http://check.x.com:8080/sso/checkCookie.action", * cookie.getName(), cookie.getValue()); if ("1".equals(result)) { * return SUCCESS; } } } } */ // 登陆失败后将gotoUrl写到JSP页面 gotoUrl = "http://demo1.x.com:8080/demo1/main.action"; return LOGIN; } /** * 登录方法 * * @return */ public String doLogin() { Map<String, Object> map = new HashMap<>(); map.put("username", username); map.put("password", password); String result = this.doGet("http://www.x.com/sso/doLogin.action", map); if ("1".equals(result)) { return SUCCESS; } return LOGIN; } /* * 验证方法 */ public String doGet(String url, Map<String, Object> map) { // 用于接收返回的数据 StringBuffer sb = new StringBuffer(); // 创建一个连接的请求 HttpURLConnection httpURLConnection = null; try { StringBuffer t_s = new StringBuffer(url).append("?"); for (Map.Entry<String, Object> entry : map.entrySet()) { t_s.append(entry.getKey() + "=" + entry.getValue() + "&"); } url = t_s.substring(0, t_s.length() - 1); // 包装请求的地址 URL urls = new URL(url); // 打开连接 httpURLConnection = (HttpURLConnection) urls.openConnection(); httpURLConnection.setRequestMethod("GET"); // 通过BufferReader读取数据 InputStream iStream = httpURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(iStream); BufferedReader bReader = new BufferedReader(inputStreamReader); String temp = null; while ((temp = bReader.readLine()) != null) { sb.append(temp); } // 关闭流(先开后关,后开先关) bReader.close(); inputStreamReader.close(); iStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (httpURLConnection != null) { // 关闭连接 httpURLConnection.disconnect(); } } return sb.toString(); } }
LoginAction.java 验证服务器处理登录请求(接收上面带来的用户名与密码进行验证,不用设置cookie,只用设置返回验证结果)
package www.x.com; import java.awt.image.VolatileImage; import java.io.IOException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ; import www.x.com.utils.CheckCookie; public class LoginAction extends ActionSupport { private String username; private String password; private String gotoUrl; private String cookieName; private String cookieValue; public String getCookieName() { return cookieName; } public void setCookieName(String cookieName) { this.cookieName = cookieName; } public String getCookieValue() { return cookieValue; } public void setCookieValue(String cookieValue) { this.cookieValue = cookieValue; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } /** * 验证登录信息 * * @throws IOException */ public void doLogin() throws IOException { boolean OK = this.check(); String result = "0"; if (OK) { result = "1"; } HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().print(result); response.getWriter().close(); } public void checkCookie() throws IOException { String result = "0"; if (CheckCookie.checkCookie(cookieName, cookieValue)) { result = "1"; } HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().print(result); response.getWriter().close(); } public boolean check() { if ("user".equals(username) && "123".equals(password)) return true; return false; } }
struts.xml进行配置
<package name="sso" namespace="/sso" extends="struts-default"> <!-- 只是验证,没有返回值 --> <action name="doLogin" class="www.x.com.LoginAction" method="doLogin"> </action> </package> <package name="demo1" namespace="/demo1" extends="struts-default"> <action name="main" class="www.a.com.Demo1Action" method="doLogin"> <result name="success">/Demo1Index.jsp</result> <result name="login">/login.jsp</result> </action> </package> <package name="demo2" namespace="/demo2" extends="struts-default"> <action name="main" class="www.b.com.Demo2Action" method="doLogin"> <result name="success">/Demo2Index.jsp</result> <result name="login">/login.jsp</result> </action> </package>
3.登录校验接口----------------LoginAction.java检验cookie是否有效
public void checkCookie() throws IOException { String result = "0"; if ("ssocookie".equals(cookieName) && "sso".equals(cookieValue)) { result = "1"; } HttpServletResponse response = ServletActionContext.getResponse(); response.getWriter().print(result); response.getWriter().close(); }
struts.xml进行配置
4.编写Demo1和Demo2主页
两个成功页面都是成功后加载主页时访问域名a与域名b下的添加cookie的方法(通过隐藏的iframe可以实现),cookie添加在本域下面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>欢迎访问Demo2的主页</title> </head> <body> 欢迎访问Demo2的主页,这是Demo2的主页。 <!--成功之后隐藏一个设置cookie的连接 --> <c:forEach var="url" items="${hiddenurls }"> <iframe src="${url }" width="0px" height="0px" style="display: none"></iframe> </c:forEach> </body> </html>
主页处理增加cookie
package www.a.com; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.print.attribute.standard.RequestingUserName; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; /** * Demo1主页,访问主页要先验证cookie * * @author: qlq * @date : 2017年8月29日下午12:02:31 */ public class Demo1Action extends ActionSupport { private String gotoUrl; private String username; private String password; private String path; private List<String> hiddenurls; public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getGotoUrl() { return gotoUrl; } public void setGotoUrl(String gotoUrl) { this.gotoUrl = gotoUrl; } public List<String> getHiddenurls() { return hiddenurls; } public void setHiddenurls(List<String> hiddenurls) { this.hiddenurls = hiddenurls; } @Override public String execute() throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); Cookie cookies[] = request.getCookies(); if (cookies != null) { for (Cookie cookie : cookies) { if ("ssocookie".equals(cookie.getName())) { HashMap<String, Object> map = new HashMap<>(); map.put("cookieName", cookie.getName()); map.put("cookieValue", cookie.getValue()); String result = this.doGet("http://www.x.com/sso/checkCookie.action", map); if ("1".equals(result)) { return SUCCESS; } } } } // 登陆失败后将gotoUrl写到JSP页面 path = "demo1"; gotoUrl = "http://www.a.com/demo1/main.action"; return LOGIN; } public void addCookie() { Cookie cookie = new Cookie("ssocookie", "sso"); cookie.setPath("/"); HttpServletResponse response = ServletActionContext.getResponse(); response.addCookie(cookie); } /** * 登录方法 * * @return */ public String doLogin() { Map<String, Object> map = new HashMap<>(); map.put("username", username); map.put("password", password); String result = this.doGet("http://www.x.com/sso/doLogin.action", map); if ("1".equals(result)) { hiddenurls = new ArrayList<>(); hiddenurls.add("http://www.a.com/demo1/addCookie.action"); hiddenurls.add("http://www.b.com/demo2/addCookie.action"); return SUCCESS; } return LOGIN; } /* * 验证方法 */ public String doGet(String url, Map<String, Object> map) { // 用于接收返回的数据 StringBuffer sb = new StringBuffer(); // 创建一个连接的请求 HttpURLConnection httpURLConnection = null; try { StringBuffer t_s = new StringBuffer(url).append("?"); for (Map.Entry<String, Object> entry : map.entrySet()) { t_s.append(entry.getKey() + "=" + entry.getValue() + "&"); } url = t_s.substring(0, t_s.length() - 1); // 包装请求的地址 URL urls = new URL(url); // 打开连接 httpURLConnection = (HttpURLConnection) urls.openConnection(); httpURLConnection.setRequestMethod("GET"); // 通过BufferReader读取数据 InputStream iStream = httpURLConnection.getInputStream(); InputStreamReader inputStreamReader = new InputStreamReader(iStream); BufferedReader bReader = new BufferedReader(inputStreamReader); String temp = null; while ((temp = bReader.readLine()) != null) { sb.append(temp); } // 关闭流(先开后关,后开先关) bReader.close(); inputStreamReader.close(); iStream.close(); } catch (Exception e) { e.printStackTrace(); } finally { if (httpURLConnection != null) { // 关闭连接 httpURLConnection.disconnect(); } } return sb.toString(); } }
struts.xml配置
5.测试:
1.访问:http://www.b.com/demo2/main.action
查看源码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content="qlq"> <meta name="Keywords" content=""> <meta name="Description" content="单点登录的界面"> <title>登录界面</title> </head> <body> <center> <h3>请登录</h3> <!-- 向当前本域提交登录申请,处理登录与cookie验证在其它域处理 --> demo2 <form action="/demo2/doLogin.action" method="post"> 用户名:<input type="text" name="username" value="user" /> 密码:<input type="password" name="password" value="123" /> <input type="hidden" name="gotoUrl" value="http://www.b.com/demo2/main.action" /> <input type="submit" value="登录" /> </form> </center> </body> </html>
2.访问: http://www.a.com/demo1/main.action
查看源码:
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content="qlq"> <meta name="Keywords" content=""> <meta name="Description" content="单点登录的界面"> <title>登录界面</title> </head> <body> <center> <h3>请登录</h3> <!-- 向当前本域提交登录申请,处理登录与cookie验证在其它域处理 --> demo1 <form action="/demo1/doLogin.action" method="post"> 用户名:<input type="text" name="username" value="user" /> 密码:<input type="password" name="password" value="123" /> <input type="hidden" name="gotoUrl" value="http://www.a.com/demo1/main.action" /> <input type="submit" value="登录" /> </form> </center> </body> </html>
3.登录demo1
4.刷新demo2