SpringBoot+SpringSession+Redis实现session共享及唯⼀登录⽰例最近在学习springboot,session这个点⼀直困扰了我好久,今天把这些天踩的坑分享出来吧,希望能帮助更多的⼈。
⼀、l配置
<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
#超时⼀定要⼤于0
spring.session.store-type=redis
在配置redis时需要确保redis安装正确,并且配置notify-keyspace-events Egx,dis.timeout设置为⼤于0,我当时这⾥配置为0时springboot时启不起来。
三、编写登录状态RedisSessionInterceptor
//拦截登录失效的请求
public class RedisSessionInterceptor implements HandlerInterceptor
{
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
{
//⽆论访问的地址是不是正确的,都进⾏登录验证,登录成功后的访问再进⾏分发,404的访问⾃然会进⼊到错误控制器中
HttpSession session = Session();
if (Attribute("loginUserId") != null)
{
try
{
//验证当前请求的session是否是已登录的session
String loginSessionId = redisTemplate.opsForValue().get("loginUser:" + (long) Attribute("loginUserId"));
if (loginSessionId != null && loginSessionId.Id()))
{
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
{
}
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
springboot和过滤器public class WebSecurityConfig extends WebMvcConfigurerAdapter
{
@Bean
public RedisSessionInterceptor getSessionInterceptor()
{
return new RedisSessionInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry)
{
//所有已api开头的访问都要进⼊RedisSessionInterceptor进⾏登录验证,并排除login接⼝(全路径)。必须写成链式,分别设置的话会创建多个。
//必须写成getSessionInterceptor(),否则SessionInterceptor中的@Autowired会⽆效
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 = Session();
session.setAttribute("loginUserId", UserId());
redisTemplate.opsForValue().set("loginUser:" + UserId(), Id());
return new ReturnData(StatusCode.REQUEST_SUCCESS, user, "登录成功!");
}
else
{
throw new MyException(StatusCode.ACCOUNT_OR_PASSWORD_ERROR, "账户名或密码错误!");
}
}
@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上登录相同的账号,浏览器再获取⽤户信息,就会提⽰401错误了,浏览器需要重新登录才能获取得到⽤户信息,同样,postman上登录的账号就失效了。
浏览器:
postman:
七、核⼼原理详解
分布式session需要解决两个难点:1、正确配置redis让springboot把session托管到redis服务器。2、唯⼀登录。
1、redis:
redis需要能正确启动到出现如下效果才证明redis正常配置并启动
同时还要保证配置正确
@EnableCaching
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 30)//session过期时间(秒)
@Configuration
public class RedisSessionConfig
{
@Bean
public static ConfigureRedisAction configureRedisAction()
{
//让springSession不再执⾏config命令
return ConfigureRedisAction.NO_OP;
}
}
springboot启动后能在redis上查到缓存的session才能说明整个redis+springboot配置成功!
2、唯⼀登录:
1、⽤户登录时,在redis中记录该userId对应的sessionId,并将userId保存到session中。
HttpSession session = Session();
session.setAttribute("loginUserId", UserId());
redisTemplate.opsForValue().set("loginUser:" + UserId(), Id());
2、访问接⼝时,会在RedisSessionInterceptor中的preHandle()中捕获,然后根据该请求发起者的session中保存的userId去redis查当前已登录的sessionId,若查到的sessionId与访问者的sessionId相等,那么说明请求合法,放⾏。否则抛出401异常给全局异常捕获器去返回给客户端401状态。
唯⼀登录经过我的验证后满⾜需求,暂时没有出现问题,也希望⼤家能看看有没有问题,有的话给我点
好的建议!
到此这篇关于SpringBoot+SpringSession+Redis实现session共享及唯⼀登录⽰例的⽂章就介绍到这了,更多相关SpringBoot 唯⼀登录内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论