SpringBoot项目如何设置权限拦截器和过滤器
作者:执檀月夜游
过滤器 Filter
Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是设置字符集、控制权限、控制转向、做一些业务逻辑判断等。
其工作原理是,只要你在web.xml文件(或通过注解)配置好要拦截的客户端请求,它都会帮你拦截到请求,此时你就可以对请求或响应(Request、Response)统一设置编码,简化操作;同时还可进行逻辑判断,如用户是否已经登陆、有没有权限访问该页面等等工作。
作用
- 在HttpServletRequest到达Servlet之前,拦截客户的HttpServletRequest。
- 根据需要检查HttpServletRequest,也可以修改HttpServletRequest头和数据。
- 在HttpServletResponse到达客户端之前,拦截HttpServletResponse。
- 根据需要检查HttpServletResponse,也可以修改HttpServletResponse头和数据。
生命周期
随web应用启动而启动的,只初始化一次,以后就可以拦截相关请求,只有当你的web应用停止或重新部署的时候才销毁。
示例代码
import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import javax.servlet.*; import javax.servlet.annotation.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import java.io.IOException; import java.util.Base64; @Component @WebFilter(filterName = "CharestFilter" , urlPatterns = "/*" , dispatcherTypes = {DispatcherType.ASYNC, DispatcherType.ERROR} , initParams = {@WebInitParam(name = "charset", value = "utf-8")}) public class CharestFilter implements Filter { /** * 初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置 * * @param config * @throws ServletException */ @Override public void init(FilterConfig config) throws ServletException { } /** * 销毁时调用 */ @Override public void destroy() { } /** * 过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理 * * @param request * @param response * @param chain * @throws ServletException * @throws IOException */ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper((HttpServletRequest) request) { /** * 当调用request.getHeader("token")时,则获取请求参数中token值并当做Header的值返回 * @param name * @return */ @Override public String getHeader(String name) { // 先从原本的Request中获取头信息,如果字段是用户名,且值不为null时,进行解码 String superHeader = super.getHeader(name); if ("X-USERNAME".equalsIgnoreCase(name) && StringUtils.hasText(superHeader)) { return new String(Base64.getDecoder().decode(superHeader)); } return superHeader; } }; //交给下一个过滤器或servlet处理 chain.doFilter(requestWrapper, response); } }
拦截器 Interceptor
拦截器是在面向切面编程中应用的,就是在service或者一个方法前调用一个方法,或者在方法后调用一个方法。是基于JAVA的反射机制。
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
实现
第一种方式是要定义的Interceptor类要实现了Spring 的HandlerInterceptor 接口;
第二种方式是实现Spring的WebRequestInterceptor接口
或继承这两个接口的实现类子类
interceptor 的执行顺序大致为:
- 请求到达 DispatcherServlet
- DispatcherServlet 发送至 Interceptor ,执行 preHandle
- 请求达到 Controller
- 请求结束后,postHandle 执行
Spring 中主要通过 HandlerInterceptor 接口来实现请求的拦截,
实现 HandlerInterceptor 接口需要实现下面三个方法:
- preHandle() – 在handler执行之前,返回 boolean 值,true 表示继续执行,false 为停止执行并返回。
- postHandle() – 在handler执行之后, 可以在返回之前对返回的结果进行修改
- afterCompletion() – 在请求完全结束后调用,可以用来统计请求耗时等等
示例代码
第一步:在pom.xml中添加依赖
<parent><!--parent 是父模块,由父模块统一进行 spring-boot 版本管理--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.5.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <dependency><!--web核心依赖--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
第二步:新建一个 intercepors 包
如图
在 intercepors 包下的第一个java类LoginInterceptor是自定义登录拦截器,记得在类名上加 @Component 注解,我们需要在下一步的 WebConfigurer 类中注入。
代码如下:
import com.example.bookstore.entity.Users;//这是我自己项目的用户类 import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; /** * 登录拦截器 */ @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //获取请求的RUi:去除http:localhost:8080这部分剩下的 String uri = request.getRequestURI(); //UTL:除了login.jsp是可以公开访问的,其他的URL都进行拦截控制 if (uri.indexOf("login")+uri.indexOf("register") >= 0) { return true; } //获取session HttpSession session = request.getSession(); Users user = (Users) session.getAttribute("user"); //判断session中是否有用户数据,如果有,则返回true,继续向下执行 if (user != null) { return true; } //不符合条件的给出提示信息,并转发到登录页面,这里.getRequestDispatcher()的路径换成自己项目的首页路径。parameter是一个给jsp页面显示的参数,在jsp页面用${parameter}就能显示。 request.setAttribute("parameter", "您还没有登录,请先登录!"); request.getRequestDispatcher("/WEB-INF/jsp/book/bookList.jsp").forward(request, response); return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
在 intercepors 包下的第三个java类WebConfigurer是用来把自定义的拦截器告诉框架用的,需要实现WebMvcConfigurer 接口,并实现它的两个方法。
代码如下:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfigurer implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; // 这个方法是用来配置静态资源的,比如html,js,css,等等 @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { } // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效 //.addPathPatterns("/**"),设置拦截的范围,/**代表全部 // .excludePathPatterns是设置白名单,这里本项目中的首页、登录注册、商品的浏览和查找是不需要判断是否已登录的 @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(loginInterceptor).addPathPatterns("/**").excludePathPatterns("/index","/login", "/register","/bookList","/bookName","/bookType"); } }
第三步:重新编译部署项目
在IDEA中
快捷键 Ctrl+F9 重新部署
快捷键 Shift+F9重新运行
然后在浏览器访问测试即可
过滤器和拦截器的区别
Spring的Interceptor(拦截器)与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,都能实现权限检查、日志记录等。
不同的是:
- Filter在只在 Servlet 前后起作用。Filters 通常将 请求和响应(request/response) 当做黑盒子,Filter 通常不考虑servlet 的实现。
- 拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。允许用户介入(hook into)请求的生命周期,在请求过程中获取信息,Interceptor 通常和请求更加耦合。
- Filter 是在 Servlet 规范中定义的,是 Servlet 容器支持的。
- 而拦截器是在 Spring容器内的,是Spring框架支持的。
总结
过滤器:所谓过滤器顾名思义是用来过滤的,在java web中,你传入的request,response提前过滤掉一些信息,或者提前设置一些参数,然后再传入servlet或者struts的action进行业务逻辑,比如过滤掉非法url(不是login.do的地址请求,如果用户没有登陆都过滤掉),或者在传入servlet或者struts的action前统一设置字符集,或者去除掉一些非法字符(聊天室经常用到的,一些骂人的话)。filter 流程是线性的, url传来之后,检查之后,可保持原来的流程继续向下执行,被下一个filter, servlet接收等.
java的拦截器 主要是用在插件上,扩展件上比如 hibernate spring struts2等 有点类似面向切片的技术,在用之前先要在配置文件即xml文件里声明一段的那个东西。
在Spring构架的程序中,要优先使用拦截器。几乎所有 Filter 能够做的事情, interceptor 都能够轻松的实现
最后
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。