单点登录(SSO):SSO是指在多个应用系统中个,用户只需要登陆一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一用户的登陆的机制。

SSO的实现过程:

通过上述图形,我们可以看到SSO的大体实现步骤主要分为两大步:存储登录信息,查验登录信息。

对于SSO,我们也可以将之分为两大不同的类型:同域SSO和跨域SSO;其中同域SSO又可以分为完全同域SSO和同父域SSO。

一、完全同域SSO:指的是域名完全相同的多个应用系统中实现单点登录。

其实现步骤主要分为:前期准备工作,编写统一登录接口,编写登录校验接口,编写验证页面,实现SSO;

编写统一登录接口:
登录页面的编写主要是录入用户的登录信息,包括用户名,密码,以及登录页面的地址。因为存在多个应用系统,所以用户在统一登录页面登陆成功后,系统需要知道用户想要访问的是哪个系统页面,这个时候就需要记录用户第一次访问的地址,等到用户登录成功后,就可直接跳转该页面。

<body>
<center>
<h1>请登录</h1>
<form action="/sso/doLogin.action" method="POST">
<span>用户名:</span><input type="text" name="username" />
<span>密码:</span><input type="text" name="password" />
//暂存需要登录页面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>

登录方法的编写:需要新建cookie,将用户的信息存进cookie中,并指定cookie的路径,因为是完全同域,所以cookie的地址可以简写为(“/”)。这里必须要设置cookie的路径,如果不设置,那么cookie的路径将并不一定在当前域名的顶层,它有可能就在当前的这个路径下才可见,这样会导致在当前域的其他路径下找不到这个cookie,解决办法就是把cookie设置到当前域的最顶层域里面,这样当前域下的所有应用就会都可见。

public String doLogin(){
//新建Cookie
Cookie cookie = new Cookie("ssocookie","sso");
//设置Cookie路径
cookie.setPath("/");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
return "success";
}

登录校验接口的编写:通常SSO登录接口校验都会放在登录拦截器中,当用户想要访问某个系统时,登录拦截器将直接重定向到统一登录页面,用户填写完登录信息后,就会进行登录校验。

//cookie校验(放在拦截器中进行校验)
public static boolean checkCookie(HttpServletRequst request){
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookies cookie:cookies){
if(cookie.getName().equals("ssocookie")
&&cookie.getValue().equals("sso")){
return true;
}
}
}
return false;
  }

编写测试主页

public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
if(SSOCheck.checkCookie(request)){
//登陆成功,记录用户登录信息......
return "success";
}
//登录失败,暂存需要访问的地址,登录成功后,直接访问该地址
gotoUrl="/demo1/main.action";
return "login";
}

最后还有struts2的配置文件

<struts>
<package name="sso" namespace="/sso" extends="struts-default">
<action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
       <!-- 用户登录成功后,需要进行重定向,重新跳转到用户最初访问的路径 -->
<result name="success" type="redirect">${gotoUrl}</result>
</action>
</package> <package name="demo1" namespace="/demo1" extends="struts-default">
<action name="main" class="com.xm.controllerAction.Demo1Action" method="main">
<result name="success">/success1.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
<package name="demo2" namespace="/demo2" extends="struts-default">
<action name="main" class="com.xm.controllerAction.Demo2Action" method="main">
<result name="success">/success2.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
</struts>

二、同父域SSO:指的是父域名相同的应用系统上实现SSO。

其实现步骤与上述完全同域SSO相同。

其中检验域名:http://check.x.com

测试页面域名:http://demo1.x.com和http://demo2.x.com

编写统一登录接口:
代码实现与完全同域名SSO基本一致,不过在设置提交路径时,因为二级域名不同,所以不能写成相对路径,需要写成绝对路径地址。

<body>
<center>
<h1>请登录</h1>
     //表单提交地址需写成绝对路径,不能写相对路径
<form action="http://check.x.com/sso/doLogin.action" method="POST">
<span>用户名:</span><input type="text" name="username" />
<span>密码:</span><input type="text" name="password" />
//暂存需要登录页面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>

