Filter

Filter介绍

  • 过滤器,它是Servlet技术中最实用的技术,web开发人员通过filter技术,对web服务器管理的所有web资源例如:JSP,Servlet,静态图片文件或静态html文件等进行拦截,从而实现一些特殊的功能。例如实现URL级别的权限访问控制,过滤敏感词汇,压缩响应信息等一些高级功能。

javaee的API,filter接口
javax.servlet.filter

  • void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException
    • difilter是真正用于过滤的方法。filter也需要在web.xml文件中配置
    • 每个Filter都有对FilterConfig对象的访问权,可从该对象获得其初始化参数以及对它可以使用的ServletContext的引用,以便为过滤任务加载所需要的资源。
    • 每次由于对链末尾的某个资源的客户端请求而通过链传递请求/响应对时,容器都会调用Filter的doFilter 方法,传入此方法的FilterChain允许Filter将请求和响应传递到链中的下一个实体。
  • void init(FilterConfig filterConfig) throws ServletException
  • void destroy()

这里写图片描述

Filter入门

Filter创建步骤

  • 创建一个类,实现javax.servlet.Filter接口
  • 重写接口中的方法
  • 在web.xml文件中配置
public class DemoFilter implements Filter{
    //重写接口内的方法
    public void destriy(){

    }
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
    System.out.println(“执行过滤操作”);
//放行,继续执行index.jsp
    chain.dofilter(request,response);


    }
    public void init(FilterConfig filterConfig) throws ServletException{

    }
}
//web.xml配置
<filter>
    <filter-name>demoFilter</filter-name>
    <filter-class>cn.itcast.web.filter.DemoFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>deFilter</filter-name>
    <url-pattern>/index.jsp</url-pattern>
    <!--访问index.jsp页面会被DemoFilter过滤-->
</filter-mapping>

访问index.jsp,结果展示:
这里写图片描述
设置参数chain:

这里写图片描述
执行结果:
这里写图片描述

实现过滤操作步骤:

  • <url-pattern>它是用于设置过滤的路径
  • 在doFilter方法的第三个参数FilterChain,它是用于控制是否继续往下执行(访问服务器端资源)的。

Filter的生命周期

  • 在javax.servlet.Filter接口中三个方法
    • public void init(FilterConfig filterConfig) throws ServletException
      • 初始化方法,只执行一次
    • public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
      • 真正进行拦截操作的方法
      • 通过chain.doFilter(request,response)向下执行
    • public void destroy()
      • 销毁操作

FilterConfig(参考ServletConfig)

  • 在Filter的init方法中有一个参数FilterConfig
  • FilterConfig作用也是获取Filter的相关配置信息
    • 初始化参数的获取
    • Filter的名称获取
    • ServletContext对象获取

接口FilterConfig

  • public String getFilterName()
    • 如部署描述符中定义的那样,返回此过滤器的过滤器名称
  • public ServletContext getServletContext()
    • 返回对调用者在其中执行操作的ServletContext的作用
  • public String getInitParameter(String name)
    • 返回包含指定初始化参数的值的String,如果参数不存在,则返回null
  • public java.util.Enumeration<E> getInitParameterNames()
    • 以String对象的Enumeration的形式返回过滤器初始化参数的名称,如果过滤器没有初始化参数,则返回一个空的Enumeration。
public void init(FilterConfig filterConfig) throws ServletException{
    //获取Filter名称
    String filterName = filterConfig.getFilterName();
    System.out.println(filterName);
    //获取初始化参数
    String encoding = filterConfig.getInitParameter("encoding");//utf-8
    System.out.println(encoding);//utf-8
//
    Enumeration<String> names = filterConfig.getInitParameterNames();
    while(names.hasMoreElements()){
        System.out.println(names.nextElements());
    }//encoding,username

        //获取ServletContext对象
        filterConfig.getServletContext();

}
//web.xml配置文件
<filter>
    <filter-name>demo2Filter</filter-name>
    <filter-class>cn.itcast.web.filter.Demo2Filter</filter-class>
    <!--初始化参数-->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <init-param>
        <param-name>username</param-name>
        <param-value>tom</param-value>
    </init-param>
</filter>

Filter详细配置信息

关于配置Filter

<filter>
    <filter-name></filter-name>
    <filter-class></filter-class>
    <init-param>
        <param-name></param-name>
        <param-value></param-value>
    </init-param>

    <filter-mapping>
        <filter-name></filter-name>
        <url-pattern></url-pattern>
    </filter-mapping>
</filter>

