結合自身項目中的一個案列來編寫第三方單點登錄接口,目的是讓第三方系統調用我們的接口,無需再次登錄,跳轉到我們的系統,我們系統自動幫用戶進行登錄
這個接口需要寫兩個,第一個則需要生成token,token的作用是防止第三方惡意登錄以及會話過期。結合我個人案列的場景,這個案例是圖書館,用戶現在在第三方登錄,跳到圖書館系統,調用我們這個接口。
這里使用des加密參數生成token。
代碼如下,第一個接口:
/** * 校驗身份和生成token * * @param cardNO 卡號 * @param idcardNO 身份證號 * @param signatrue 簽名 * @param timestamp 時間戳 * @param type 登錄設備類型 * @return */ @RequestMapping("/createToekn") @ResponseBody public ResultEntity createToken(String cardNO, String idcardNO, @RequestParam(required = true) String signatrue, @RequestParam(required = true) String timestamp, @RequestParam(required = true) String type) { //根據參數名進行排序 SortedMap<String, String> parameterMap = new TreeMap<>(); parameterMap.put("cardNO", cardNO); parameterMap.put("idcardNO", idcardNO); parameterMap.put("timestamp", timestamp); parameterMap.put("type", type); StringBuffer sb = new StringBuffer(); Set es = parameterMap.entrySet(); //所有參與傳參的參數按照accsii排序(升序) Iterator it = es.iterator(); while (it.hasNext()) { Map.Entry entry = (Map.Entry) it.next(); Object v = entry.getValue(); //空值不傳遞,不參與簽名組串 if (null != v && !"".equals(v)) { sb.append(v); } } ResultEntity result = new ResultEntity(); //排序好的參數進行MD5加密 String md5Str = MD5Util.md5(sb + secretKey); if (md5Str.equals(signatrue)) { //驗證通過,使用des生成token返回 //判斷時間戳,超過120分鍾,認證超時 Long currTime = System.currentTimeMillis(); if ((currTime - Long.parseLong(timestamp)) / (1000 * 60) > 120) { //這里設置簽名只有兩個小時有效時間,超過需要重新請求,這個第三方請求則需要將參數易進行accsii排序(升序),然后MD5加密,將sign傳值過來再次認證 result.setState(HttpCode.FAILED); result.setMessage("認證超時,請重新請求!"); return result; } String jsonStr = JsonUtils.toJson(parameterMap); //使用des進行加密 DESPlus des = new DESPlus(); String token = des.encrypt(jsonStr); //返回token result.setResult(token); result.setMessage("認證通過!"); result.setState(HttpCode.SUCCESS); return result; } result.setMessage("認證失敗!"); result.setState(HttpCode.FAILED); return result; }
第二個接口這需要驗證token,驗證通過了,則系統幫用戶登錄,驗證不通過則跳到登錄頁面,讓用戶自行登錄。
代碼如下,第二個接口:
/** * 免密登錄 */ @RequestMapping("/checkToken") public String checkToken(String token, HttpServletRequest request, HttpServletResponse response) { String cardNO = ""; String idcardNO = ""; String type = ""; String timestamp = ""; if (token != null && token != "") { try { //使用des解密 DESPlus des = new DESPlus(); String decStr = des.decrypt(token); //將字符串轉換成map對象 Map<String, String> parameterMap = new HashMap<String, String>(); //將對象放到map中 parameterMap = JsonUtils.fromJson(decStr, Map.class); cardNO = parameterMap.get("cardNO"); idcardNO = parameterMap.get("idcardNO"); type = parameterMap.get("type"); timestamp = parameterMap.get("timestamp"); //判斷時間有沒有超過120分鍾,超過即失效,跳轉到登錄界面 Long currTime = System.currentTimeMillis(); if ((currTime - Long.parseLong(timestamp)) / (1000 * 60) > 120) { //跳轉到用戶主頁 if (type.equals("2")) { //跳轉到微信端的界面 return "mobile/index"; } else { //默認跳轉到pc端界面 return "pc/index"; } } if (cardNO != null || idcardNO != null) { //根據卡號或者身份證號去數據庫查詢用戶信息 ReaderEntity param = new ReaderEntity(); param.setCardno(cardNO); param.setIdcardno(idcardNO); List<ReaderEntity> readerEntities = readerDao.selectByParam(param); if (!readerEntities.isEmpty()) { //存入session中,並且判斷type pc:1,微信:2,然后跳轉到各自首頁 //創建session對象 HttpSession session = request.getSession(); session.setAttribute(USES_SESSION_ID, readerEntities.get(0)); //跳轉到用戶主頁 if (type.equals("2")) { //跳轉到微信端的界面 return "mobile/index"; } else { //默認跳轉到pc端界面 return "pc/index"; } } } } catch (Exception e) { //報錯直接跳轉到登錄界面 if (type.equals("2")) { //跳轉到微信端的界面 return "mobile/index"; } else { //默認跳轉到pc端界面 return "pc/index"; } } } //驗證不通過,跳轉到登錄界面,type不傳默認跳轉到pc端登錄 return "/pc/index"; }