登录方法:在设置cookie路径的时候有所变化,同上,为了使得当前两个同父域的应用系统都可见这个cookie,那么我们需要将这个cookie设置到父域下面,而不应该设置到本域下面,这样才可以实现域不同,但是父域相同的应用都可以看到的这个cookie。

    public String doLogin(){
     boolean ok = SSOCheck.checkLogin(userName,passWord);
     if(ok){
  //新建Cookie
  Cookie cookie = new Cookie("ssocookie","sso");
  //设置Cookie的父域
  cookie.setDomain(".x.com");
  //设置Cookie路径
   cookie.setPath("/");
  HttpServletResponse response = ServletActionContext.getResponse();
  response.addCookie(cookie);
   return "success";
     }
  }

登录校验接口:因为有着不同的域,所以我们应该将登录所获得cookie传到专门的校验域下的校验方法中进行校验,否则我们需要在各自不同的登录页面实现校验,这样显得代码十分的冗余。

    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 void checkCookie() throws IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result="0";
if(ok){
result="1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}
public static boolean checkCookie(String cookieName,String cookieValue){
if(cookieName.equals("ssocookie")&&cookieValue.equals("sso")){
return true;
}
return false;
}

编写测试主页

public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
     //获取cookie
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie cookie:cookies){
if(cookie.getName().equals("ssocookie")){
            //向检验服务器中发送cookieName和cookieValue
String result = Demo1Tool.doGet("http://check.x.com/so/checkCookie.action",
cookie.getName(),cookie.getValue());
if(result.equals("1")){
return "success";
}
}
}
}
//暂存需要访问的地址,登录成功后,直接访问该地址
gotoUrl="http://demo1.x.com/demo1/main.action";
return "login";
}
public static 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");
//开始连接
httpURLConnection.connect();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String temp = null;
while((temp = br.readLine())!=null){
sb.append(temp);
}
br.close();
isr.close();
in.close();
} catch(IOException e){
e.printStackTrace();
} finally{
if(httpURLConnection!=null){
httpURLConnection.disconnect();
}
}
return sb.toString();
}

struts配置文件

<struts>
<package name="sso" namespace="/sso" extends="struts-default">
<action name="doLogin" class="com.xm.controllerAction.SSOAction" method="doLogin">
<result name="success" type="redirect">${gotoUrl}</result>
</action>
<action name="checkCookie" class="check.x.com.SSOAction" method="checkCookie">
</action>
</package>
<package name="demo1" namespace="/demo1" extends="struts-default">
<action name="main" class="demo1.x.com.Demo1Action" method="main">
<result name="success">/success1.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" method="main">
<result name="success">/success2.jsp</result>
<result name="login">/login.jsp</result>
</action>
</package>
</struts>

三、跨域SSO:在域名完全不同的应用程序上实现SSO。

其实现步骤与完全同域SSO相同。

其中检验域名:http://www.x.com

测试页面域名:http://www.a.com和http://www.b.com

编写统一登录接口:

<body>
<center>
<h1>请登录</h1>
//这里需要向当前所在的域提交申请,因为如果向校验域提交申请,那么在本域中将无法看到cookie
<form action="/${path}/doLogin.action" method="POST">
<span>用户名:</span><input type="text" name="username" />
<span>密码:</span><input type="text" name="password" />
//暂存需要登录页面的url地址
<input type="hidden" name="gotoUrl" value="${gotoUrl}" />
<input type="submit" />
</form>
</center>
</body>

登录方法:

public String doLogin(){
Map<String,String> map = new HashMap<String,String>();
map.put("userName", userName);
map.put("password", passWord);
String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
if(result.equals("1")){
return "success";
}
return "login";
}
public void doLogin() throw IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result = "0";
if(ok){
result = "1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}

登录校验接口;和同父域SSO的登录校验基本一致,没有什么变化。

public void checkCookie() throws IOException{
boolean ok=SSOCheck.checkCookie(cookieName,cookieValue);
String result="0";
if(ok){
result="1";
}
HttpServletResponse response = ServletActionContext.getResponse();
response.getWriter().print(result);
response.getWriter().close();
}

编写测试主页

public String main(){
HttpServletRequst request = ServletActionContext.getRequst();
Cookie[] cookies=request.getCookies();
if(cookies!=null){
for(Cookie cookie:cookies){
if(cookie.getName().equals("ssocookie")){
Map<String,String> map = new HashMap<String,String>();
map.put("userName", cookie.getName());
map.put("password", cookie.getValue());
String result = Demo1Tool.doGet("http://www.x.com/so/checkCookie.action",
cookie.getName(),cookie.getValue());
if(result.equals("1")){
return "success";
}
}
}
}
//暂存需要访问的地址,登录成功后,直接访问该地址
path = "demo1";
gotoUrl="http://www.a.com/demo1/main.action";
return "login";
}
public static String doGet(String url,Map<String,String> map){
//定义返回值
StringBuffer sb = new StringBuffer();
HttpURLConnection httpURLConnection = null;
try{
StringBuffer t_s = new StringBuffer(url).append("?");
for(Map.Entry<String, String> entry:map.entrySet()){
t_s.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); }
url = t_s.substring(0,t_s.length()-1);
//校验方法所在的地址
URL urls = new URL(url);
//打开连接
httpURLConnection = (HttpURLConnection) urls.openConnection();
//设置打开连接的方法
httpURLConnection.setRequestMethod("GET");
//开始连接
httpURLConnection.connect();
InputStream in = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String temp = null;
while((temp = br.readLine())!=null){
sb.append(temp);
}
br.close();
isr.close();
in.close();
} catch(IOException e){
e.printStackTrace();
} finally{
if(httpURLConnection!=null){
httpURLConnection.disconnect();
}
}
return sb.toString();
}

至此,准备工作做完,接下来是跨域SSO实现中最重要的部分,也就是cookie的设置,在之前完全同域和同父域的情况下,为了实现SSO,我们在进行doLogin时就设置了cookie,因为域名相同,所以十分简单,但是在跨域SSO中,因为不同域之间的cookie是不可见的,所以我们不可能只设置一个cookie,然后令所有的域名下的应用程序皆可见,所以我们应该在每个域下面都有着为本域设置cookie的方法,而不应该直接将设置cookie交给校验域。

//为本域设置cookie的方法
public void addCookie(){
Cookie cookie = new Cookie("ssocookie","sso");
cookie.setPath("/");
HttpServletResponse response = ServletActionContext.getResponse();
response.addCookie(cookie);
}

还需要在配置文件中进行配置:

<action name="addCookie" class="www.a.com.Demo1Action" method="addCookie"></action>

写完好方法,则需要进行调用,因此我们需要找一个可以让二者进行交会的地方,在这里我选择了登录成功的瞬间,通过隐藏的Iframe让二者进行交会。

public String doLogin(){
Map<String,String> map = new HashMap<String,String>();
map.put("userName", userName);
map.put("password", passWord);
String result = Demo1Tool.doGet("http://www.x.com/sso/doLogin.action",map);
if(result.equals("1")){
return "success";
}
List hidderUrl = new ArrayList<String>();
hidderUrl.add("http://www.a.com/demo1/addCookie.action");
hidderUrl.add("http://www.b.com/demo2/addCookie.action");
return "login";
}
<c:forEach var="url" item="${hiddenUrl}">
<iframe src="${url}" width="0px" heigth="0px" style="display:none"></iframe>
</c:forEach>

