SpringBoot+SpringSession+Redis实现session共享及唯一登录示例

网友投稿 1232 2023-01-24

SpringBoot+SpringSession+Redis实现session共享及唯一登录示例

SpringBoot+SpringSession+Redis实现session共享及唯一登录示例

最近在学习springboot,session这个点一直困扰了我好久,今天把这些天踩的坑分享出来吧,希望能帮助更多的人。

一、pom.xml配置

org.springframework.boot</groupId>

spring-boot-starter-data-redis

org.springframework.session

spring-session-data-redis

二、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

#超时一定要大于0

spring.redis.timeout=3000

spring.session.store-type=redis

在配置redis时需要确保redis安装正确,并且配置notify-keyspace-events Egx,spring.redis.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 = 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, "", "用户未登录!")));

}

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开头的访问都要进入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 = 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, "账kxrwu户名或密码错误!");

}

}

@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 = request.getSession();

session.setAttribute("loginUserId", user.getUserId());

redisTemplate.opsForValue().set("loginUser:" + user.getUserId(), session.getId());

2、访问接口时,会在RedisSessionInterceptor-中的preHandle()中捕获,然后根据该请求发起者的session中保存的userId去redis查当前已登录的sessionId,若查到的sessionId与访问者的sessionId相等,那么说明请求合法,放行。否则抛出401异常给全局异常捕获器去返回给客户端401状态。

唯一登录经过我的验证后满足需求,暂时没有出现问题,也希望大家能看看有没有问题,有的话给我点好的建议!

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot+SpringCache实现两级缓存(Redis+Caffeine)
下一篇:混合app开发要几个人(开发一个混合app)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~