Spring Boot当中使用自定义注解

本文最后更新于:2018年11月20日 晚上

前言

自定义注解算是 Java 这门语言当中我非常喜欢的特性了,因为它能够实实在在的提高开发效率,简化代码而不失可读性。之前仅仅在写入门级 ORM 框架的时候使用过,这两天开发新的项目,看到dalao们在Spring Boot 当中使用自定义注解来完成各种事务,立马就学习了一下

环境

  • Spring Boot 2.0.5.RELEASE

目标

我们希望使用对于方法的注解,来为该方法加入请求鉴权,增加 RESTful API 的安全性

注解定义

使用 public @interface 来定义一个公共的注解,具体代码如下

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorization {
    Class type();
}

这其中的 type 属性我们用来区别用户角色

编写拦截器

有了注解之后,我们需要编写一个拦截器,为注解绑定处理流程。Spring MVC 允许我们直接继承一个拦截器适配器 HandlerInterceptorAdapter ,来实现一个自定义拦截器,只需要实现一个 preHandle 方法就可以了,完整代码如下

@Component
public class AuthorizationInterceptors extends HandlerInterceptorAdapter {
    @Autowired
    TokenService tokenService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)){
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod)handler;
        Method method = handlerMethod.getMethod();
        Annotation annotation;
        if ((annotation = method.getAnnotation(Authorization.class) ) == null){
            return true;
        }
        String authorization = request.getHeader("token");
        AccessToken token = tokenService.getToken(authorization);
        if (token == null){
            // 设置但 token 错误的时候返回 401
            response.setStatus(401);
            return false;
        }else {
            // 判断 token 对象是否属于特定的角色(管理员、微信用户),然后分开处理
            if (((Authorization) annotation).type() == Admin.class && token.getAdmin()!=null){
                request.setAttribute("token", token.getUuid());
                return true;
            }else if (((Authorization) annotation).type() == Wechater.class && token.getWechater()!=null){
                request.setAttribute("token", token.getUuid());
                return true;
            }else {
                response.setStatus(200);
                response.getWriter().append(JSON.toJSONString(ResJson.errorAccessToken()));
                return false;
            }
        }
    }
}

将注解添加到 Spring 当中

注解绑定了处理的事务之后还需要将其添加到Spring 配置当中,新建一个配置类直接实现 WebMvcConfigurer 接口就可以了,然后填充 addInterceptors 方法,完整代码如下

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
    @Bean
    AuthorizationInterceptors authorizationInterceptor() {
        return new AuthorizationInterceptors();
    }
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 鉴权的 @Authorization 注解
        registry.addInterceptor(authorizationInterceptor()).addPathPatterns("/**");
        System.out.println("鉴权 @Authorization 注解增加成功");
    }
}

使用注解

@RequestMapping(value = "/api/logout")
@Authorization(type = Admin.class)
public String test(){
    return "success";
}

这样的话,请求/api/logout的时候,就一定要在 header 里面带上一个 token 参数才可以,token 一般是从登录接口那里获取的