单点登陆

单点登入简介
单点登入(Single Sign On) ,简称为SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。 具体的说就是多个应用系统使用SSO整合在一起后,用户只需要登录一次,就可以访问所有的应用,而不需要每访问一个应用就需要登录一次。

单点登入的要求
统一的认证系统。认证系统的功能主要是验证用户名和密码,管理用户资料和密码。所有的应用系统能够识别已经登入过的用户。通过与认证系统的通讯,能自动判断当前用户是否登入过,从而完成单点登入。

大致流程:
在这里插入图片描述
下面对上图说明,假设主系统的地址为 http://localhost:8088/master,辅系统的地址为http://localhost:8088/slave:
4 访问主系统http://localhost:8088/master
新开一个浏览器,在地址栏中输入主系统地址,访问主系统
5显示登入页面并设置cookie
主系统接到请求后,发现没有cookie知道该用户是第一次访问主系统,没有登入,会返回登入页面的内容,并设置cookie到浏览器
6登入主系统
浏览器中显示了登入页面,用户输入用户名和密码,登入主系统
7显示登入后的页面
主系统接到登入请求后,登入成功,显示登入后的页面。至此登入主系统完成
8第一次访问辅系统http://localhost:8088/slave
在地址栏输入辅系统的地址,访问辅系统
9设置cookie,并重定向到http://localhost:8088/slave
辅系统接到请求后,发现没有cookie知道该用户第一次访问辅系统,设置cookie到浏览器,再次重定向到http://localhost:8088/slave
10再次访问http://localhost:8088/slave
浏览器接到重定向请求后,再次向辅系统发送访问请求http://localhost:8088/slave
11向主系统发送sso请求,请求参数中带有辅系统的cookie
辅系统接到请求后,判断用户没有登入,重定向到主系统的sso请求地址,参数中带有辅系统的cookie
12重定向到主系统的sso,请求参数中带有辅系统的cookie
浏览器接到重定向请求后,访问主系统的sso请求地址,地址中带有辅系统的cookie信息
13登入辅系统
主系统接到sso请求后,用当前登入用户的用户名和密码,登入辅系统。此过程是主系统直接连辅系统,不通过浏览器实现。
14登入成功
辅系统接到主系统的登入请求后,登入成功,返回登入结果给主系统
15重定向到辅系统http://localhost:8088/slave
主系统接到辅系统的登入结果,得到登入辅系统成功的信息,再次重定向到第一次访问辅系统的地址http://localhost:8088/slave
16再次请求辅系统http://localhost:8088/slave
浏览器接到重定向请求后,再次访问辅系统http://localhost:8088/slave
17返回辅系统页面内容
辅系统接到请求后,判断用户已经登入,返回用户请求的内容到浏览器。单点登入过程完成。
== 注意:从第5步输入辅系统的地址后,一直到第14步都是浏览器,主系统,辅系统自动完成的,没有人为参与。==

下面写个案例:
一、方案简述
为了让主系统不受开发语言限制,采用预登录的方式来实现单点。也就是主系统在登录以后,后台代码中模拟发送辅系统的登录请求,传递辅系统能够识别的登录用户ID和密码串,让辅系统后台执行登录操作。(理论上,在前台代码中发送登录请求也可以,但是前台发送登录请求可能会在浏览器的F12等工具上暴露登录用户ID和密码串的值,所以不推荐前台请求。)同理,主系统注销时,也可以发送辅系统的注销请求进行同步注销。注销请求可以简单的通过前台发送。
二、流程
1.主系统登录操作时,前端通过JSONP请求辅系统后端生成的SESSIONID值
2.主系统将这个值回传给后台
3.主系统在调用辅系统登录的请求时,增加辅系统回传的SESSIONID值作为请求cookie头

