aop (权限控制之功能权限)
在实际web开发过程中通常会存在功能权限的控制,不如这个角色只允许拥有查询权限,这个角色拥有CRUD权限,当然按钮权限显示控制上可以用button.tld来控制,本文就不说明。
具体控制流程就是通过登录系统时候请求控制层将用户的所拥有功能权限查询出来存入session中,然后通过aop切面编程技术获取session里的功能权限与当前方法标签注解权限匹配,当存在则继续执行,若不存在,通过springmvc简单的异常重定向到自己的无权限页面。
1、配置注解方式
privilegeInfo.java
package com.tp.soft.common.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface PrivilegeInfo { String name() default ""; }
2、通过反射获取注解上的标签的封装类
PrivilegeInfoAnnotationParse.java
package com.tp.soft.common.util; import java.lang.reflect.Method; public class PrivilegeInfoAnnotationParse { public static String parse(Class targetClass, String methodName) throws NoSuchMethodException, SecurityException{ String privilegeName = ""; Method method = targetClass.getMethod(methodName); //判断方法上是否存在@PrivilegeInfo 注解 if(method.isAnnotationPresent(PrivilegeInfo.class)){ //获取注解对象 PrivilegeInfo annotation = method.getAnnotation(PrivilegeInfo.class); //获取注解对象上的名字@PrivilegeInfo(name="admin") //即name为"admin" privilegeName = annotation.name(); } return privilegeName; } }
3、创建控制层
LoginController.java
具体session创建在之前那一篇文章中有写到,通过拦截器创建的
package com.tp.soft.controller; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.tp.soft.common.util.SysContext; import com.tp.soft.entity.Privilege; import com.tp.soft.entity.User; @Controller public class LoginController { @RequestMapping(value = "/login") public ModelAndView login() { // 这里创建一个对象当做登录成功 User user = new User(); user.setLogin_name("taop"); user.setLogin_pwd("1"); // 登录查询 if (user != null) { // 根据用户查询出所有权限,本来存入数据库,这边就生动生成taop的权限 // 不如只有添加权限 Privilege privilege = new Privilege(); privilege.setName("query"); privilege.setDesc("查詢权限"); List<Privilege> privilegeList = new ArrayList<Privilege>(); privilegeList.add(privilege); SysContext.getSession().setAttribute("privileges", privilegeList); SysContext.getSession().setAttribute("user", user); return new ModelAndView("/pc/main"); } return null; } @RequestMapping(value="/toHasNoPower") public ModelAndView toHasNoPower(){ return new ModelAndView("/pc/privilege/noPower"); } }
UserController.java
package com.tp.soft.controller; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.annotation.Resource; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.tp.soft.common.util.PrivilegeInfo; import com.tp.soft.common.util.SysContext; import com.tp.soft.entity.Privilege; import com.tp.soft.entity.User; import com.tp.soft.service.login.LoginSvc; import com.tp.soft.service.sys.UserSvc; @Controller public class UserController { @Resource private UserSvc userSvc; @Resource private LoginSvc loginSvc; @RequestMapping(value="/toQueryUser") @PrivilegeInfo(name="query") public ModelAndView toQueryUser(){ User user = userSvc.getUser(21); Map<String, Object> map = new HashMap<String, Object>(); map.put("user", user); return new ModelAndView("/pc/userTest"); } }
@PrivilegeInfo(name="query") 可以通过数组的形式 如name={"query", "add"}
创建异常类
AssessDeniedException.java
package com.tp.soft.common.exception; public class AssessDeniedException extends RuntimeException{ /** * */ private static final long serialVersionUID = 5188167616201017971L; public AssessDeniedException() { super(); // TODO Auto-generated constructor stub } public AssessDeniedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { super(message, cause, enableSuppression, writableStackTrace); // TODO Auto-generated constructor stub } public AssessDeniedException(String message, Throwable cause) { super(message, cause); // TODO Auto-generated constructor stub } public AssessDeniedException(String message) { super(message); // TODO Auto-generated constructor stub } public AssessDeniedException(Throwable cause) { super(cause); // TODO Auto-generated constructor stub } }
创建权限对象
Privilege.java
public class Privilege { private int pid; private String name; private String desc; ...省略set get }
4、配置aop切面类
AdminAspect.java
package com.tp.soft.aop; import java.util.List; import javax.servlet.http.HttpSession; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import com.tp.soft.common.exception.AssessDeniedException; import com.tp.soft.common.util.PrivilegeInfoAnnotationParse; import com.tp.soft.common.util.SysContext; import com.tp.soft.entity.Privilege; import com.tp.soft.entity.User; @Aspect public class AdminAspect { @Pointcut("execution(* com.tp.soft.controller..*.*(..)) && !execution(* com.tp.soft.controller.LoginController.*(..))") public void pointCutMethod(){ } @Around("pointCutMethod()") public Object dealPrivilege(ProceedingJoinPoint jpj) throws Throwable{ //获取请求的类和方法名 Class<? extends Object> cls = jpj.getTarget().getClass(); String name = jpj.getSignature().getName(); System.out.println(cls); System.out.println(name); //获取注解上的标签 String privilegeName = PrivilegeInfoAnnotationParse.parse(cls, name); HttpSession session = SysContext.getSession(); User user = (User) session.getAttribute("user"); List<Privilege> privileges = (List<Privilege>) session.getAttribute("privileges"); if(user == null){ throw new AssessDeniedException("您无权操作!"); } //是否通过访问 boolean flag = false; if(privilegeName == "" || privilegeName == null){ flag = true; }else{ for (Privilege privilege : privileges) { if(privilegeName.equals(privilege.getName())){ //用户访问权限(add) 是否包含当前方法的访问权限 flag = true; break; } } } if(flag){ return jpj.proceed(); }else{ //权限不足 System.out.println("权限不足"); throw new AssessDeniedException("您无权操作!"); } } }
配置spring-mvc.xml 异常类重定向跳转
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver"> <property name="exceptionMappings"> <props> <prop key="com.tp.soft.common.exception.AssessDeniedException">forward:/toHasNoPower</prop> </props> </property> </bean>
当无权限抛出异常时候即会重定向到toHashNoPower 然后modelandview 自己写的一个无权限的页面
至此全部结束
请求结果:当直接访问查询方法
当访问
再访问
当将权限设置成
继续访问