- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- SpringBoot+SpringSession+Redis實(shí)現session共享及唯一登錄
最近在學(xué)習springboot,session這個(gè)點(diǎn)一直困擾了我好久,今天把這些天踩的坑分享出來(lái)吧,希望能幫助更多的人。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.session</groupId> <artifactId>spring-session-data-redis</artifactId> </dependency>
#redis spring.redis.host=127.0.0.1 spring.redis.port=6379 spring.redis.password=123456 spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 #超時(shí)一定要大于0 spring.redis.timeout=3000 spring.session.store-type=redis
在配置redis時(shí)需要確保redis安裝正確,并且配置notify-keyspace-events Egx,spring.redis.timeout設置為大于0,我當時(shí)這里配置為0時(shí)springboot時(shí)啟不起來(lái)。
//攔截登錄失效的請求 public class RedisSessionInterceptor implements HandlerInterceptor { @Autowired private StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //無(wú)論訪(fǎng)問(wèn)的地址是不是正確的,都進(jìn)行登錄驗證,登錄成功后的訪(fǎng)問(wèn)再進(jìn)行分發(fā),404的訪(fǎng)問(wèn)自然會(huì )進(jìn)入到錯誤控制器中 HttpSession session = request.getSession(); if (session.getAttribute("loginUserId") != null) { try { //驗證當前請求的session是否是已登錄的session String loginSessionId = redisTemplate.opsForValue().get("loginUser:" + (long) session.getAttribute("loginUserId")); if (loginSessionId != null && loginSessionId.equals(session.getId())) { return true; } } catch (Exception e) { e.printStackTrace(); } } response401(response); return false; } private void response401(HttpServletResponse response) { response.setCharacterEncoding("UTF-8"); response.setContentType("application/json; charset=utf-8"); try { response.getWriter().print(JSON.toJSONString(new ReturnData(StatusCode.NEED_LOGIN, "", "用戶(hù)未登錄!"))); } catch (IOException e) { e.printStackTrace(); } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
@Configuration public class WebSecurityConfig extends WebMvcConfigurerAdapter { @Bean public RedisSessionInterceptor getSessionInterceptor() { return new RedisSessionInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { //所有已api開(kāi)頭的訪(fǎng)問(wèn)都要進(jìn)入RedisSessionInterceptor攔截器進(jìn)行登錄驗證,并排除login接口(全路徑)。必須寫(xiě)成鏈式,分別設置的話(huà)會(huì )創(chuàng )建多個(gè)攔截器。 //必須寫(xiě)成getSessionInterceptor(),否則SessionInterceptor中的@Autowired會(huì )無(wú)效 registry.addInterceptor(getSessionInterceptor()).addPathPatterns("/api/**").excludePathPatterns("/api/user/login"); super.addInterceptors(registry); } }
@RestController @RequestMapping(value = "/api/user") public class LoginController { @Autowired private UserService userService; @Autowired private StringRedisTemplate redisTemplate; @RequestMapping("/login") public ReturnData login(HttpServletRequest request, String account, String password) { User user = userService.findUserByAccountAndPassword(account, password); if (user != null) { HttpSession session = request.getSession(); session.setAttribute("loginUserId", user.getUserId()); redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId()); return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "登錄成功!"); } else { throw new MyException(StatusCode.ACCOUNT_OR_PASSWORD_ERROR, "賬戶(hù)名或密碼錯誤!"); } } @RequestMapping(value = "/getUserInfo") public ReturnData get(long userId) { User user = userService.findUserByUserId(userId); if (user != null) { return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "查詢(xún)成功!"); } else { throw new MyException(StatusCode.USER_NOT_EXIST, "用戶(hù)不存在!"); } } }
我在瀏覽器上登錄,然后獲取用戶(hù)信息,再在postman上登錄相同的賬號,瀏覽器再獲取用戶(hù)信息,就會(huì )提示401錯誤了,瀏覽器需要重新登錄才能獲取得到用戶(hù)信息,同樣,postman上登錄的賬號就失效了。
瀏覽器:
postman:
分布式session需要解決兩個(gè)難點(diǎn):1、正確配置redis讓springboot把session托管到redis服務(wù)器。2、唯一登錄。
redis需要能正確啟動(dòng)到出現如下效果才證明redis正常配置并啟動(dòng)
同時(shí)還要保證配置正確
@EnableCaching @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)//session過(guò)期時(shí)間(秒) @Configuration public class RedisSessionConfig { @Bean public static ConfigureRedisAction configureRedisAction() { //讓springSession不再執行config命令 return ConfigureRedisAction.NO_OP; } }
springboot啟動(dòng)后能在redis上查到緩存的session才能說(shuō)明整個(gè)redis+springboot配置成功!
1、用戶(hù)登錄時(shí),在redis中記錄該userId對應的sessionId,并將userId保存到session中。
HttpSession session = request.getSession(); session.setAttribute("loginUserId", user.getUserId()); redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId());
2、訪(fǎng)問(wèn)接口時(shí),會(huì )在RedisSessionInterceptor攔截器中的preHandle()中捕獲,然后根據該請求發(fā)起者的session中保存的userId去redis查當前已登錄的sessionId,若查到的sessionId與訪(fǎng)問(wèn)者的sessionId相等,那么說(shuō)明請求合法,放行。否則拋出401異常給全局異常捕獲器去返回給客戶(hù)端401狀態(tài)。
唯一登錄經(jīng)過(guò)我的驗證后滿(mǎn)足需求,暫時(shí)沒(méi)有出現問(wèn)題,也希望大家能看看有沒(méi)有問(wèn)題,有的話(huà)給我點(diǎn)好的建議!
到此這篇關(guān)于SpringBoot+SpringSession+Redis實(shí)現session共享及唯一登錄示例的文章就介紹到這了,更多相關(guān)SpringBoot 唯一登錄內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站