Spring Security框架使用过程中会有很多Restful API的拦截操作,像各种过滤器拦截器以及Spring AOP的使用,所以在学习Spring Security之前很有必要对他们进行一个简单介绍。
过滤器(Filter)
简介
- JavaWeb三大组件(Servlet、Filter、Listener)之一,Web开发人员通过Filter技术,对web服务器管理的
所有web资源(例如Jsp、Servlet、静态图片文件或静态html文件等)进行拦截
,从而实现一些特殊的功能。
使用场景
- 主要用于对用户请求进行
预处理
,也可以对HttpServletResponse进行后处理
。 - 使用Filter的
完整流程
:Filter对用户请求进行预处理,接着将请求交给Servlet进行处理并生成响应,最后Filter再对服务器响应进行后处理。
简单演示
/**
* 过滤器演示:直接定义一个类实现Filter接口,记得需要配置该过滤器,或者直接加@Component自动配置
*
* @author HuaDong
* @date 2020/4/11 18:38
*/
@Component
public class TimeFilter implements Filter {
/**
* 容器销毁的时候调用
*/
@Override
public void destroy() {
System.out.println("time filter destroy");
}
/**
* Web服务器每次在调用Web资源之前,都会先调用filter的doFilter方法
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("time filter start");
long start = System.currentTimeMillis();
chain.doFilter(request, response);
System.out.println("time filter 耗时:" + (System.currentTimeMillis() - start));
System.out.println("time filter finish");
}
/**
* 容器启动时候调用
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("time filter init");
}
}
拦截器(Interceptor)
简介
- Java 里的拦截器是动态拦截 action 调用的对象,它提供了一种机制可以使开发者可以定义在一个 action 执行的前后执行的代码,也可以在一个 action 执行前阻止其执行,同时也提供了一种可以提取 action 中可重用部分的方式。通俗来说就是
可以拦截一个请求
,对请求进行Controller方法的调用之前之后或者抛出异常时的一个自定义的操作。
使用场景
- 可以对请求进行一个
登录凭证的校验
。 - 可以对请求响应之后
加上一些统一的响应字段
等。
简单演示
- 声明拦截器
/**
* 拦截器演示:定义一个类实现HandlerInterceptor接口
*
* @author HuaDong
* @date 2020/4/11 19:21
*/
@Component
public class TimeInterceptor implements HandlerInterceptor {
/**
* 请求Controller方法之前:返回false表示被拦截不再往下执行,即不再调用Controller方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle");
System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
System.out.println(((HandlerMethod)handler).getMethod().getName());
request.setAttribute("startTime", System.currentTimeMillis());
return true;
}
/**
* 请求Controller方法之后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (System.currentTimeMillis() - start));
}
/**
* 抛出异常之后 postHandle 方法不会被调用,无论是否抛出异常 afterCompletion 方法都会被调用
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (System.currentTimeMillis() - start));
System.out.println("ex is "+ex);
}
}
- 注册拦截器
/**
* 注册拦截器:创建一个config类,继承WebMvcConfigurerAdapter,将我们上面定义的拦截器注册到InterceptorRegistry中
*
* @author HuaDong
* @date 2020/4/11 19:32
*/
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Autowired
private TimeInterceptor timeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
}
缺点
- preHandle方法无法通过handler拿到一些
封装之后的请求参数
,因为封装参数的方法是在preHandle之后进行的。 - 查看源码:org.springframework.web.servlet.DispatcherServlet#doService --> doDispatch
// 实际 preHandler 的调用
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 参数封装处理逻辑
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
切片(Aspect)
简介
- AOP,
面向切面编程
,采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。
使用场景
- 权限控制
- 缓存控制
- 事务控制
- 审计日志
- 性能监控
- 分布式追踪
- 异常处理