S2SH基于角色权限拦截
对于B/S应用的权限拦截主要有粗密度和细密度两种:
A.粗密度:对于粗密度的权限拦截不过是拦截相应的URL然后再判断例如用户是否登录 如果没登陆跳转到登录页面,已经登录了的就继续执行,对于这种拦截只需要配置一个filter 在web.xml中加入相应的配置 在mapping里面加入要拦截的URL,这个很简单
B.细密度:对于这种拦截是实现例如:商品部的员工不能拥有增删员工的权限,而拥有和商品操作相关的权限 对商品部的员工访问的所有她没有的权限的操作都要拦截 禁止他的执行
我使用的是基于角色的方式 即把相应的角色拥有的说有权限(SystemPrivilege)放在一个组(PrivilegeGroup)里面,然后将这个组附给应的员工(Employee), 这样我们只要看访问当前操作的用户的权限组里面是否有执行当前操作的权限就能判断了,对于权限的标识有两个属性:模块(module) 和权限值(privilege) 我把它放在了一个类里面 ,也可以不放。 模块表示的是你当前操作的模块 权限值是例如 CRUD 当你有 (product,update)这个权限时即拥有商品模块的更新商品的权限下面是关于权限相关的简单类图 :
(类图是用Rational Rose画的 由于很久没用过了 里面怎么表示关系忘了 那些什么多对多什么的就没画)
实现:对于上面说到的实体类就不详细说了 主要说的是权限拦截 我使用的是基于注解和自定义标签
1.首先创建注解类
2.有了这个类我们就能在要拦截的方法上加上这个注解了
对于现在的注解而言一点效果都没有 我们只是标注了你要使用该edit()方法那么你就要有(product,update)这个权限
3.要真正的实现拦截了 一开始准备使用spring的AOP技术但是我这个注解是放在action的方法上的并不是service的接口上使用要使用到cglib ,而且当我加上@Aspect标签标注切入点时 action里面所以由spring的IOC注入的service全部为空了,所以想想还是用简单点的东西吧 所以选择了struts2的Interceptor拦截器它也是AOP
1 import java.lang.reflect.Method; 2 3 import javax.servlet.http.HttpServletRequest; 4 5 import org.apache.struts2.ServletActionContext; 6 import org.aspectj.lang.annotation.Aspect; 7 8 import com.opensymphony.xwork2.ActionInvocation; 9 import com.opensymphony.xwork2.interceptor.AbstractInterceptor; 10 import com.yixi.shopping.model.privilege.Employee; 11 import com.yixi.shopping.model.privilege.PrivilegeGroup; 12 import com.yixi.shopping.model.privilege.SystemPrivilege; 13 import com.yixi.shopping.model.privilege.SystemPrivilegePK; 14 import com.yixi.shopping.util.SiteUrl; 15 import com.yixi.shopping.util.WebUtil; 16 import com.yixi.shopping.web.action.privilege.Permission; 17 18 public class PermissionInterceptor extends AbstractInterceptor { 19 20 private static final long serialVersionUID = -446959629705298377L; 21 22 /** 23 * 1、通过动态代理类和反射机制获取调用的方法 24 * 2、获取方法的Permission注解 25 * 3、获取Permission中包含的权限信息(构造SystemPrivilege权限类) 26 * 4、和用户的权限信息进行对比(PrivilegeGroup中的SystemPrivilege)判断用户的权限 27 */ 28 @Override 29 public String intercept(ActionInvocation invocation) throws Exception { 30 31 HttpServletRequest request = ServletActionContext.getRequest(); 32 if(WebUtil.getRequestURI(request).startsWith("/control/")){ 33 String methodName = invocation.getProxy().getMethod(); 34 Method method = invocation.getAction().getClass().getMethod(methodName); 35 if(method!=null && method.isAnnotationPresent(Permission.class)){ 36 System.out.println("Call the Action Method:" + method.toString()); 37 //获取当期执行的Action上的注解 38 Permission permission = method.getAnnotation(Permission.class); 39 System.out.println("当前需要的权限为:" + permission.moudle()); 40 //获取当期执行的Action方法需要的权限 41 SystemPrivilege methodPrivilege = new SystemPrivilege(new SystemPrivilegePK(permission.moudle(),permission.methid())); 42 //WebUtil.getEmployee(request) 方法是从session中获取保存的employee信息,包括权限集合 43 Employee employee = WebUtil.getEmployee(request); 44 //循环判断用户是否具有该权限,如果有则继续执行,否则返回提示视图 45 for(PrivilegeGroup group : employee.getGroups()){ 46 if(group.getPrivileges().contains(methodPrivilege)){ 47 return invocation.invoke(); 48 } 49 } 50 System.out.println("权限不足"); 51 request.setAttribute("message", "你没有执行该操作的权限"); 52 request.setAttribute("urladdress", SiteUrl.readUrl("control.center.right")); 53 return "message"; 54 } 55 System.out.println("未设置权限"); 56 return invocation.invoke(); 57 } 58 System.out.println("所有权限"); 59 return invocation.invoke(); 60 } 61 62 }
这样你就能实现拦截了,但是问题又来了 在页面上虽然我们不能执行那个操作但是相应的按钮却还在那里 既然我没有修改的权力那么那个修改的按钮就不应该让我看到要完成这个功能就要使用到自定义标签了
B.自定义标签
实现:
1.编写标签类 如下:
1 import java.util.Set; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.jsp.JspException; 5 import javax.servlet.jsp.tagext.TagSupport; 6 7 import com.yixi.shopping.model.privilege.Employee; 8 import com.yixi.shopping.model.privilege.PrivilegeGroup; 9 import com.yixi.shopping.model.privilege.SystemPrivilege; 10 import com.yixi.shopping.model.privilege.SystemPrivilegePK; 11 import com.yixi.shopping.util.WebUtil; 12 13 /** 14 * 15 * 定义权限标签 16 * @author 罗宏 17 * 18 */ 19 public class PermissionTaglib extends TagSupport { 20 private static final long serialVersionUID = -1603078353787859001L; 21 22 private String moudle; 23 private String methid; 24 public String getMoudle() { 25 return moudle; 26 } 27 public void setMoudle(String moudle) { 28 this.moudle = moudle; 29 } 30 public String getMethid() { 31 return methid; 32 } 33 public void setMethid(String methid) { 34 this.methid = methid; 35 } 36 37 @Override 38 public int doStartTag() throws JspException { 39 boolean result= false; 40 Employee employee = WebUtil.getEmployee((HttpServletRequest) pageContext.getRequest()); 41 SystemPrivilege systemPrivilege = new SystemPrivilege(new SystemPrivilegePK(moudle, methid)); 42 Set<PrivilegeGroup> set = employee.getGroups(); 43 for (PrivilegeGroup privilegeGroup : set) { 44 if(privilegeGroup.getPrivileges().contains(systemPrivilege)){ 45 result = true; 46 break; 47 } 48 } 49 return result ? EVAL_BODY_INCLUDE : SKIP_BODY; 50 } 51 }
编写标签类的时候一定要重写它的doStartTag()方法 也就是在页面执行到这个标签后这里后就会执行这个方法 这里里面的代码也是用于权限比较 根据返回的值判断是否执行标签中的内容
2.将自己的标签文件加入到WEB-INF目录下 文件的格式都是一样的
圈起来的地方要注意 没圈的地方可以随意写
3.在页面上加注解
当加上这个注解后那么就可以根据你的权限的有无显示相应的按钮了。