写在前面的话: 这篇文章是与Token验证关联的,看友们可以去看看俺的这篇Servlet的Token的实现
实现Servlet过滤器方式:
1、在xml文件里面配置
2、在文件头添加注解、
首先我们应该知道什么是过滤器:
java过滤器:顾名思义,就是在java中起到过滤的作用的一个方法。
可以在一个请求到达servlet之前,将其截取进行逻辑判断,然后决定是否放行到请求的servlet中。
也可以在一个response到达客户端之前,截取结果进行逻辑判断,然后决定是否允许返回给客户端。
在前面文章Token的实现中,我们可以知道,用户第一次登录是没有Token的,需要验证生成。同时前端需要在每次业务请求带上后端返回最新的一个Token,下面我们用过滤器进行Token的过滤。
1、首先新建一个java文件,继承Filter,并在文件头上加上@WebFilter注解,这里的Url是业务页面的请求地址,/*
可匹配多个请求并处理
@WebFilter(urlPatterns = "/recharge/*") public class Myfilter implements Filter {
继承了Filter接口,就需要实现的三个方法:
看单词的意思,doFilter方法应该就是处理过滤的方法
@Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
这里需要注意的一点是:要明白这是前端发来的业务请求,需要过滤器来验证Token
简单写一个前端的业务dopost请求:
package com.example.demo.newyears.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Author:Yun * @Date:2022/01/10/10:34 * @Description: **/ @WebServlet(name = "recharge", urlPatterns = "/recharge") public class Recharge extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (resp.getHeader("Token") != null) { resp.getWriter().println(req.getAttribute("id")); } } }
过滤器的工作:那么过滤器的工作就是拿到前端的请求头中的Token,并对Token进行处理,然后要注意的一点就是后端有异常需要处理,因为过滤器处理后,后端拿到的Token可能已经被过滤器过滤返回给前端了,那么后端就需要处理一下异常。
过滤器代码如下:
package com.example.demo.newyears.servlet; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.text.ParseException; /** * @Author:Yun * @Date:2022/01/10/8:52 * @Description: **/ //拦截所有指定的url @WebFilter(urlPatterns = "/recharge/*") public class Myfilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //在过滤器中设置了返回体的编码格式的话,那么在业务页面就不需要再一个个页面去设置了 ((HttpServletResponse) servletResponse).setHeader("Content-Type", "application/json;charset=UTF-8"); // String token = ""; // if (servletRequest instanceof HttpServletRequest) { **//这里需要注意,doFilter方法中的servletRequest,servletResponse和HttpServletRequest是对应一个请求** HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse resp = (HttpServletResponse) servletResponse; try { //该方法再下面的代码段 Token.timethan(req, resp); } catch (NullPointerException | ParseException e){ e.printStackTrace(); } //验证Token // ((HttpServletResponse) servletResponse).setHeader("Token", "xxxxxxxxxxx"); //todo servlet执行之前 //继续往前走,职责链,这句话很关键 filterChain.doFilter(servletRequest, servletResponse); //todo servlet的内容 } }
这里需要注意,doFilter方法中的servletRequest,servletResponse和HttpServletRequest是对应一个请求,所以再这里可以对请求中的参数进行获取,并设置想要传递的参数
完整源代码:
Myfilter.java package com.example.demo.newyears.servlet; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.text.ParseException; /** * @Author:Yun * @Date:2022/01/10/8:52 * @Description: **/ //拦截所有指定的url @WebFilter(urlPatterns = "/recharge/*") public class Myfilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void destroy() { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { ((HttpServletResponse) servletResponse).setHeader("Content-Type", "application/json;charset=UTF-8"); // String token = ""; // if (servletRequest instanceof HttpServletRequest) { HttpServletRequest req = (HttpServletRequest) servletRequest; HttpServletResponse resp = (HttpServletResponse) servletResponse; // token = req.getHeader("Token"); // req.setAttribute("id", 24); //setArribute设置的内容,可以在servlet doget中拿到 // } try { Token.timethan(req, resp); } catch (NullPointerException | ParseException e){ e.printStackTrace(); } //验证Token // ((HttpServletResponse) servletResponse).setHeader("Token", "xxxxxxxxxxx"); //todo servlet执行之前 //继续往前走,职责链 filterChain.doFilter(servletRequest, servletResponse); //todo servlet的内容 } } Recharge.java package com.example.demo.newyears.servlet; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Author:Yun * @Date:2022/01/10/10:34 * @Description: **/ @WebServlet(name = "recharge", urlPatterns = "/recharge") public class Recharge extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (resp.getHeader("Token") != null) { resp.getWriter().println(req.getAttribute("id")); } } } Token.java /** * 后端拿到前端请求头的token对象,验证身份,比较有效时间 * * @param req * @param resp * @return * @throws ParseException */ public static void timethan(HttpServletRequest req, HttpServletResponse resp) throws ParseException, IOException { //拿到token对象 try { String str = Base644.decoding(req.getHeader("Token")); //将token切割成两部分 //str:"id:1001,status:1,endtime:2022-01-08 19:18:43";fb675266364f697519dac6d1e6ec1da3 String ahead = str.substring(0, str.indexOf(";")); String behind = str.substring(str.indexOf(";") + 1, str.length()); //时间从字符串中截取出来 String ss = ahead.substring(ahead.indexOf("e"), ahead.length()); String cc = ss.substring(ss.indexOf(":") + 1, ss.length()); //将字符串的时间转为long类型的数据进行比较 SimpleDateFormat sif = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date data = sif.parse(cc); long stime = data.getTime(); Date date1 = new Date(); Date dateafter = new Date(date1.getTime()); long nowtime = dateafter.getTime(); long differen = stime - nowtime; //解析当前token对象的id,状态 int id = Integer.parseInt(ahead.substring(ahead.indexOf("i") + 3, ahead.indexOf(","))); int status = Integer.parseInt(ahead.substring(ahead.indexOf("s") + 7, ahead.lastIndexOf(","))); if (getMd5(ahead).equals(behind)) { try { if (differen < 0) { resp.getWriter().println("请重新登录!"); } else { resp.getWriter().println("前端请求的业务处理结果,后端已送到,请接受!"); //创建一个新的Token resp.getWriter().println("Token:" + createToken(id, status)); resp.setHeader("Token", createToken(id, status)); req.setAttribute("id", id); } } catch (IOException e) { e.printStackTrace(); } } else { resp.getWriter().println("请重新登录!"); } } catch (NullPointerException e) { e.printStackTrace(); } } /** * 创建Token对象 * * @param id * @param status */ public static String createToken(int id, int status) throws UnsupportedEncodingException { SimpleDateFormat sif = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = new Date(); Date dateafter = new Date(date.getTime() + 300000); Object endtime = sif.format(dateafter); String json = "id:" + id + ",status:" + status + ",endtime:" + endtime; JSONObject jsonObject = new JSONObject(); String ss = jsonObject.toJSONString(json); System.out.println(ss); String begin = ss + ";" + getMd5(ss); //调用并转换成base64 return Base644.encoding(begin); } Token.http GET http://localhost:8080/war/helloworld?name=cc&password=cc123 Accept: application/json;application/json;charset=utf-8 ### POST http://localhost:8080/war/recharge Content-Type: application/json;charset=utf-8 Token: ImlkOjEwMDEsc3RhdHVzOjEsZW5kdGltZToyMDIyLTAxLTEwIDEyOjAwOjA0IjtkYjE3Y2M4YjJlZWVkZGJjMjhlMDBhMTA0MTdjNTM0OA== { "id": 1001, "name": "云先生", "date": [ { "create_time": "2022-01-06" } ] }
最后请看效果图:
登录请求:
业务请求:
今天就到这里啦,有疑问的看友请留言或私聊我哦