这个单点登录会存在的问题:token过期无法刷新token,只能重新登录。但只要把过期时间设置大点,如8小时,用户超过8小时都没调用过接口,那么token才会被删除,则基本上不会有什么问题。
思路:
- 登录时返回token和用户权限信息给前端。
- 前端每次访问接口都需要请求头携带token。
- 后端filter过滤器拦截请求,把请求头没有携带token的请求给拦截(登录等接口设置白名单不拦截)
- 把校验通过的token,通过redis的expire重新设置过期时间。
Redis配置
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
@Bean(name="redisTemplate")
public RedisTemplate redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
// 设置序列化
Jackson2JsonRedisSerializer
登录接口
@Value("${token-overtime}")
private int tokenOvertime;//在配置文件设置token过期时间,方便修改
@Resource
RedisTemplate redisTemplate;
@Resource
LoginMapper loginMapper;
@PostMapping("login")
public TokenInfo login(@RequestParam Long userId, @RequestParam String password){
User user = loginMapper.checkUserId(userId);
if (user == null) {
throw new Err("用户不存在");
} else if (!RSAUtil.decrypt(password.replaceAll(" ", "+"), user.getPrivateKey()).equals(user.getPassword())) {
throw new Err("密码错误");
} else {
//把当前登录用户的信息存储到redis并返回给前端
String token = UUID.randomUUID().toString();
List roles = loginMapper.selectUserRoles(user.getId());//角色组
TokenInfo tokenInfo = new 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)){
throw new Err("token不能为空");
}else if (redisTemplate.hasKey(token)){
throw new Err("token不存在");
}else {
redisTemplate.delete(token);//删除redis的key,key就是token
return "登出成功!";
}
}



