您的位置:首页 > 编程语言 > Java开发

struts下通过过滤器进行权限控制

2011-07-13 17:29 417 查看

权限验证

(代码中部分删除,保留框架)

1.struts框架安全隐患

使用Struts框架时,权限通常控制在Action级(比如将权限验证放在Action的基类中,这样新的Action都继承于这个Action基类,所有Action就可以专注于业务逻辑,而不需要重复地进行权限控制了),这也符合MVC中的角色划分。然而,这会产生一个安全隐患。因为权限控制在Action中,所以,页面也就没有安全屏障了。一般的新增数据、更新数据不会有什么问题,因为这些数据必须通过HTML的Form提交到Struts的中心控制器,最终由相应的Action来处理,所以Action中就可以验证该用户的权限了。然而,对于一些不需要Action进行数据存取,或者有的页面没有严格按照MVC的角色划分而在页面中有获取数据的代码,那么这个页面就危险了。比如,显示一张通知页面,通常可以通过配置权限,使部分授权的用户才可以看到该级别的通知。这个通知页面是不需要从数据库中获取数据的。所以,可以不通过Action的调用来显示,而是直接敲入显示该通知的页面的链接就可以看到了。甚至不需要登录系统,不用管是否有查看该通知的权限!
比如下图中:
请求1: http://.../XXX.do 是通过正常的途径访问的,需要经过权限验证。
而请求2: http://.../XXX.jsp 则完全绕过了权限检查,任何人,不需要登录系统就可以访问到该信息了。



2.解决方案

解决的办法: 采用servlet过滤器
servlet过滤器是小型的web组件,它能够处理传入的请求和传出的响应。Filter 不是一个servlet,它不能产生一个response,它能够在一个request到达servlet之前预处理request,也可以在离开servlet时处理response。它具有高度的透明性,无需更改应用程序代码,就可以根据需要添加、修改或从应用程序中将它删除。
一个filter 包括:
1. 在servlet被调用之前截获;
2. 在servlet被调用之前检查servlet request;
3. 根据需要修改request头和request数据;
4. 根据需要修改response头和response数据;
5. 在servlet被调用之后截获.
你能够配置一个filter 到一个或多个servlet;单个servlet或servlet组能够被多个filter 使用。几个实用的filter包括:用户辨认filter,日志filter,审核filter,加密filter,符号filter,能改变xml内容的XSLT filter等。
一个客户化的过滤器要实现Filter接口的三个方法:init()、destroy()和doFilter()。
1. init():在容器实例化过滤器时调用,该方法接受一个FilterConfig类型的对象做为输入。
2. destroy():执行一些清理操作。
3. doFilter():类似servlet的doPost()、doGet()方法,执行具体的过滤任务。
设置URL拦截器,对截获的请求url(两部分包括XXX.do和XXX.Jsp)做权限验证,具有该权限则继续下一步,否则跳转到相应页面显示用户没有权限。



3.具体步骤

统过滤器配置具体步骤:

1. 首先写一个权限过滤filter类,实现Filter接口

