拦截器以及自定义注解的使用

本文介绍如何在Spring Boot应用中配置UserTokenInterceptor和SecurityInterceptor,实现请求拦截,校验用户权限和Token有效性。涉及路径排除、Token解析与验证,以及@SecurityGrade注解的使用。

1,设置预处理,设置不需要拦截的请求

@Component
public class MyWebConfig implements WebMvcConfigurer {
  private final UserTokenInterceptor userTokenInterceptor;
  private final SecurityInterceptor securityInterceptor;

  public MyWebConfig(
      UserTokenInterceptor userTokenInterceptor, SecurityInterceptor securityInterceptor) {
    this.userTokenInterceptor = userTokenInterceptor;
    this.securityInterceptor = securityInterceptor;
  }

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    // 定义排除swagger访问的路径配置
    String[] swaggerExcludes =
        new String[] {"/swagger-ui.html", "/swagger-resources/**", "/webjars/**"};
    registry
        .addInterceptor(userTokenInterceptor)
        .addPathPatterns("/**")
        .excludePathPatterns(
            "/user/login", "/static/**", "/*.html", "/*.ico", "/*.json", "/*.png", "/heartbeat/**")
        .excludePathPatterns(swaggerExcludes);
    registry
        .addInterceptor(securityInterceptor)
        .addPathPatterns("/maintain/**", "/user/**")
        .excludePathPatterns("/user/login");
  }
}

2.UserTokenInterceptor ,securityInterceptor分别处理不同的请求拦截,执行不同的拦截逻辑。

2个处理的类请求上可以有交集,2个处理类都执行。

@Component
public class UserTokenInterceptor implements HandlerInterceptor {
  private final EmpInfoService empInfoService;

  public UserTokenInterceptor(EmpInfoService empInfoService) {
    this.empInfoService = empInfoService;
  }

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // 校验handler是否是HandlerMethod
    if (!(handler instanceof HandlerMethod)) {
      return true;
    }
    // 从请求头中获取token
    String token = request.getHeader("Authorization");
    /**
     * update:2021/11/30 ShengJieLi
     * 增加逻辑:Authorization的值不为本系统生成的token时,解密Authorization,获取token并验证
     */
    if (StrUtil.isNotEmpty(token)) {
      EmpInfo securityEmployee = empInfoService.queryToken(token);
      if(securityEmployee != null){
        // token有效
        String ref = empInfoService.isRef(token);
        if (StrUtil.isNotBlank(ref)) {
          response.setHeader("Access-Control-Expose-Headers", "token");
          response.addHeader("token", ref);
        }
      }else{
        //Authorization为PBE加密数据
        securityEmployee = empInfoService.analyticQueryToken(token,response);
      }
      if (securityEmployee != null) {
        // token有效
        // 将User对象放入到ThreadLocal中
        UserLocal.set(securityEmployee);
        return true;
      }
      return false;
    }
//    String s = JSONUtil.toJsonStr(ResponseResult.error(ErrorCode.TOKEN_ERROR));
//    response.setContentType("text/html;charset=UTF-8");
//    JSONUtil.toJsonStr(s, response.getWriter());
//    response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
    InterceptorExceptionResolver.interceptorError(response,ErrorCode.TOKEN_ERROR);
    //update 结束
    return false;
  }

  @Override
  public void afterCompletion(
      HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
      throws Exception {
    // 响应结束后刪除對象
    UserLocal.remove();
  }
}
@Component
public class SecurityInterceptor implements HandlerInterceptor {
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // 校验handler是否是HandlerMethod
    if (!(handler instanceof HandlerMethod)) {
      return true;
    }
    HandlerMethod method = (HandlerMethod) handler;
    // 判断是否包含@NoAuthorization注解,如果包含,直接放行
    if (method.hasMethodAnnotation(NoAuthorization.class)) {
      return true;
    }
    SecurityGrade methodAnnotation = method.getMethodAnnotation(SecurityGrade.class);
    if (methodAnnotation == null) {
      methodAnnotation = method.getMethod().getDeclaringClass().getAnnotation(SecurityGrade.class);
    }
    // 權限等級 用戶對象
    EmpInfo info = UserLocal.get();
    if (info == null) {
      retError(response);
      return false;
    }

    List<String> value = List.of(methodAnnotation.value());
    // 權限等級
    List<Role> roles = info.getRoles();
    boolean isRelease = false;
    for (Role role : roles) {
      String permission = role.getRolePermission();
      if (value.contains(permission)) {
        isRelease = true;
        break;
      }
    }
    if (isRelease) {
      return true;
    } else {
      retError(response);
      return false;
    }
  }

  private void retError(HttpServletResponse response) throws IOException {
    String s = JSONUtil.toJsonStr(ResponseResult.error(ErrorCode.ROLE_ERROR));
    response.setContentType("text/html;charset=UTF-8");
    JSONUtil.toJsonStr(s, response.getWriter());
  }
}

3.关于注解的使用

@SecurityGrade({"SUPER_ADMIN", "SYSTEM_ADMIN"})
public class SecurityController {
  private final EmpInfoService empInfoService;

  public SecurityController(EmpInfoService empInfoService) {
    this.empInfoService = empInfoService;
  }

  @GetMapping("getUserInformation")
  @ApiOperation("登陸用户信息")
  @NoAuthorization
  public ResponseResult getUserInformation(@ApiIgnore HttpServletResponse response) {
    return empInfoService.getUserInformation(response);
  }
}

method.getMethodAnnotation(SecurityGrade.class) 获得注解信息,methodAnnotation.value()获得注解内容"SUPER_ADMIN", "SYSTEM_ADMIN"。

MyBatis拦截器自定义注解是MyBatis框架中的两个重要特性。下面我会分别解释它们的作用和用法。 MyBatis拦截器是一种机制,可以在执行SQL语句的过程中对其进行拦截和修改。它提供了一种方便的方式来扩展和自定义MyBatis的功能。拦截器可以在SQL语句执行前后、参数设置前后、结果集处理前后等关键点进行拦截,并对其进行修改或增强。 要实现一个MyBatis拦截器,你需要实现`Interceptor`接口,并重写其中的方法。其中最重要的方法是`intercept`,它接收一个`Invocation`对象作为参数,通过该对象你可以获取到当前执行的SQL语句、参数等信息,并可以对其进行修改。另外还有`plugin`方法和`setProperties`方法用于对拦截器进行初始化。 自定义注解是一种用于标记和配置特定功能的注解。在MyBatis中,你可以使用自定义注解来配置一些特殊的功能,比如动态SQL的条件判断、结果集映射等。通过自定义注解,你可以将一些常用的功能封装成注解,并在需要时直接使用。 要使用自定义注解,你需要先定义一个注解,并在相应的地方使用注解。然后通过MyBatis的配置文件或者Java代码进行配置,告诉MyBatis如何处理这些注解。在MyBatis的执行过程中,它会根据注解的配置来动态生成相应的SQL语句或者进行特定的处理。 总结一下,MyBatis拦截器自定义注解是MyBatis框架中的两个重要特性。拦截器可以对SQL语句进行拦截和修改,自定义注解可以用于配置一些特殊功能。它们都提供了一种扩展和自定义MyBatis功能的方式。如果你有具体的问题或者需要更详细的示例代码,欢迎继续提问!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值