//在主系统登陆之前,请求辅系统sessionid
$.getJSON("http://ip:8079/project/cookie.do?jsonp=?", function(data) {
	if (data) {
		//请求到sessionid之后的回调
		//该值是辅系统生成使用的cookie值,需要将该值传给后台,并在给辅系统请求头中加入该值
		var cookie = data.sessionid;
		//将该sessionid传到主系统后台
		//在这之后做主系统的登陆请求
		//主系统登陆代码挪到回调里面,在这里做登陆,并将cookie值传回后台
		//参数形式:id=admin&pw=admin&fusessionid=cookie
		//登陆
		sendLogin(后台响应的地址,参数);
	}
});
/**
* 主系统登陆辅系统后台代码
* 发送post请求
*/
private String sendPost(String urlpath, String params, String sessionId) throws IOException {
	PrintWriter out = null;
	BufferedReader in = null;
	String results = "";
	System.out.println("POST请求地址:" + urlpath);
	try {
		URL realUrl = new URL(urlpath);
		// 打开和URL之间的连接
		URLConnection conn = realUrl.openConnection();
		conn.setRequestProperty("accept", "*/*");
		conn.setRequestProperty("connection", "Keep-Alive");
		conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
		conn.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
		conn.setRequestProperty("Access-Control-Allow-Origin", "*");
		conn.setRequestProperty("Cookie", SecurityFunc.checkHttpHeader(null,"JSESSIONID=" + sessionId));
		// 发送POST请求必须设置如下两行
		conn.setDoOutput(true);
		conn.setDoInput(true);
		out = new PrintWriter(conn.getOutputStream());
		// 发送请求参数
		out.print(params);
		// flush输出流的缓冲
		out.flush();
		// 定义BufferedReader输入流来读取URL的响应
		in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
		String line;
		while ((line = in.readLine()) != null) {
		results += line;
		}
		return results;
	} catch (Exception e) {
		System.out.println("发送 POST 请求出现异常!" + e);
		e.printStackTrace();
	} finally {
		if (in != null) {
			in.close();
		}
		if (out != null) {
			out.close();
		}
	}
	return results;
}

五、辅系统改动
1.辅系统提供了一个取sessionid的接口,供主系统调用。主要代码如下:

  protected void cookie(HttpServletRequest req, HttpServletResponse res, ClientResult result)
    throws Exception {
    String callbackfunc = req.getParameter("jsonp");
    Cookie[] cookies = req.getCookies();
    ArrayList ar = new ArrayList();
    for (int i = 0; (cookies != null) && (i < cookies.length); i++) {
      Cookie ck = cookies[i];
      if ("JSESSIONID".equals(ck.getName())) {
        ar.add(ck.getValue());
      }
    }
    String[] ids = new String[ar.size()];

    String[] sessionId = (String[])ar.toArray(ids);

    //由于IE6,IE7支持W3C的P3P协议,会在iframe中阻止cookie,导致无法跨域获取cookie问题,在服务器就会因此丢失session
    //在sso中,第三方系统,是直接嵌入到iframe中,这样就导致res.sendRedirect时session丢失。
    //为了保证以后所有的url嵌入第三方系统后cookie都会被浏览器接受,需要设置以下http头,这样就不会出现iframe跨域访问阻止cookie的问题了
    if (!res.containsHeader("P3P"))
    	res.setHeader("P3P", "CP=\"IDC DSP COR CURa ADMa OUR IND PHY ONL COM STA\"");
    HttpSession session = req.getSession();
    String id = session.getId();
    if (sessionId == null || sessionId.length == 0 && StrFunc.isNull(id)) {
      throw new RuntimeException("无法从request中得到sessionId参数!");
    }
    JSONObject json = new JSONObject();
    json.put("cookie", StrFunc.isNull(id) ? sessionId[0] : id);
    result.getWriter().print(callbackfunc + "(" + json + ")");
  }

2.更改辅系统中:/web-inf/web.xml文件
filter配置,放过拦截请求辅系统sessionid的接口

<filter>
<filter-name>filterLoginCheck</filter-name>
<filter-class>com.action.FilterLoginCheck</filter-class>
<init-param>
<param-name>paltfrom_FreeAccess</param-name>
<param-value>/路径/cookie.do</param-value>
</init-param>
</filter>

3.写一个过滤器

<filter>
<filter-name>SSOLoginFilter</filter-name>
<filter-class>com.action.login.SSOLoginFilter</filter-class>
<init-param>
<param-name>notCheckURLList</param-name>
<param-value>/ssoconfig.do;/test.do;</param-value>
</init-param>
</filter>

4.单点登录的地址映射

<filter-mapping>
<filter-name>SSOLoginFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>

写到这里在这个项目上差不多就结束了,代码仅供参考,不足之处,还望多多包涵

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值