1

为什么要写这个:
原因简单,就是需求来了,哈哈!!!
要求:
1.自己对外提供的接口,哪些厂商有权限访问。
2.每个接口限制访问次数,每天需要重置访问次数上限。
具体的原因不说了,千言万语就是安全,安全,安全。


开始我们的表演
先来一遍Spring Boot
在来一遍Spring MVC

第一个重点:自己对外提供的接口,哪些厂商有权限访问
一、设置拦截URL请求

/**
 * @Description: 设置拦截
 * @author: 你瞅瞅~~
 * @create: 2020-01-10 14:51
 */
public class AuthRequestInterceptor implements HandlerInterceptor {  
  
  @Autowired  
  private AuthService authService;  
  
     @Override  
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
              // 验证权限  
              if (handler instanceof HandlerMethod) {  
              HandlerMethod handlerMethod = (HandlerMethod) handler;  
              // AuthRequest是我们定义在controller方法上的注解~  
              AuthRequest authRequest = handlerMethod.getMethod().getAnnotation(AuthRequest.class);  
              // AuthRequest是我们定义在controller类上的注解~  
              if (authRequest == null) {  
              authRequest = handlerMethod.getMethod().getDeclaringClass().getAnnotation(RequiredPermission.class);  
              // 获取请求URL  
              String requestURI = request.getRequestURI();  
              // 校验接口URL/访问次数  
              // redis或数据库(加缓存) 中获取该用户的权限信息 并判断是否有权限  
              List<String> authCount = authService.getAuthCount();  
              if (!authURL.contains(requestURI)) {  
                  return false;  
              }   
              // 这里简单写一下,明确一点就是【接口URL --> 访问次数】
              Long accessCount = authCount.getAccessCount();  
              if (accessCount < 0) {  
                 return false;  
              } else {  
                int count = accessCount - 1;
                authService.updateCount(count);  
              }  
           }  
          return true;  
       }  
    }
  
    @Override  
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {  
    }  

    @Override  
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {  
    }
 
 }

二、使用注解的拦截器
写这个注解的意思很明确,这样不管在哪里项目都可以设置统一拦截,给大家提供一个简单的注解就完事了,如果你用了Spring boot你就知道注解是多么省事。

自定义一个注解 AuthRequest 类

/**
 * @Description: 注解拦截
 * @author: 你瞅瞅~~
 * @create: 2020-01-10 14:51
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AuthRequest {
    String value();
}

三.拦截配置文件WebAppConfig
@Configuration 这个注解,在启动的时候在会被加载
多个拦截就设置多个类似定义方法 getInterceptor1()/getInterceptor2()

 /**
 * @Description:对外接口权限拦截  
 * @author: 你瞅瞅~~
 * @create: 2020-01-10 14:51
 */
@Configuration
public class WebAppConfig extends WebMvcConfigurerAdapter {  

  
  @Override  
  public void addInterceptors(InterceptorRegistry registry) {
        // 拦截@AuthRequest注解的所求请求
        // addPathPatterns 用于添加拦截规则  
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(getInterceptor1()).addPathPatterns("/login/**");
        registry.addInterceptor(getInterceptor2()).addPathPatterns("/login2/**");  
        super.addInterceptors(registry);  
   }  
  
  
  @Bean  
  public HandlerInterceptor getInterceptor(){  
        return new authInterceptor;  
  }  
  
}

四.Controller添加拦截请求注解

 /**
 * @Description:对外接口权限拦截  
 * @author: 你瞅瞅~~
 * @create: 2020-01-10 14:51
 */
这个注解就是拦截整个Controller所有请求,全局注解
@AuthRequest
@RequestMapping("/login")
public class AuthController {  
   
  private static final String  NO_AUTH = "接口权限";
  
  // 权限注解,相当于局部注解,AuthController.AuthRequest表示在进入拦截判断是否有值 
  @AuthRequest(AuthController.AuthRequest) 
  @RequestMapping("/list")
  public String list() {  
      // 各种操作
      return "/login/users";  
  }  
  
  // 未注解,表示不拦截 
  @RequestMapping("/delete")  
  public String detail() {  
      // 各种操作
      return "/login/user";  
  }  
 
}

第二个重点:每个接口限制访问次数,每天需要重置访问次数上限
简单说明:设置定时刷新任务,在需要刷新的方法上定时刷新,这样就可以每天获取重置次数,当然也可写到redis里,这样的话,就可以不用定时刷新获取。

1.Application 要加注解,也就是总开关@EnableAsync
2.在需要获取的接口上加上@Scheduled 配置cron表达式

/**
 * @Description: 定时任务,每天刷新请求次数   
 * @author: 你瞅瞅~~
 * @create: 2020-01-10 14:51
 */
@Scheduled(cron = "0 0 1 * * ?")  
// 每天凌晨一点刷新接口,authRequest定义一个全局变量
public void accessCountCurrentByCron() {  
        List<String> authRequest = authRequest.getAuthRequests();
        logger.warn("我在刷新。。。");  
        result authRequest;
      }
  }  
}

为什么写Spring mvc 因为我们有老项目,嘿嘿
重头再来,我们走完了Spring boot,那来说说Spring mvc

在我们SpringMVC中也可以使用拦截器对用户的请求进行拦截,
用户可以自定义拦截器来实现 HandlerInterceptor

主要区别就是个添个配置,Spring boot可以用注解完事,Spring mvc需要写在配置文件,剩下的都一样。
一、添加简单配置springmvc.xml

<mvc:interceptors>  
 <mvc:interceptor>  
 <mvc:mapping path\="/login/**"/>  
 <bean class\="com.interceptor.AuthInterceptor"/>  
 </mvc:interceptor>  
</mvc:interceptors>

// 这里是为了扫描到注释@AuthRequest
// 启动包扫描功能,以便注册带有@Controlle
<context:component-scan base-package\="com.org.需要拦截的类" use-default-filters\="false"\>  
 <context:include-filter type\="annotation" expression\="org.springframework.stereotype.Controller"/>  
 <context:include-filter type\="annotation" expression\="com.interceptor.AuthRequest"/>  
</context:component-scan>

可以参考这篇文章,spring mvc的用法Controller写的很详细 :[https://segmentfault.com/a/11...]

遇见的问题【重点】
HandlerInterceptor拦截器使用中,就能遇见这个问题,

Required request body is missing OR Stream closed

继承并实现 HttpServletRequestWrapper包装类,可参考这一篇
[https://segmentfault.com/a/11...]


走在小路上
11 声望1 粉丝

Swim against the stream 要敢于逆流而上