servlet极简单权限拦截设计处理
8gw234
10年前
在java web的开发中 遇到的极其简单的权限控制,整个小项目就分为四五种用户的权限角色,因此不想考虑使用框架以及数据库建角色表,菜单表,操作表等来完成权限设计,而是采用反射,注解的简单方法完成。
核心代码
BaseServlet.java文件
import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zk.annotation.Permission; import com.zk.bean.User; /** * servlet基类 * * @Description TODO * @author zk * @version 1.0 * @date 2015-4-9 下午4:53:11 */ @SuppressWarnings("all") public abstract class BaseServlet extends HttpServlet { private static final long serialVersionUID = -6898295798172047477L; protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { /** * 思路1 .根据method参数 处理 2.使用反射调用 * 2 加入简单的权限判断(当然也可以通过过滤器设计 拦截实现) * 由于本案例不需要复杂的权限设计,故没有采用分别建几张表 来存角色,菜单,操作等信息,只用在用户表添加一个字段 level 0 1,4,7来处理 * 0:此用户无效(软删除)相当于已经删除 * 1: 普通访客等级 无需登录 主要是前端的信息浏览 * 4 :会员等级 可以登录,进行相关操作 * 7 :顶级管理员操作 * 中间预留一些字段做不同的权限。 * 3权限判断的核心思路: * 1> 建一个 BaseServlet 父类 让之类Servlet继承 * 2> 在BaseServlet 中重写service 方法通过反射 以及在之类中的方法操作上加自定义注解【见下文自定义注解文件】 eg:@Permission(level=3) * 3> 在service 方法中通过 request.getParmenter("method") 获取在子类中对应的方法操作名称,并反射获取该方法名称 * 上面的注解信息 level * 4> 对注解信息 以及用户的登录状态 和用户的level状态进行判断 * 对于有些操作需要登录 或者权限等级较高的 就可以重定向处理拦截权限 * 0等级忽略 由于1 为 普通权限 故先判断是否为普通权限 就是普通网站访问者权限 * 当操作方法的leve为1 放行 * 不为1 说明需要更高的用户权限 * 那么首先判断是否登录 没有登录的 返回登录 * 登录成功的 获取登录用户的leve状态 和请求该方法的操作level权限等级对比 * 如果用户的leve小于该方法操作的 就拦截 返回,反之就可以进行方法操作 * * */ // 只处理了post的乱码问题,get自行处理 req.setCharacterEncoding("utf-8"); // 只是处理 了 字符流的问题,字节流自行处理 resp.setContentType("text/html;charset=utf-8"); String methodName = req.getParameter("method"); // 判断是否有方法 if (methodName == null || methodName.trim().isEmpty()) { throw new RuntimeException("亲!请传入method的参数"); } Class clazz = this.getClass(); Method method = null; try { method = clazz.getMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); // 注意 此处利用注解 获取 每一个请求方法上的注解信息 Permission info = method.getAnnotation(Permission.class); // 如果获取到注解信息 if (info != null) { int level = info.level();// 访问此操作需要的权限级别 if (level != 1) { // level 级别为默认的 最低等级 故无需处理 跳过 // level !=1 说明需要登录 以及更高等级的用户权限 User user = (User) req.getSession() .getAttribute("backUser"); // 判断是否登录 if (req.getSession().getAttribute("backUser") == null) { String contextPath = getServletContext() .getContextPath(); resp.getWriter() .print("亲,您还没有登录,请<a href='" + contextPath + "/index.jsp' target='_parent'>登录</a>!"); return; } else { // 登录成功 判断用户所拥有等级与 此操作的等级 if (user.getLevel() < level) { String contextPath = getServletContext() .getContextPath(); resp.getWriter() .print("对不起,你暂且无权限操作,请<a href='" + contextPath + "/index.jsp' target='_parent'>登录</a>申请为会员!"); return; } } } } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("亲!传入method的参数错误"); } try { String result = (String) method.invoke(this, req, resp); if (result != null && !result.trim().isEmpty()) { req.getRequestDispatcher(result).forward(req, resp); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }
自定义注解文件Permission.java
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义权限注解 * @Description TODO * @author zk * @version 1.0 * @date 2015-4-12 下午9:34:46 */ @Retention(RetentionPolicy.RUNTIME) @Target(value={ElementType.METHOD,ElementType.TYPE}) public @interface Permission { int level (); }
子类Servlet的操作 使用示例:
import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import com.zk.annotation.Permission; import com.zk.bean.Customer; import com.zk.bean.Message; import com.zk.bean.MessageType; import com.zk.bean.MessageTypeLev; import com.zk.bean.PageBean; import com.zk.bean.User; import com.zk.service.CustomerService; import com.zk.service.MessageService; import com.zk.service.MessageTypeService; /** * 和信息相关的控制器 继承自定义的BaseServlet * * @Description TODO * @author zk * @version 1.0 * @date 2015-4-11 上午10:21:56 */ public class MessageServlet extends BaseServlet { /** * 通过id删消息 * @param request * @param response * @return * @throws ServletException * @throws IOException */ @Permission(level = 3)// 注意 :注解的使用 不同的操作设置不同的值 public String deleteById(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String id = request.getParameter("id"); String pageCode = request.getParameter("pageCode"); String totalPage = request.getParameter("totalPage"); MessageService cs = new MessageService(); cs.deleteById(id); int pg = 1; if (Integer.parseInt(totalPage) % Integer.parseInt(pageCode) == 0) { if (Integer.parseInt(pageCode) > 1) { pg = Integer.parseInt(pageCode) - 1; } else { // 已结没有信息了 } } return "/message?method=listMsg&pageCode=" + pg; } }
附上user用户表设计的结构
-- ---------------------------- -- Table structure for t_customer -- ---------------------------- CREATE TABLE `t_customer` ( `id` varchar(40) NOT NULL, `username` varchar(20) DEFAULT NULL, `gender` varchar(10) DEFAULT NULL, `birthday` varchar(20) DEFAULT NULL, `cellphone` varchar(20) DEFAULT NULL, `email` varchar(40) DEFAULT NULL, `love` varchar(100) DEFAULT NULL, `type` varchar(40) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
总结:反射 注解 简单继承 统一处理。东西和思路比较粗糙,只是为了实现写简单功能,希望批判接受和建议,谢谢。