Filter链

  • 在一个web应用中,可以开发编写多个Filter,这些Filter组合起来称之为一个Filter链
  • web服务器根据Filter在web.xml文件中的注册顺序<mapping>,决定先调用哪个Filter,当第一个Filter的doFilter方法被调用时,web服务器会创建一个代表Filter链的FilterChain对象传递给该方法 。在doFilter方法中,开发人员如果调用了FilterChain对象的doFilter方法,则web服务器会检查FilterChain对象中是否还有filter,如果有,则调用第二个filter,如果没有则调用目标资源。
  • 注意:
    • FilterChain.doFilter(request,response)它代表的是向下执行,如果下一个还是filter,那么访问这个filter,如果当前filter已经是整个链的末尾,那么访问web资源。
    • Filter的顺序由<Filter-mapping>的配置顺序决定。
//firstFilter
public class FirstFilter implements Filter{
    public void destroy{}
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
        System.out.pritnln("firstFilter...");
        chain.doFilter(request,response);//向下放行
        System.out.println("firstFilter end ...");
    }
    public void init(FilterConfig filterConfig) throws ServletException{

    }
}
//secondfilter
public class SecondFilter implements Filter{
    public void destroy{}
    public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
        System.out.pritnln("secondFilter...");
        chain.doFilter(request,response);//向下放行
        System.out.println("secondFilter end ...");
    }
    public void init(FilterConfig filterConfig) throws ServletException{
    }
}
//DemoServlet
public class DemoServlet extends HttpServlet{
    public void doGet(HttpServletRequest reequest,HttpServletResponse response) throws ServletException,IOException{
        Ssytem.out.pritnln("demo servlet");
    }
    public void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
        doGet(request,response);
    }


}
<!--firstFilter-->
<filter-mapping>
        <filter-name>firstFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
</filter-mapping>
<!--secondFilter-->
<filter-mapping>
        <filter-name>secondFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
</filter-mapping>

这里写图片描述

这里写图片描述

<url-pattern>

  • 对于Fliter来说,它是用于确定拦截资源路径
  • <url-pattern>有几种方法:
    • 完全匹配 必须以“/”开始
    • 可以使用* 通配符
      • 目录匹配
        • /a/* /* 要求必须“/”开始
      • 扩展名匹配
        • .do .action 要求,不能以“/”开始,以*.xxx结束

简单的编码过滤(只针对于post请求)

  • 编写一个jsp页面
  • 编写一个servlet,在servlet中获取请求参数
  • 问题:乱码问题
    • 对于post解决方法:request.setCharacterEncoding(“utf-8”);
  • 创建一个Filter,在Filter中完成编码处理

禁用jsp页面缓存

  • 禁用页面缓存的目的:为了得到实时信息
  • 禁用jsp页面缓存的方式
    • 在jsp页面上设置
    • <meta http-equiv="pargma" content = "no-cache">
    • <meta http-equiv="cache-control" content="no-cache">
    • <meta http-equiv="expires" content="0">
    • 可以通过Filter来控制
    • 在Filter中设置
      • response.setHeader(“pragma”,”no-cache”);
      • response.setHeader(“cache-control”,”no-cache”);
      • response.setDateHeader(“expires”,-1);
    • filter的url-pattern
      • *.jsp(jsp格式的)
<filter-mapping>
    <filter-name>cacheFilter</filter-name>
    <url-pattern>*.jdp</url-pattern>
</filter-mapping>
public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) throws IOException,ServletException{
    //强制转换
    HttpServletResponse request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)resp;
    //操作
    response.setDateHeader("expires",0);
    //放行
    chain.doFilter(request,response);

}

设置图片缓存时间

  • 让图片缓存,缓存的目的是为了提高性能和效率
  • filter的url-pattern
    • *.bmp(图片的格式)
public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) throws IOException,ServletException{
    //强制转换
    HttpServletResponse request = (HttpServletRequest)req;
    HttpServletResponse response = (HttpServletResponse)resp;
    //操作
    response.setDateHeader("expires",System.currentTimeMillis()+60*60*24*10*1000);//缓存10天
    //放行
    chain.doFilter(request,response);

}

自动登录案例

  • 在访问一个站点,登陆时勾选自动登陆(三个月内不用登录),操作系统后,关闭浏览器,过几天再次访问该站点时,直接进行登陆后状态。
  • 自动登陆原理:
    • 登录成功后,判断是否勾选了自动登录
    • 如果勾选了自动登录,将用户名与密码存储到cookie中
    • 做一个Filter,它拦截所有请求,当访问资源时,我们从cookie中获取用户名与密码,进行登录操作。

登录操作

  • 创建User数据库,user表,添加数据。
  • DataSourceUtils.java c3p0-config.xml User.java(javaBean)
  • login.jsp success.jsp
//success.jsp
<body>
    当前用户:${user.username}
</body>
//login.jsp
<body>
<!--展示异常信息-->
    ${requestScope["login.message"]}<br>
    <form action="${pageContext.request.contextPath}/login" method="post">
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        <input type="submit" value="登录">
    </form>

</body>
//LoginServlet.java  url:login
public class LoginServlet extends HttpServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
        //得到请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //登录 
        UserService service = new  UserService();
        try{
            User user = service.login(username,password);
            if(user != null){
                //登录成功
                request.getSession().setAttribute("user",user);
                response.senRedirect(request.getContextPath()+"/demo4/success.jsp")
                return;
            }else{
                request.setAttribute("login.message","用户名或密码错误");
                request.getRequestDispatche("/demo4/login.jsp").forward(request,response);
                return;
            }
        }catch(SQLException e){
            e.printStackTrace();
            request.setAttribute("login.message","登录失败");
            request.getRequestDispatche("/demo4/login.jsp").forward(request,response);
            return;
        }

    }

}
public class UserService throws SQLException{
    public User login(String username,String password){
        return new UserDao().findUserByUsernameAndPassword(username,password);


  }

}
public class UserDao{
    //根据用户名与密码查找用户
    public User findUserByUsernameAndPassword(String username,String password) throws SQLException{
        String sql = "select * from user where username=? and password=?";
        QueryRunner runner = new QueryRunner(DataSourceUtils.getDataSource());
        return runner.query(sql,new BeanHandler<User>(User.class),username,password);
    }
}

完成自动登录

  • 在页面上添加自动登录按钮
  • 在LoginServlet中
    *如果登录成功后,判断是否勾选了自动登录,如果勾选了,将用户名与密码存储到cookie中。
  • 创建一个AutoLoginFilter
//login.jsp
<body>
<!--展示异常信息-->
    ${requestScope["login.message"]}<br>
    <form action="${pageContext.request.contextPath}/login" method="post">
        username:<input type="text" name="username"><br>
        password:<input type="password" name="password"><br>
        <input type="checkbox" name="autologin" value="ok">自动登录<br>
        <input type="submit" value="登录">
    </form>

</body>
//LoginServlet.java中
public class LoginServlet extends HttpServlet{
    public void doGet(HttpServletRequest request,HttpServletResponse response) throws ServletException,IOException{
        //得到请求参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //登录 
        UserService service = new  UserService();
        try{
            User user = service.login(username,password);
            if(user != null){
                //登录成功
                //判断是否勾选了自动登录按钮
                String autologin = request.getParameter("autologin");
                if("ok".equals(autologin)){
                    //勾选了
                    //创建一个cookie
                    Cookie cookie = new Cookie(“autologin”,usernaem+"::"+password);
//cookie持久化
                    cookie.setMaxAge(60*60*24*10);//存储10天
                    cookie.setPath("/");
                    response.addCookie(cookie);

                }
                request.getSession().setAttribute("user",user);
                response.senRedirect(request.getContextPath()+"/demo4/success.jsp")
                return;
            }else{
                request.setAttribute("login.message","用户名或密码错误");
                request.getRequestDispatche("/demo4/login.jsp").forward(request,response);
                return;
            }
        }catch(SQLException e){
            e.printStackTrace();
            request.setAttribute("login.message","登录失败");
            request.getRequestDispatche("/demo4/login.jsp").forward(request,response);
            return;
        }
    }
}
public calss AutoLoginFilter implements Filter{
    public void destroy){

    }
    public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) throws IOException,ServletException{
        //强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //操作
        //得到cookie中的username.password
        Cookie cookie = CookieUtils.findCookidByName(request.getCookies(),"autologin");
        if(cookie != null){
            //找到了,进行自动登录
            String username = cookie.getValue().split("::")[0];
            String password = cookie.getValue().split("::")[1];
            UserService service = new UserService();
            User user = service.login(username,password);
            if(user != null){
                //查找到用户,进行自动登录
                request.getSession().setAttribute("user",user);
            }
        }
        //放行
        chain.doFilter(request,response);
    }
    public void init(FilterConfig filterConfig) throws ServletException{    
    }
}
public calss CookieUtils{
    public static Cookie findCookieByName(Cookie[] cs,String name){
        if(cs==null || cs.length==0){
            return null;
        }
        for(Cookie c : cs){
            fi(c.getName().equals(name)){
                return c;
            }
        }
        return null;
    }
}

问题分析:

  • 如果用户已经登录了,不需要自动登录。
  • 如果用户是进行例如,注册,登录操作,不需要自动登录。
    • 得到请求资源路径,判断是否是登录,注册操作
    • 例如:Http://localhost/day21-2/demo4/login.jsp
    • String uri = request.getRequestURI();—>/day21-2/demo4/login.jsp
    • String contextPath = requext.getContextPath();—>/day21-2
    • String path = uri.subString(contextPath.length());—>/demo4/login.jsp
public void doFilter(ServletRequest req,ServletResponse resp,FilterChain chain) throws IOException,ServletException{
        //强制转换
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse)resp;
        //操作
        //判断用户没有登录,才进行自动登录
        User u= (User)request.getSession().getAttribute("user");
        if(u==null){
                //得到cookie中的username.password
            Cookie cookie = CookieUtils.findCookidByName(request.getCookies(),"autologin");
            if(cookie != null){
            //找到了,进行自动登录
                String username = cookie.getValue().split("::")[0];
                String password = cookie.getValue().split("::")[1];
                UserService service = new UserService();
                User user = service.login(username,password);
                if(user != null){
                //查找到用户,进行自动登录
                    request.getSession().setAttribute("user",user);
                }
            }

        }
        //放行
        chain.doFilter(request,response);
    }

如果用户是中文,怎样处理?

  • cookie中不能存储中文的。
  • 存储时,存utf-8码,使用时解码
  • 存:Cookie cookie = new Cookie(“autologin”,URLEncoder.encode(username,”utf-8”)+”::”+password); (LoginServlet.java)
  • 取:String username = URLDecoder.decode(cookie.getValue().split(“::”)[0],”utf-8”); (AutoLoginFilter)

关于密码的安全性问题

  • 可以对密码进行加密 md5
  • mysql中加密方式:md5(字段)
    • update user set password = md5(password);
  • java中加密方式:
public class Md5Utils{
    public static STring md5(String plainText){
        byte[] secretBytes = null;
        try{
            secretBytes = MessageDigest.getInstance("md5").digest(plainText.getBytes());
        }catch(NoSuchAlgorithmException e){
            throw new RuntimeException("没有md5这个算法!")
        }
        String md5code = new BigInteger(1,sevretBytes).toString(16);
        for(int i=0;i<32-md5code.length();i++){
            md5code = "0"+md5code;
        }
        return md5code; 
    }
}
//UserDao.java
return runner.query(sql,new BeanHandler<User>(User.class),username,Md5Utils.md5(password));

url级别权限控制

  • 权限控制的原理
    • 可以做一个权限的Filter,在Filter中判断用户是否登录了,如果登录了,可以访问资源,如果没有登录,不能访问资源。
  • 问题1:怎样判断哪些资源需要权限,哪些资源不需要权限?
  • String uri = request.getrequestURI();
    String contextPath = request.getContextPath();
    String path = uri.substring(contextPath.length());
    if(path.equals("/book_add") || path.equals("/book_update")||path.equals("/book_delete")||path.equals("/book_search")){
    }
  • 问题2:我们的用户是有role的,如果admin,可以访问所有资源,而User只能访问book_search怎样处理。
if("admin".equals(user.getRole())){
    //这是admin角色
    if(!(path.equals("/book_add")||path.eauals("/book_update")||path.equals("/book_delete"))){
        throw new PrivilegeException();
    }else{
        //这是User角色
        if(!(path.equals("/book_search"))){
            throws new PrivilegeException();
        }
    }
}

对权限控制代码优化

主要对url路径的判断进行优化

  • 在src下创建两个配置文件,user.properties admin.properties
    • 在这两个文件中分别保存不同的角色具有的权限路径
    • 例如:admin.properties中url=/book_add,/book_delete,/book_update,/book_serch
  • 在PrivilegeFilter中完成权限控制
    • 在init方法中将配置文件中的信息读取出来分别保存到users,admins两个List<String>集合中。
      • ResourceBundle.getBundle(String baseName);
      • admin.properties文件它的基名就是admin
      • user.properties文件它的基名就是user.
      • 得到ResourceBundle对象,可以通过它的getString(String name);
      • bundle.getString(“url”);这就得到了配置文件中名称叫url的值。
    • 在判断时就比较方便
      • 判断资源路径是否需要权限控制
        • if(admins.contains(path) || users.contains(path))
    • 判断每一个角色是否可以访问资源路径
      • if(!(admins.contains(path))){
        throw new PrivilegeException();
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值