在某新闻客户端实习第二周。组里在开发了一个内部使用的内容投放系统,系统刚开发不久,用户登录还是使用注册的方式,组里想接入公司的SSO系统,这个工作让我来做了。首先了解了下单点登陆的原理,然后根据公司给的接口,实现了单点登录系统的接入。下面结合自己的接入代码,简单阐述一下单点登陆的原理。
单点登录是什么就不再阐述。首先要登录系统A,系统A会对请求进行拦截,检查session和cookie是否有登录凭证。如果没有,直接通知浏览器跳转到SSO认证中心去请求登录。在跳转时会传入约定好的token,backurl(用户需要请求到A的地址)、authurl(验证成功后通知浏览器重新定向请求的回调函数)。浏览器请求认证中心登录时会先检查cookie(这是浏览器和认证中心的cookie),如果没有,则进入登录页面,登录成功后会为创建一个cookie并将两者建立的sessionid放入其中,并且返回给浏览器一个凭证,里面有新的token和udi、backurl。并且通知浏览器重定向到authurl并带上参数(也就是那个凭证)。浏览器向回调函数发起请求。在回调函数里会再次向SSO认证中心发送一个验证(使用URLconnect),取得返回的标志。验证标志成功后就可以发送请求获取账户登录的信息了,把登录凭证存到浏览器和系统A之间的cookie和session中。初写博客,感觉叙述比较凌乱。相关代码如下:
HttpServletRequest hrequest = (HttpServletRequest) request; String url = hrequest.getRequestURI(); //判断是否在过滤url之外 if(url.indexOf(this.excludedPages)<0 && url.indexOf("error.html")<0){ HttpServletResponse hresponse = (HttpServletResponse) response; HttpSession session = hrequest.getSession(); Cookie[] cookies = hrequest.getCookies(); if (session.getAttribute("uid") == null) { boolean flag = true; if (cookies != null) { for (int i = 0; i < cookies.length; i++) { Cookie c = cookies[i]; if (c.getName().equalsIgnoreCase("name")) { String name = c.getValue(); session.setAttribute("name", name); } else if (c.getName().equalsIgnoreCase("uid")) { String uid = c.getValue(); session.setAttribute("uid", uid); flag = false; } } } log.info("sso flag=" + flag); if (flag) { String from = ComParameter.FROM; String key = ComParameter.KEY; String tm = "" + System.currentTimeMillis(); String localIp = hrequest.getScheme() + "://" + hrequest.getServerName() + ":" + hrequest.getServerPort() + "/"; String authurl = ""; String backurl = ""; if(localIp.contains("push.tongji.ifeng.com")){ //部署到工作环境中的地址 authurl = localIp + "domainCheck"; backurl = localIp; }else{ authurl = localIp + "operate-web/domainCheck"; backurl = localIp + "operate-web/testLogin"; //SSO认证中心返回uid和name后转发到的地址,同时也作为浏览器请求地址 } String token1 = MD5Util.encode(from + key + tm + authurl + backurl); String redirectUrl = ComParameter.SSO_INTF_1 + "?from=" + from + "&tm=" + tm + "&authurl=" + authurl + "&backurl=" + backurl + "&token1=" + token1; hresponse.sendRedirect(redirectUrl); } 这是拦截并重定向到SSO认证中心
@Controller public class DomainCheckController { @RequestMapping(value = "/domainCheck") public String domainCheck(HttpServletRequest hrequest, HttpServletResponse hresponse, HttpSession httpSession,String token2,String uid,String tm,String backurl) throws UnsupportedEncodingException { String result = userValide(token2); if("<ret>1</ret>".equals(result)){ String userInfo = getUserInfo(uid,"json"); JSONObject jsonObject = JSONObject.fromObject(userInfo); String name = jsonObject.getString("cn"); httpSession.setAttribute("name",name); httpSession.setAttribute("uid",uid); Cookie nameCookie = new Cookie("name", URLEncoder.encode(name, "UTF-8")); nameCookie.setMaxAge(60 * 60 * 24 * 30); nameCookie.setPath("/"); Cookie uidCookie = new Cookie("uid", uid); uidCookie.setMaxAge(60 * 60 * 24 * 30); uidCookie.setPath("/"); hresponse.addCookie(nameCookie); hresponse.addCookie(uidCookie); }else { return "redirect:/"; } hrequest.setAttribute("finalUrl",backurl); return "domainCheck/domain"; } public static String userValide(String token2){ String from = ComParameter.FROM; String key = ComParameter.KEY; String token3 = MD5Util.encode(from+key+token2).toLowerCase(); String ret = HttpReqUtil.getDataFromURL(ComParameter.SSO_INTF_2+"?token3="+token3); return ret; } public static String getUserInfo(String uid , String fmt){ String from = ComParameter.FROM; String key = ComParameter.KEY; String userUrl = ComParameter.SSO_INTF_3; long millis = Calendar.getInstance().getTimeInMillis(); String time = "" + millis; String token4 = MD5Util.encode(uid+key+time+from).toLowerCase(); String ret = HttpReqUtil.getDataFromURL(userUrl + "?uid=" + uid + "&tm=" + time + "&from=" + from + "&fmt=" + fmt + "&token4=" + token4); return ret; } //这是回调函数
参考博客及文档http://blog.csdn.net/cuo9958/article/details/53580466
https://apereo.github.io/cas/4.1.x/protocol/CAS-Protocol.html