jsp权限过滤器permissionFilter
package dao;import javax.servlet.Filter;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.FilterChain;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import po.login;/* * jsp安全过滤器 * filter:permissionFilter * */public class permissionFilter implements Filter { // 1,doFilter方法的第一个参数为ServletRequest对象。 // 此对象给过滤器提供了对进入的信息(包括表单数据、cookie和HTTP请求头)的完全访问。 // 第二个参数为ServletResponse,通常在简单的过滤器中忽略此参数。 // 最后一个参数为FilterChain,此参数用来调用servlet或JSP页。 private FilterConfig filterConfig; private FilterChain chain; private HttpServletRequest request; private HttpServletResponse response; public void destroy() { this.filterConfig = null; } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) { this.chain = chain; this.request = (HttpServletRequest) servletRequest; // 如果处理HTTP请求,并且需要访问诸如getHeader或getCookies等在ServletRequest中无法得到的方法, // 就要把此request对象构造成HttpServletRequest this.response = ((HttpServletResponse) servletResponse); // 获取当前页面文件名此处url为:/Gzlkh/login.jsp String url = request.getRequestURI(); // 此处截取的url为:login.jsp url = url.substring(url.lastIndexOf("/") + 1, url.length()); try { HttpSession session = request.getSession(); // 获取网站访问根目录 String accessPath = request.getContextPath(); // 获取用户登录验证信息 login st = (login) session.getAttribute("st"); if (noFileUrl(url, request)) { // 不需要判断权限的请求如登录页面,则跳过 chain.doFilter(request, response);// 继续执行请求 } else if (st == null) { response.sendRedirect(accessPath + "/login.jsp");// 未登录或超时,返回登陆页面 } else { verifyUrl(url, st);// 判断当前user是否拥有访问此url的权限 } } catch (Exception sx) { sx.printStackTrace(); } } /** * 判断当前user是否拥有访问此url的权限 * @param url * 当前请求的url * @param st * 当前登录用户信息 * @throws IOException * @throws ServletException */ private void verifyUrl(String url, login st) throws IOException, ServletException {// 获取user拥有的所有资源串,此处全部提取出来,以方便以后项目扩展//更好的方式是把此处的权限页面存储在数据库中,与角色建立关系,以后可以直接根据用户角色从//数据库中取出 String sturl = null;// 拥有权限页1的jsp页面String url1="";// // 拥有权限页2的jsp页面String url2 = ""// // 拥有权限页3的jsp页面 String url3 = ""; // 拥有权限页4的jsp页面 String url4 = ""; // // 拥有权限页5的jsp页面 String url5 = ""; // 拥有权限页6的jsp页面 String url6 = ""; // 公共 String url7 = ""; sturl = url7; //以下判断用户是否有进入该页面的权限,有则加入 if ("1".equals(st.getKhbfqx())) { sturl = sturl + "," + url1; } if ("1".equals(st.getRcgzqx())) { sturl = sturl + "," + url2; } if ("1".equals(st.getKhzbqx())) { sturl = sturl + "," + url3; } if ("1".equals(st.getKhjgqx())) { sturl = sturl + "," + url4; } if ("1".equals(st.getXtpzqx())) { sturl = sturl + "," + url6; } if ("1".equals(st.getYhglqx())) { sturl = sturl + "," + url5; } if (sturl.indexOf(url) >= 0) { //判断用户权限页面包含请求url里面的页面 chain.doFilter(request, response); } else { //用户无权限跳转提示 response.setContentType("text/html;charset=GBK"); response.getWriter().println("<div style='margin: 100 auto;text-align: center; " + "font: bold 18px 宋体;color: #0066CC;vertical-align: middle'> Sorry,您没有权限访问该资源!</div>"); } } /** * 特殊页面判断 * 是否需要判断权限,如客户端浏览、登录页面则不需要判断权限 */ protected boolean noFileUrl(String url, HttpServletRequest request) { //不需要权限验证的页面动作等 String exclude = "xx.jsp"; //判断请求页面是否是特殊页面 if (exclude.indexOf(url) >= 0) { return true; } return false; }}
Action权限过滤器permissiondoFilter
package dao; import javax.servlet.Filter;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.FilterChain;import java.io.IOException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.http.HttpServletResponse;import po.login; public class permissiondoFilter implements Filter { //1,doFilter方法的第一个参数为ServletRequest对象。 //此对象给过滤器提供了对进入的信息(包括表单数据、cookie和HTTP请求头)的完全访问。 //第二个参数为ServletResponse,通常在简单的过滤器中忽略此参数。 //最后一个参数为FilterChain,此参数用来调用servlet或JSP页。 private FilterConfig filterConfig; private FilterChain chain; private HttpServletRequest request; private HttpServletResponse response; public void destroy() { this.filterConfig = null; } public void init(FilterConfig filterConfig) throws ServletException { this.filterConfig = filterConfig; } public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) { this.chain = chain; this.request = (HttpServletRequest) servletRequest; //如果处理HTTP请求,并且需要访问诸如getHeader或getCookies等在ServletRequest中无法得到的方法,就要把此request对象构造成HttpServletRequest this.response = ((HttpServletResponse) servletResponse); // 获取当前页面文件名此处url为:/Gzlkh/login.jsp String url = request.getRequestURI(); // 此处截取的url为:login.jsp url = url.substring(url.lastIndexOf("/") + 1, url.length()); try { // 排除后台不作权限控制的页面名 // 登陆页面无需验证文件 HttpSession session = request.getSession(); // 获取网站访问根目录 String accessPath = request.getContextPath(); login st = (login) session.getAttribute("st"); if (noFileUrl(url, request)) { // 不需要判断权限的请求如登录页面,则跳过 chain.doFilter(request, response); } else if (st == null) { response.sendRedirect(accessPath + "/login.jsp");// 返回登陆页面(未登录或超时) } else { System.out.println(st.getRolename()+st.getUsername()+"-访问-"+url); verifyUrl(url, st);// 判断当前user是否拥有访问此url的权限 } } catch (Exception sx) { sx.printStackTrace(); } } /** * @param url * 当前请求的url * @param user * 当前登录用户 * @throws IOException * @throws ServletException */ private void verifyUrl(String url, login st)throws IOException, ServletException { // 获取user拥有的所有资源串 String sturl=null; String url1=""; String url2=""; // 考核结果页面 String url3=""; // 用户管理页面 String url4=""; // 权重配置页面 String url5=""; // 个人密码修改公共 String url6=""; sturl=url6; if("1".equals(st.getRcgzqx())){ sturl=sturl+","+url1; } if("1".equals(st.getKhzbqx())){ sturl=sturl+","+url2; } if("1".equals(st.getKhjgqx())){ sturl=sturl+","+url3; } if("1".equals(st.getXtpzqx())){ sturl=sturl+","+url4; } if("1".equals(st.getYhglqx())){ sturl=sturl+","+url5; } if(sturl.indexOf(url)>=0){ System.out.println("有权访问!"); chain.doFilter(request, response); }else{ System.out.println("无权限!"); response.setContentType("text/html;charset=GBK"); response.getWriter().println("<div style='margin: 100 auto;text-align: center;background-image:url(images/bg.jpg); " + "font: bold 18px 宋体;color: #0066CC;vertical-align: middle'> Sorry,您没有权限访问该资源!</div>"); } } /** * 是否需要判断权限,如客户端浏览、登录页面则不需要判断权限 */ protected boolean noFileUrl(String url, HttpServletRequest request) { String exclude = "login.do"; if (exclude.indexOf(url)>=0) { return true; } return false; } }

2.配置 Servlet过滤器

容器通过 Web 应用程序中的配置描述符 web.xml 文件了解过滤器。有两个新的标记与过滤器相关:<filter> 和 <filter-mapping>。应该指定它们为 web.xml 文件内 <web-app> 标记的子标记。
过滤器定义的元素
<filter> 标记是一个过滤器定义,它必定有一个 <filter- name> 和 <filter-class> 子元素。
<filter-name> 子元素给出了一个与过滤器实例相关的、基于文本的名字。
<filter-class> 指定了由容器载入的实际类。您能随意地包含一个 <init-param> 子元素为过滤器实例提供初始化参数。

<!--权限jsp过滤器--> <filter > <filter-name>permission </filter-name> <filter-class>dao.permissionFilter</filter-class> </filter> <filter-mapping> <filter-name>permission </filter-name> <!-- 只过滤 .jsp 结尾的url, 其余的如 .do, .html, .jpg, .css 等不作过滤--> <url-pattern>*.jsp</url-pattern> </filter-mapping>
<!--权限do过滤器--> <filter > <filter-name>permissiondo </filter-name> <filter-class>dao.permissiondoFilter</filter-class> </filter> <filter-mapping> <filter-name>permissiondo </filter-name> <!-- 只过滤 .do 结尾的url, 其余的如 .jsp, .html, .jpg, .css 等不作过滤--> <url-pattern>*.do</url-pattern> </filter-mapping>

原文地址:http://blog.csdn.net/ttff521xx/article/details/4430143
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: