在某新聞客戶端實習第二週。組裏在開發了一個內部使用的內容投放系統,系統剛開發不久,用戶登錄還是使用註冊的方式,組裏想接入公司的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