注解实现接口鉴权和防刷限制
项目中需要对开放给第三方接口实现鉴权和防刷限制可以使用自定义注解和Interceptor来实现
步骤
1. 自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AccessLimit {
int seconds() default 1;
int maxCount() default 1;
boolean needLogin()default true;
}
2. 自定义Interceptor
@Component
public class InterfaceInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String,Integer> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//是否方法请求
if (handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
//方法上是否有注解
AccessLimit methodAnnotation = hm.getMethodAnnotation(AccessLimit.class);
if(methodAnnotation == null){
return true;
}
int maxCount = methodAnnotation.maxCount();
int seconds = methodAnnotation.seconds();
//TODO 注入RedisTemplate
boolean needLogin = methodAnnotation.needLogin();
if(needLogin){
//判断登陆,接口授权的秘钥
String secertKey = request.getParameter("secertKey");
if(StringUtils.hasText(secertKey)){
//查询数据库判断
return true;
}else{
render(response,"未登录");
return false;
}
}
String key = request.getRequestURI();
//从redis中获取用户访问的次数
Integer count = redisTemplate.opsForValue().get(key);
if(count == null){
//第一次访问
redisTemplate.opsForValue().set(key,1);
redisTemplate.expire(key,seconds, TimeUnit.SECONDS);
}else if(count < maxCount){
//加1
redisTemplate.boundValueOps(key).increment();
redisTemplate.expire(key,seconds, TimeUnit.SECONDS);
}else{
//超出访问次数
render(response,"超出访问次数,请稍后重试"); //这里的CodeMsg是一个返回参数
return false;
}
}
return true;
}
private static void render(HttpServletResponse response,String str) throws IOException {
response.setContentType("application/json;charset=UTF-8");
OutputStream out = response.getOutputStream();
out.write(str.getBytes(StandardCharsets.UTF_8));
out.flush();
out.close();
}
}
3. 拦截器注入Springboot
@Configuration
@RequiredArgsConstructor
public class InterfaceConfig implements WebMvcConfigurer {
private final InterfaceInterceptor interceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(interceptor);
}
}
4. 使用
@AccessLimit
@RequestMapping("/save")
public String save(User users) {
return users.toString();
}