springboot filter redis 实现sso单点登录

家电修理 2023-07-16 19:16www.caominkang.com电器维修

这个单点登录会存在的问题token过期无法刷新token,只能重新登录。但只要把过期时间设置大点,如8小时,用户超过8小时都没调用过接口,那么token才会被删除,则基本上不会有什么问题。

思路

  1. 登录时返回token和用户权限信息给前端。
  2. 前端每次访问接口都需要请求头携带token。
  3. 后端filter过滤器拦截请求,把请求头没有携带token的请求给拦截(登录等接口设置白名单不拦截)
  4. 把校验通过的token,通过redis的expire重新设置过期时间。

Redis配置

import .fasterxml.jackson.annotation.JsonAutoDetect;
import .fasterxml.jackson.annotation.PropertyAessor;
import .fasterxml.jackson.databind.ObjectMapper;
import .springframeork.context.annotation.Bean;
import .springframeork.context.annotation.Configuration;
import .springframeork.data.redis.connection.lettuce.LettuceConnectionFactory;
import .springframeork.data.redis.core.RedisTemplate;
import .springframeork.data.redis.serializer.Jackson2JsonRedisSerializer;
import .springframeork.data.redis.serializer.RedisSerializer;
import .springframeork.data.redis.serializer.StringRedisSerializer;


@Configuration
public class RedisConfig {
 
 @Bean(name="redisTemplate")
 public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
  // 设置序列化
  Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = ne Jackson2JsonRedisSerializer<>(Object.class);
  ObjectMapper om = ne ObjectMapper();
  om.setVisibility(PropertyAessor.ALL, JsonAutoDetect.Visibility.ANY);
  om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  jackson2JsonRedisSerializer.setObjectMapper(om);
  // 配置redisTemplate
  RedisTemplate redisTemplate = ne RedisTemplate<>();
  redisTemplate.setConnectionFactory(lettuceConnectionFactory);
  RedisSerializer stringSerializer = ne StringRedisSerializer();
  // key序列化
  redisTemplate.setKeySerializer(stringSerializer);
  // value序列化,可序列化对象
  redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
  // Hash key序列化
  redisTemplate.setHashKeySerializer(stringSerializer);
  // Hash value序列化,可序列化对象
  redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
  redisTemplate.afterPropertiesSet();
  return redisTemplate;
 }
}
 

登录接口

	@Value("${token-overtime}")
 private int tokenOvertime;//在配置文件设置token过期时间,方便修改
 @Resource
 RedisTemplate redisTemplate;
 @Resource
 LoginMapper loginMapper;
 
	
 @PostMapping("login")
 public TokenInfo login(@RequestParam Long userId, @RequestParam String passord){
  User user = loginMapper.checkUserId(userId);
  if (user == null) {
   thro ne Err("用户不存在");
  } else if (!RSAUtil.decrypt(passord.replaceAll(" ", "+"), user.getPrivateKey()).equals(user.getPassord())) {
   thro ne Err("密码错误");
  } else {
   //把当前登录用户的信息存储到redis并返回给前端
   String token = UUID.randomUUID().toString();
   List roles = loginMapper.selectUserRoles(user.getId());//角色组
   TokenInfo tokenInfo = ne TokenInfo(token,user.getId(),user.getName(),loginMapper.selectUserDepts(user.getId()),roles,roles.size() <= 0 ? null:loginMapper.selectUserMenus(roles));
   redisTemplate.opsForValue().set(token,tokenInfo,tokenOvertime, TimeUnit.SECONDS);//把当前登录用户的信息存储到redis并设置过期时间
   return tokenInfo;
  }
 }

token、userId、userName必须返回给前端,其它权限等自由调配。

前端拿到token以后把token放到请求头,请求后端接口时携带请求头访问后端接口。

前端请求头携带正确的token访问后端hello接口,filter过滤器会进行拦截,合法的token才运行访问hello。

@Component
@WebFilter(urlPatterns = "
 @PostMapping("logout")
 public String logout(@RequestParam String token){
  if (StringUtils.isBlank(token)){
   thro ne Err("token不能为空");
  }else if (redisTemplate.hasKey(token)){
   thro ne Err("token不存在");
  }else {
   redisTemplate.delete(token);//删除redis的key,key就是token
   return "登出成功!";
  }
 }

Copyright © 2016-2025 www.caominkang.com 曹敏电脑维修网 版权所有 Power by