SpringBoot+SpringSession+Redis實(shí)現(xiàn)session共享及唯一登錄示例
最近在學(xué)習(xí)springboot,session這個(gè)點(diǎn)一直困擾了我好久,今天把這些天踩的坑分享出來吧,希望能幫助更多的人。
一、pom.xml配置
<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>
二、application.properties的redis配置
#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設(shè)置為大于0,我當(dāng)時(shí)這里配置為0時(shí)springboot時(shí)啟不起來。
三、編寫登錄狀態(tài)攔截器RedisSessionInterceptor
//攔截登錄失效的請(qǐng)求 public class RedisSessionInterceptor implements HandlerInterceptor { @Autowired private StringRedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //無論訪問的地址是不是正確的,都進(jìn)行登錄驗(yàn)證,登錄成功后的訪問再進(jìn)行分發(fā),404的訪問自然會(huì)進(jìn)入到錯(cuò)誤控制器中 HttpSession session = request.getSession(); if (session.getAttribute("loginUserId") != null) { try { //驗(yàn)證當(dāng)前請(qǐng)求的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, "", "用戶未登錄!"))); } 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) { //所有已a(bǔ)pi開頭的訪問都要進(jìn)入RedisSessionInterceptor攔截器進(jìn)行登錄驗(yàn)證,并排除login接口(全路徑)。必須寫成鏈?zhǔn)剑謩e設(shè)置的話會(huì)創(chuàng)建多個(gè)攔截器。 //必須寫成getSessionInterceptor(),否則SessionInterceptor中的@Autowired會(huì)無效 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, "賬戶名或密碼錯(cuò)誤!"); } } @RequestMapping(value = "/getUserInfo") public ReturnData get(long userId) { User user = userService.findUserByUserId(userId); if (user != null) { return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "查詢成功!"); } else { throw new MyException(StatusCode.USER_NOT_EXIST, "用戶不存在!"); } } }
六、效果
我在瀏覽器上登錄,然后獲取用戶信息,再在postman上登錄相同的賬號(hào),瀏覽器再獲取用戶信息,就會(huì)提示401錯(cuò)誤了,瀏覽器需要重新登錄才能獲取得到用戶信息,同樣,postman上登錄的賬號(hào)就失效了。
瀏覽器:
postman:
七、核心原理詳解
分布式session需要解決兩個(gè)難點(diǎn):1、正確配置redis讓springboot把session托管到redis服務(wù)器。2、唯一登錄。
1、redis:
redis需要能正確啟動(dòng)到出現(xiàn)如下效果才證明redis正常配置并啟動(dòng)
同時(shí)還要保證配置正確
@EnableCaching @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)//session過期時(shí)間(秒) @Configuration public class RedisSessionConfig { @Bean public static ConfigureRedisAction configureRedisAction() { //讓springSession不再執(zhí)行config命令 return ConfigureRedisAction.NO_OP; } }
springboot啟動(dòng)后能在redis上查到緩存的session才能說明整個(gè)redis+springboot配置成功!
2、唯一登錄:
1、用戶登錄時(shí),在redis中記錄該userId對(duì)應(yīng)的sessionId,并將userId保存到session中。
HttpSession session = request.getSession(); session.setAttribute("loginUserId", user.getUserId()); redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId());
2、訪問接口時(shí),會(huì)在RedisSessionInterceptor攔截器中的preHandle()中捕獲,然后根據(jù)該請(qǐng)求發(fā)起者的session中保存的userId去redis查當(dāng)前已登錄的sessionId,若查到的sessionId與訪問者的sessionId相等,那么說明請(qǐng)求合法,放行。否則拋出401異常給全局異常捕獲器去返回給客戶端401狀態(tài)。
唯一登錄經(jīng)過我的驗(yàn)證后滿足需求,暫時(shí)沒有出現(xiàn)問題,也希望大家能看看有沒有問題,有的話給我點(diǎn)好的建議!
到此這篇關(guān)于SpringBoot+SpringSession+Redis實(shí)現(xiàn)session共享及唯一登錄示例的文章就介紹到這了,更多相關(guān)SpringBoot 唯一登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java將字符串String轉(zhuǎn)換為整型Int的兩種方式
這篇文章主要介紹了Java如何將字符串String轉(zhuǎn)換為整型Int,在 Java 中要將 String 類型轉(zhuǎn)化為 int 類型時(shí),需要使用 Integer 類中的 parseInt() 方法或者 valueOf() 方法進(jìn)行轉(zhuǎn)換,本文通過實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下2023-04-04J2SE基礎(chǔ)之在Eclipse中運(yùn)行hello world
本文的內(nèi)容非常的簡(jiǎn)單,跟隨世界潮流,第一個(gè)Java程序輸出“Hell World!”。希望大家能夠喜歡2016-05-05Java?Http請(qǐng)求方式之RestTemplate常用方法詳解
這篇文章主要為大家介紹了Java?Http請(qǐng)求方式之RestTemplate常用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09springboot中的springSession的存儲(chǔ)和獲取實(shí)現(xiàn)
這篇文章主要介紹了springboot中的springSession的存儲(chǔ)和獲取實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09Bean的管理與SpringBoot自動(dòng)裝配原理解讀
在SpringBoot項(xiàng)目中,啟動(dòng)時(shí)自動(dòng)創(chuàng)建IOC容器并初始化bean對(duì)象,支持通過依賴注入獲取,Bean可以通過name或類型獲取,支持單例和非單例等多種作用域,對(duì)于第三方Bean,推薦在配置類中用@Bean標(biāo)識(shí)方法進(jìn)行定義2024-11-11idea微服務(wù)項(xiàng)目服務(wù)如何顯示在同一窗口
本文介紹了如何在微服務(wù)項(xiàng)目導(dǎo)入時(shí)將所有服務(wù)加入同一窗口中,解決啟動(dòng)項(xiàng)目服務(wù)時(shí)顯示不全的問題,通過點(diǎn)擊左上角的View,選擇ToolWindows,然后選擇Services,使用快捷鍵Alt+8,選擇Spring Boot,就可以將所有服務(wù)加到同一窗口中2025-02-02提高開發(fā)效率Live?Templates使用技巧詳解
這篇文章主要為大家介紹了提高開發(fā)效率Live?Templates使用技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01