导入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- 连接池--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
application.yml中redis配置
redis: database: 0 # Redis服务器地址 写你的ip host: 182.92.***.** # Redis服务器连接端口 port: 6379 # Redis服务器连接密码(默认为空) password: # jedis连接池最大连接数(使用负值表示没有限制 类似于mysql的连接池 jedis: pool: #最大连接数 max-active: 200 # 连接池最大阻塞等待时间(使用负值表示没有限制) 表示连接池的链接拿完了 现在去申请需要等待的时间 max-wait: -1 # 连接池中的最大空闲连接 max-idle: 10 # 连接池中的最小空闲连接 min-idle: 0 # 连接超时时间(毫秒) 去链接redis服务端 timeout: 6000
模拟手机号验证码登录
//获取验证码 @GetMapping("/getcode") public Result code(@RequestParam("phone") String phone, HttpServletRequest request){ String PHONE_REGEX = "13[0-9]\\d{8}|15[1089]\\d{8}";//手机号正则 if(!phone.matches(PHONE_REGEX)){ return Result.error("403","手机号格式错误"); } String s = RandomUtil.randomNumbers(6); // HttpSession session = request.getSession(true); // session.setAttribute("code"+phone,s); redisTemplate.opsForValue().set(phone+"code",s,2, TimeUnit.MINUTES); log.info("发送的验证码为"+s); return Result.success(); } //登录 @GetMapping("/login") public Result login(String phone,String code){ String code1 = (String)redisTemplate.opsForValue().get(phone + "code"); if(!code.equals(code1)){ return Result.error("403","手机验证码错误"); } TbUser tbUser = tbUserMapper.selectOneByPhone(phone); String token = JwtUtil.generateToken(tbUser.getId()); redisTemplate.opsForValue().set(String.valueOf(tbUser.getId()),tbUser,30,TimeUnit.MINUTES); return Result.success(token); }
配置拦截器
public class LoginInterceptor implements HandlerInterceptor { @Autowired RedisTemplate redisTemplate; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(request.getMethod().equals("OPTIONS")) return true; // if(!(handler instanceof HandlerMethod)) //return true; String token = request.getHeader("token"); System.out.println(token); if(token==null) throw new Exception("无token,请重新登陆"); DecodedJWT decodedJWT = JwtUtil.decodeToken(token); Long userId = decodedJWT.getClaim("userId").asLong(); System.out.println(userId); TbUser s = (TbUser) redisTemplate.opsForValue().get(String.valueOf(userId)); if(s==null){ throw new Exception("用户不存在"); } return true; } }
@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Bean public LoginInterceptor loginInterceptor(){ return new LoginInterceptor(); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor()) .addPathPatterns("/**") .excludePathPatterns("/login") .excludePathPatterns("/getcode"); } }
注:这里要将LoginInterceptor生成Bean,因为使用到@Autowired注解,如果不配置成bean,Spring容器就无法扫描到这个拦截器,里面使用的RedisTemplate就无法自动装配。然后导致各类错误。
if(request.getMethod().equals("OPTIONS"))
return true;
上面这行代码在前后端分离中必不可少,cors跨域复杂请求会先发送一个方法为OPTIONS的预检请求,这个请求是用来验证本次请求是否安全的, 拦截器判断token时会把预请求当做真正的请求去判断,所有拦截器要放行预请求,不然这个代码在运行的时候就会抛异常。
另外在代码运行过程中在拦截器中出现错误打印出多个异常信息是什么原因呢?经过资料的查询,当在拦截器中出现异常后会有一个error请求,然后又被拦截器给拦截了,这会导致打印出多个异常信息。具体的有关这个拦截器这方面描述可以参考文章
SpringBoot下自定义拦截器preHandle方法执行多次原因分析 - 爱码网