拦截器整合Redis实现登陆安全方案
-
首先系统中任何部分不存在用户token
-
登陆时使用jwt产生非对称加密的token,将用户基础信息Map存储到token的payload中,随后将用户的详细信息存储到redis中,数据结构为: “用户id” :“用户详细信息(Hash)”
//非对称token(默认6小时过期) HashMap<String, String> userTokenMap = new HashMap<>(); userTokenMap.put("username", user.getUsername()); userTokenMap.put("userId", user.getId().toString()); String token = JWTAuth0Util.genTokenRAS(userTokenMap); /** * 创建token方法,时间设置为6小时 * 根据RSA算法加密生成token【非对称】 * @param payload * @return */ public static String genTokenRAS(Map<String, String> payload){ //指定过期时间 【6小时】 Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.HOUR, 2); //获取一个构建对象【静态内部类】 JWTCreator.Builder builder = JWT.create(); //将信息、数据(body)信息放到需要的claim里面 payload.forEach((k, v) -> builder.withClaim(k, v)); //通过hutool工具类来创建RSA对象 RSA rsa = new RSA(PRIVATE_KEY_STR, null); //获取私钥 RSAPrivateKey privateKey = (RSAPrivateKey) rsa.getPrivateKey(); String token = builder.withExpiresAt(calendar.getTime()).sign(Algorithm.RSA256(null, privateKey)); return token; }
-
并将用户的token返回到前端,每次前端请求会将token发送到后端,后端每次接收到请求后,会在拦截器中进行拦截判断,此时进行逻辑判断:
jwt有效时间:6小时;
redis中key有效时间:6小时;
这个地方会涉及到双重验证,
此时通过redisTemplate向redis服务器检查redis是否存在token中我们解密payload中的userId,若存在,证明登陆状态并放行,否则将拦截。
public class MyInterceptor implements HandlerInterceptor { @Autowired private RedisTemplate<String, Object> redisTemplate; @Override public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, Object handler) throws Exception { String authorization = request.getHeader("token"); String userId = ""; try { userId = JWTAuth0Util.decodedRSA(authorization).getClaim("userId").asString(); } catch (Exception e) { throw new RuntimeException(e); } return Objects.equals(redisTemplate.hasKey(userId),Boolean.TRUE); } } }