spring cloud security 微服务安全
->流控 Hystrix Guava
->认证
->审计
->授权
ACL 简单,无法满足复杂的要求
RBAC 复杂,简化管理
是否需要认证
最小授权原则
401 没有成功认证
403 没有权限
429 限流
->流控 Hystrix Guava
->认证
->审计
->授权
ACL 简单,无法满足复杂的要求
RBAC 复杂,简化管理
是否需要认证
最小授权原则
401 没有成功认证
403 没有权限
429 限流
public class MyInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(MyInterceptor.class);
/**
* 预处理回调方法,实现处理器的预处理(如检查登陆),第三个参数为响应的处理器,自定义Controller
* 返回值:true表示继续流程(如调用下一个拦截器或处理器);
* false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应;
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.info("preHandle");
// 返回false会阻止调用链的继续进行
return true;
}
/**
* 后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.info("postHandle");
}
/**
* 整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finall
* 但仅调用处理器执行链中preHandle返回true的拦截器的afterCompletion。
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.info("afterCompletion");
}
}
@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
}
当我们需要多个拦截器的时候,每个拦截器的方法处理顺序如下:
Interceptor1:preHandle > Interceptor2:preHandle > Interceptor2:postHandle > Interceptor1:postHandle > Interceptor2:afterCompletion > Interceptor1:afterCompletion
为什么会有这样的执行结果呢?其实这和HandlerInterceptor中三个方法的执行时机有关系:
preHandle:在Controller处理之前做拦截进行处理,因此越是声明在前的拦截器,其preHandle方法就越先得到执行。
postHandle:在Controller处理之后,视图渲染返回之前进行处理,有点像括号嵌套的机制,左括号越是在前,其对应的右括号越是在后。
(PS:这里的“返回之前”只是针对视图渲染逻辑的处理,如果是Rest的接口,那么调用会在Controller处理之后直接返回,不会等到postHandle处理完之后才返回)
afterCompletion:在所有处理完成后用于对资源进行回收进行处理,因此,所有的afterCompletion都会在所有的preHandle和postHandle之后才会执行,且和postHandle一样,按照右括号规则执行。
我们可以在拦截器中定义对那些URL需要拦截,而哪些URL是不需要做任何处理的。
@Configuration
@EnableWebMvc
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 对所有的请求都要拦截,但是“/getInt”不在拦截的范围之内
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**").excludePathPatterns("/getInt");
}
}
有时候我们可能只需要实现三个回调方法中的某一个,如果实现HandlerInterceptor接口的话,三个方法必须实现,不管你需不需要,此时spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现),允许我们只实现需要的回调方法。
spring mvc提供三种异常处理器:
DefaultHandlerExceptionResolver, ResponseStatusExceptionResolver, ExceptionHandlerExceptionResolver
为了统一异常处理,我们可以自定义一个HandlerExceptionResolver,所有的异常均由自定义的异常处理, 由此我们可以重写DispatcherServlet类的
processHandlerException()方法:
@ControllerAdvice + @ExceptionHandler
使用@ControllerAdvice 和@ExceptionHandler 可以全局控制异常,使业务逻辑和异常处理分隔开。
自定异常
@Data
public class UserNotExitsException extends RuntimeException{
private Object id;
public UserNotExitsException(Object id){
super("用户不存在");
this.id = id;
}
}
全局控制异常
@ControllerAdvice
@Slf4j
public class ControllerExceptionHandler {
/**
* 用户不存在
* 待处理异常的类 UserNotExitsException
* @return 将返回的信息转为JSON,同时返回HTTP状态码500
*/
@ExceptionHandler(UserNotExitsException.class)
@ResponseBody
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public JsonResult handleUserNotExitException(UserNotExitsException ex){
log.info("handleUserNotExitException:"+String.valueOf(ex.getId()));
return JsonResult.error(ex.getMessage(),ex.getId());
}
}
既然在SpringMVC中有两种处理异常的方式,那么就存在一个优先级的问题:
当发生异常的时候,SpringMVC会如下处理:
(1)SpringMVC会先从配置文件找异常解析器HandlerExceptionResolver
(2)如果找到了异常异常解析器,那么接下来就会判断该异常解析器能否处理当前发生的异常
(3)如果可以处理的话,那么就进行处理,然后给前台返回对应的异常视图
(4)如果没有找到对应的异常解析器或者是找到的异常解析器不能处理当前的异常的时候,就看当前的Controller中有没有提供对应的异常处理器,如果提供了就由Controller自己进行处理并返回对应的视图
(5)如果配置文件里面没有定义对应的异常解析器,而当前Controller中也没有定义的话,就看有没有全局ControllerAdvice提供的全局异常处理器,如果没有那么该异常就会被抛出来。