java之单点登录(SSO)的更多相关文章

  1. JAVA CAS单点登录(SSO) 教程

    一.教程前言 教程目的:从头到尾细细道来单点登录服务器及客户端应用的每个步骤 单点登录(SSO):请看百科解释猛击这里打开 本教程使用的SSO服务器是Yelu大学研发的CAS(Central Auth ...

  2. JAVA CAS单点登录(SSO)

    一.教程前言 教程目的:从头到尾细细道来单点登录服务器及客户端应用的每个步骤 单点登录(SSO):请看百科解释猛击这里打开 本教程使用的SSO服务器是Yelu大学研发的CAS(Central Auth ...

  3. Atitit. 单点登录sso 的解决方案 总结

    Atitit.  单点登录sso 的解决方案 总结 1. 系统应用场景and SSO模式选型 2 2. 系统应用的原则与要求 2 2.1. 开发快速简单::绝大部分系统来说,开发快速简单为主 2 2. ...

  4. CAS单点登录(SSO)完整教程

    转:http://blog.csdn.net/frinder/article/details/7969925 CAS单点登录(SSO)完整教程(2012-02-01更新) 一.教程说明 前言 教程目的 ...

  5. cas 单点登录(SSO)实验之二: cas-client

    cas 单点登录(SSO)实验之二: cas-client 参考文章: http://my.oschina.net/indestiny/blog/200768#comments http://wenk ...

  6. cas 单点登录(SSO)之一: jasig cas-server 安装

    cas 单点登录(SSO)实验之一: jasig cas-server 安装 参考文章: http://my.oschina.net/indestiny/blog/200768#comments ht ...

  7. 单点登录SSO的实现原理 (转)

    单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任.单点登录在大型网站里使用得 ...

  8. 单点登录(一)-----理论-----单点登录SSO的介绍和CAS+选型

    什么是单点登录(SSO) 单点登录主要用于多系统集成,即在多个系统中,用户只需要到一个中央服务器登录一次即可访问这些系统中的任何一个,无须多次登录. 单点登录(Single Sign On),简称为 ...

  9. cas 单点登录(SSO)之中的一个: jasig cas-server 安装

    cas 单点登录(SSO)实验之中的一个: jasig cas-server 安装 參考文章: http://my.oschina.net/indestiny/blog/200768#comments ...

  10. cas单点登录 SSO 的实现原理

    原文出处: cutesource   欢迎分享原创到伯乐头条 单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户 ...

随机推荐

  1. Excel 数据导入至Sqlserver 数据库中 ltrim() 、rtrim() 、replace() 函数 依次空格无效问题

    今天导一些数据从Excel中至Sqlserver 数据库中,在做数据合并去重的时候发现,有两条数据一模一样,竟然没有进行合并: 最后发现有一条后面有个“空格”,正是因为这个“空格”让我抓狂许久,因为它 ...

  2. 00002-layui 右侧呼出页面,PopupLayer

    我这里的功能是弹出 右侧搜索 的页面: top.layui.admin.popupRight({ id: 'LAY_business_PopupLayer' ,area: '350px' ,succe ...

  3. 我找到了Dubbo源码的BUG,同事纷纷说我有点东西

    点赞再看,养成习惯,微信搜索[三太子敖丙]关注这个互联网苟且偷生的工具人. 本文 GitHub https://github.com/JavaFamily 已收录,有一线大厂面试完整考点.资料以及我的 ...

  4. python机器学习(四)分类算法-决策树

      一.决策树的原理 决策树思想的来源非常朴素,程序设计中的条件分支结构就是if-then结构,最早的决策树就是利用这类结构分割数据的一种分类学习方法 . 二.决策树的现实案例 相亲   相亲决策树 ...

  5. 【python(deap库)实现】GEAP 遗传算法/遗传编程 genetic programming +

    目录 前言 1.优化问题的定义 单目标优化 多目标优化 2.个体编码 实数编码 二进制编码 序列编码(Permutation encoding) 粒子(Particles) 3 初始种群建立 一般族群 ...

  6. 使用urllib

    urlopen的基本用法: 工具为:python3(windows) 其完整表达式为: urllib.request.urlopen(url, data=None, [timeout, ]*, caf ...

  7. mysql小白系列_05 日常操作

    mysql启动/关闭 my.cnf的调用顺序 [root@docker02 bin]# ./mysql --help Default options are read from the followi ...

  8. Null passed to a callee that requires a non-null argument

    OC中定义的方法参数默认是不为空的,如果能够为空需要手动指定__nullable ,我想这个警告是提示开发者警惕可能空参数

  9. 洛谷P2765 魔术球问题

    题目链接:https://www.luogu.org/problemnew/show/P2765 知识点: 最大流 解题思路: 本题所有边的容量均为 \(1\). 从 \(1\) 开始加入数字,将这个 ...

  10. PHPstudy 修改数据库上传大小

    要修改的地方已经标出来了 直接修改为你需要的值即可: