背景
【springBoot|自定义拦截器实现权限校验】前几天接收到一个业务需求,简要描述一下,当某个企业账户冻结之后,企业在登陆后台管理系统,不能进行某些操作,如导入员工信息、发放员工福利、发票信息申请等,但是系统中的查看功能如账单查询、员工查询都可以正常使用。
很显然,从全局去处理账户的状态判断是不可取的,因为在账户冻结之后,并不是所有的动作都是被禁止的,这里就可以使用过滤器对指定的方法进行筛选校验
既定方案
使用自定义的注解,标注需要进行账户状态校验的请求方法,使用拦截器拦截这些接口,在拦截器中执行账户状态的判断,如果账户状态正产则放行,如果状态异常则抛出自定义的异常,并且使用自定义的异常处理类进行捕获处理。基本思路就是这样,下面我们来进行方案的实现。
方案实现
- 第一步:自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FrozenAcc {
boolean permission() default false;
}
方法级别以及运行时状态即可。
- 第二步:自定义拦截器
@Slf4j
public class FrozenFilter extends HandlerInterceptorAdapter {@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//拦截自定义的注解
HandlerMethod handlerMethod = (HandlerMethod) handler;
FrozenAcc annotation = handlerMethod.getMethod().getAnnotation(FrozenAcc.class);
if (annotation == null) {
return true;
}
//获取如果处于冻结状态,则抛出一个异常信息
String accStatus = UserUtil.getAccStatus();
if ("1".equals(accStatus)) {
return true;
}
throw new FrozenException(444, "您好,您的账户因逾期未还款已被冻结,无法进行当前操作,请尽快还款后申请解冻!");
}
}
- 第三步:注册拦截器类,使拦截器生效
@Configuration
public class CheckConfig implements WebMvcConfigurer {@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new FrozenFilter()).addPathPatterns("/employee/enterpriseEmployee/**");
registry.addInterceptor(new FrozenFilter()).addPathPatterns("/enterprisepoints/enterprisePointsBatch/**");
registry.addInterceptor(new FrozenFilter()).addPathPatterns("/invoice/**");
}
}
可注册多个拦截器,并指定拦截规则,这里我对员工管理、企业积分管理、以及发票信息管理做了拦截
- 第四步:控制层中,在需要进行账户信息校验的接口上添加注解
@FrozenAcc
@RequiresPermissions("tb:enterpriseEmployee:add")
@PostMapping(value = "https://www.it610.com/article/add")
public R add(EnterpriseEmployee enterpriseEmployee) {
return enterpriseEmployeeService.saveEmployee(enterpriseEmployee);
}
如上,在员工管理中,新增员工信息的方法上面添加FrozenAcc注解
- 第五步:自定义异常以及异常处理
@Data
@EqualsAndHashCode(callSuper = false)
public class FrozenException extends RuntimeException {private int code;
private String message;
public FrozenException(int code, String message) {
this.message = message;
this.code = code;
}
}
异常处理类,用于捕获处理自定义的异常,封装响应参数给前端
@ExceptionHandler(FrozenException.class)
public R handleFrozenException(FrozenException e) {
return R.fail(e.getCode(), e.getMessage());
}
总结
以上就可以实现对指定接口实现账户状态的校验,能够符合业务的需要,但是还是存在改进之处的。
在请求指定模块时,凡是加上注解的方法都需要去校验账户的状态,目前是采取直查数据库的方式,在日志中能发现多次查询的sql语句,一个是增加系统的IO开销,还有就是重复的查询逻辑,之前有考虑过在用户登录之后,就将企业的账户状态放到全局的会话缓存当中,但是有个弊端就是,如果用户在登陆成功之后,账户状态过期冻结,那么这个 用户还是可以进行操作的,并没有达到实时的状态过滤。
可以引入缓存机制,提高性能,但是必须还得配上缓存的更新策略。可优化的方案如下:
- 登录时,将企业的账户状态放到redis缓存中,并在企业账户状态变更的逻辑中(具体的操作或者定时任务等),添加账户状态的更新逻辑,将最新的状态更新至redis当中。而在拦截器中,就可以直接使用redis中的值来判断企业的账户状态,使用缓存提升查询效率避免直查数据库。
推荐阅读
- springBoot|springBoot使用拦截器实现权限验证,解决注入为空
- springboot|Springboot+Shiro+Vue博客管理系统
- springboot|搭建一个springboot+templates+mysql+mybatisplus代码生成器简单框架
- SpringBoot|计算机毕业设计及论文-原创(基于SpringBoot的奥运村服务管理平台的设计与实现)
- vue+springboot|基于vue+springboot的校园疫情健康打卡和离校审批系统的设计 (百度地图API对接)
- springBoot|SpringBoot整合Spring Security+JWT实现前后端分离登录权限处理
- springboot|spring boot多数据源动态切换, 多数据源事务管理
- springboot|从零开始搭建springboot项目骨架
- 技术分享|使用 SpringBoot + Redis + Vue3 + ArcoPro 开发管理系统