SpringBoot+SpringSession+Redis實(shí)現(xiàn)session共享及唯一登錄示例
最近在學(xué)習(xí)springboot,session這個(gè)點(diǎn)一直困擾了我好久,今天把這些天踩的坑分享出來(lái)吧,希望能幫助更多的人。
一、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í)啟不起來(lái)。
三、編寫(xiě)登錄狀態(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
{
//無(wú)論訪問(wèn)的地址是不是正確的,都進(jìn)行登錄驗(yàn)證,登錄成功后的訪問(wèn)再進(jìn)行分發(fā),404的訪問(wèn)自然會(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開(kāi)頭的訪問(wèn)都要進(jìn)入RedisSessionInterceptor攔截器進(jìn)行登錄驗(yàn)證,并排除login接口(全路徑)。必須寫(xiě)成鏈?zhǔn)?,分別設(shè)置的話會(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, "賬戶名或密碼錯(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過(guò)期時(shí)間(秒)
@Configuration
public class RedisSessionConfig
{
@Bean
public static ConfigureRedisAction configureRedisAction()
{
//讓springSession不再執(zhí)行config命令
return ConfigureRedisAction.NO_OP;
}
}
springboot啟動(dòng)后能在redis上查到緩存的session才能說(shuō)明整個(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、訪問(wèn)接口時(shí),會(huì)在RedisSessionInterceptor攔截器中的preHandle()中捕獲,然后根據(jù)該請(qǐng)求發(fā)起者的session中保存的userId去redis查當(dāng)前已登錄的sessionId,若查到的sessionId與訪問(wèn)者的sessionId相等,那么說(shuō)明請(qǐng)求合法,放行。否則拋出401異常給全局異常捕獲器去返回給客戶端401狀態(tài)。
唯一登錄經(jīng)過(guò)我的驗(yàn)證后滿足需求,暫時(shí)沒(méi)有出現(xiàn)問(wèn)題,也希望大家能看看有沒(méi)有問(wèn)題,有的話給我點(diǎn)好的建議!
到此這篇關(guān)于SpringBoot+SpringSession+Redis實(shí)現(xiàn)session共享及唯一登錄示例的文章就介紹到這了,更多相關(guān)SpringBoot 唯一登錄內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息
這篇文章主要介紹了Spring Boot中使用Actuator的/info端點(diǎn)輸出Git版本信息,需要的朋友可以參考下2017-06-06
Java中的強(qiáng)引用,軟引用,弱引用,虛引用的作用介紹
這篇文章主要介紹了Java中的強(qiáng)引用,軟引用,弱引用,虛引用的作用,下文內(nèi)容具有一定的知識(shí)參考價(jià)值,需要的小伙伴可以參考一下,希望對(duì)你有所幫助2022-02-02
使用java項(xiàng)目搭建一個(gè)netty服務(wù)
這篇文章主要為大家詳細(xì)介紹了如何使用java項(xiàng)目搭建一個(gè)netty服務(wù),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-10-10
SpringBoot中實(shí)現(xiàn)接收文件和對(duì)象
這篇文章主要介紹了SpringBoot實(shí)現(xiàn)接收文件和對(duì)象,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
java 獲取數(shù)據(jù)庫(kù)連接的實(shí)現(xiàn)代碼
本篇文章是對(duì)在java中獲取數(shù)據(jù)庫(kù)連接的實(shí)現(xiàn)代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
詳解spring mvc對(duì)異步請(qǐng)求的處理
spring mvc3.2及以上版本增加了對(duì)請(qǐng)求的異步處理,是在servlet3的基礎(chǔ)上進(jìn)行封裝的,有興趣的可以了解一下。2017-01-01
淺談JSP與Servlet傳值及對(duì)比(總結(jié))
下面小編就為大家?guī)?lái)一篇淺談JSP與Servlet傳值及對(duì)比(總結(jié))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
解決idea 通過(guò)build project 手動(dòng)觸發(fā)熱部署失敗的問(wèn)題
在debug運(yùn)行項(xiàng)目的過(guò)程中,并且保證(不添加方法,不修改方法名)一定的規(guī)則的情況下,可以通過(guò)build project 來(lái)手動(dòng)熱部署項(xiàng)目,本文給大家介紹解決idea 通過(guò)build project 手動(dòng)觸發(fā)熱部署失敗的問(wèn)題,感興趣的朋友一起看看吧2023-12-12

