redis緩存和cookie實現Session共享
分散式項目中要實現單點登錄(SSO - Single Sign On):對於同一個客戶端(例如 Chrome 瀏覽器),只要登錄了一個子站(例如 a.com),則所有子站(b.com、c.com)都認為已經登錄。
比如用戶在登錄淘寶後,跳轉到天貓時就已經登錄了。
用例步驟
未登錄用戶訪問子站 a.com 進行登錄,自動跳轉到賬戶中心的統一登錄頁 account.com/login
用戶在統一登錄頁進行登錄,登錄成功後顯示登錄跳轉頁
顯示登錄跳轉頁後自動跳轉回 a.com,單點登錄完成
用戶在訪問 b.com 時無需再次登錄
- 1
- 2
- 3
- 4
- 5
通過redis緩存和cookie實現單點登錄
整體實現思路如下圖所示。
Session的緩存機制
1.業務系統發起登錄請求,調用SSO用戶登錄介面;
2.SSO登錄介面的處理邏輯:
2.1 根據用戶名和密碼去資料庫驗證用戶是否合法。
2.2 用戶驗證通過之後,生成SessionID,並返回給業務系統。
同時以SessionID為key,存儲用戶信息到redis緩存中
- 1
- 2
- 3
SSO登錄介面代碼:
public JSONObject userLogin(@RequestBody JSONObject jsonObject){
UserLoginResponse userLoginResponss = new UserLoginResponse();
try {
logger.info("處理用戶登錄業務邏輯,接收報文"+jsonObject);
String msgWithDigesta=SecurityUtil.scfMatch(jsonObject.toString(), newXService.getPrivateKey());
//生成實體
User user = JSONObject.parseObject(msgWithDigesta,User.class);
//是否驗證用戶的密碼
boolean isChechPassword = true;
User userInfo = anaService.loginCheckUserInfo(user,isChechPassword);
// 存儲用戶信息到redis緩存中
String ticket = anaService.storeUserLoginSessionInRedis(userInfo,user.getModuleCode());
userLoginResponss.setRetCode(RetCode.LOGIN_SUCCESS.getCode());
userLoginResponss.setRetMessage("用戶登錄成功");
userLoginResponss.setTicket(ticket);
userLoginResponss.setStatus(userInfo.getStatus());
userLoginResponss.setIsModifyPassword(userInfo.getIsModifyPassword());
} catch (Exception e) {
userLoginResponss.setRetCode(RetCode.LOGIN_FAILED.getCode());
userLoginResponss.setRetMessage(e.getMessage());
logger.info("插入用戶數據到表中失敗,原因:"+e.getMessage());
}
logger.info("返回處理用戶登錄業務邏輯結果,Result{[]}"+JSONObject.toJSONString(userLoginResponss));
return JSON.parseObject(JSONObject.toJSONString(userLoginResponss));
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
存儲用戶信息到redis緩存的代碼:
/**
* 存儲用戶登錄session信息到redis中
* @param userInfo
* @return
*/
public String storeUserLoginSessionInRedis(User userInfo,String moduleCode) {
// 存儲用戶ticket信息
// 使用AES加密登錄用戶ID生成SessionID,加密密碼是配置文件里定義的64位字元串
String sessionId = AesUtil.encrypt(String.valueOf(userInfo.getUserId()), newXService.getBizkey());
String unique_ticket = userInfo.getSystemId()+sessionId+"_USER_LOGIN";
//
String ticket = userInfo.getSystemId()+sessionId+System.currentTimeMillis()+"_USER_LOGIN";
UserLoginSession userLoginSession = new UserLoginSession();
userLoginSession.setUserId(String.valueOf(userInfo.getUserId()));
userLoginSession.setUserName(userInfo.getUserName());
userLoginSession.setUserLoginName(userInfo.getUserLoginName());
// 獲取許可權
List<Permission> permissions = getUserPermissions(userInfo.getUserId());
userLoginSession.setPermissions(permissions);
userLoginSession.setModuleCode(StringUtils.killNull(userInfo.getModuleCode()));
userLoginSession.setLastLoginTime(userInfo.getLastLoginTime());
userLoginSession.seteId(StringUtils.killNull(userInfo.geteId()));
userLoginSession.setSessionId(ticket);
userLoginSession.setUserInfo(userInfo);
//限制唯一登錄,刪除上一個用戶信息
if (redisService.exists(unique_ticket))
redisService.del(redisService.get(unique_ticket));
redisService.set(unique_ticket, ticket);
logger.info("訪問AnaController的login方法:放進redis"+ticket);
redisService.setKeyExpire((ticket).getBytes(),1800);
logger.info("userloginsession result ="+JSONObject.toJSONString(userLoginSession));
return ticket;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
3.業務系統將返回的sessionID,存放到cookie里
業務系統controller的代碼:
@RequestMapping("/login.ajax")
@ResponseBody
public Map<String, Object> login(@RequestParam("username2") String username2,
@RequestParam("moduleCode2") String moduleCode2,
@RequestParam("password2") String password2, String requestUrl, HttpServletResponse response) {
// 其他業務邏輯省略
String sessionId = userBySso.getTicket();
Cookie cookie = new Cookie("CORE_SESSION", sessionId);
cookie.setPath("/");
response.addCookie(cookie);
// 其他業務邏輯省略
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4.業務系統取得Session信息,並檢驗用戶信息
業務系統的頁面發起web請求時,在自定義攔截器(繼承自HandlerInterceptor)的preHandle方法里取得session信息,並檢查用戶是否登錄。
Session信息取得時,首先從cookie中取得SessionId,然後根據SessionId從redis取得用戶信息
自定義攔截器的代碼此處省略,請參照【SpringMVC學習筆記2_攔截器實現登錄驗證】,以下是取得session信息的代碼
public UserLoginSession getUserLoginSession(HttpServletRequest req) {
logger.info("訪問getUserLoginSession");
String sessionId = "";
Cookie[] cookie = req.getCookies();
if (cookie == null) {
return null;
}
for (int i = 0; i < cookie.length; i++) {
Cookie cook = cookie[i];
if (cook.getName().equals("CORE_SESSION")) {
sessionId = cook.getValue().toString();
}
}
logger.info("訪問getUserLoginSession獲取sessionId: " + sessionId);
if ("".equals(sessionId)) {
return null;
}
String UserLoginSessionStr = redisService.get(sessionId);
logger.info("訪問getUserLoginSession獲取USERLOGINSESSION: " + UserLoginSessionStr);
if (null == UserLoginSessionStr || "".equals(UserLoginSessionStr)) {
return null;
}
UserLoginSession userLoginSession = (UserLoginSession) JSONObject.toJavaObject(JSONObject.parseObject(UserLoginSessionStr), UserLoginSession.class);
logger.info("訪問getUserLoginSession獲取USER_ID成功: " + userLoginSession.getUserId());
redisService.setKeyExpire((sessionId).getBytes(), 1800);
redisService.setKeyExpire((userLoginSession.getTicketRole()).getBytes(),1800);
return userLoginSession;
}


※我是如何從煤礦工成為程序員的
※TensorFlow中的所有模型
TAG:程序員小新人學習 |