利用注解和反射实现超轻量级权限管理

项目中需要用到权限管理,但是角色非常少,觉得使用Spring Security会比较重。所以,打算自己写一个简单的角色检查,实现原理就是:

把用户的信息(一定要包含角色ID)放到Session里,然后在Controller方法上加注解,该注解会标记哪些角色可以访问,通过AOP反射解析注解,同时从Session里拿到请求用户的角色ID进行比较。

由于使用到了AspectJ,所以要在Spring的配置文件里声明下:

<aop:aspectj-autoproxy/>

先定义一个注解,它是角色ID被检查的载体:

/**
 * 这个注解用来确定哪些用户可以做哪些操作,目前我们只有3个角色,管理员,高级用户,普通用户。
 * 其中普通用户只能查看,管理员可以操作一切,高级用户只比管理员少了管理用户的功能。
 */
@Documented//文档  
@Retention(RetentionPolicy.RUNTIME)//在运行时可以获取  
@Target(ElementType.METHOD)//作用到类,方法,接口上等
public @interface RolesAllowed {
	public String value() default "";
}

再定义AOP拦截器,内部通过反射解析注解(顺带可以检查用户是否登录过):

/**
 * 这个类用来拦截请求,如果用户没有登录,则被要求先登录。
 * 任何请求访问的Controller的方法都会被检测,看是否包含
 * RolesAllowed注解,如果有就看当前登录用户是否有权限操作这个方法。
 */
@Component
@Aspect
public class RoleControlAspect {
	@Before("execution(* com.hebta.vinci.controller.*Controller.*(..))")  
    public void logBefore(JoinPoint joinPoint) throws Exception {
		HttpServletRequest request = ((ServletRequestAttributes) 
				RequestContextHolder.getRequestAttributes()).getRequest();
		HttpSession session = request.getSession();
		if (!(session != null || request.getRequestURI().contains("login") 
				|| request.getRequestURI().contains("logout"))){
			throw new RuntimeException("用户尚未登录。");
		}
		
		User user = new User();
		try {
			user = (User)session.getAttribute(VinciConstants.SESSION_ATTR_USER);
		} catch (Exception e) {
			throw new RuntimeException("用户没有登录过,请先登录。");
		}
		int roleId = 0;
		if (user != null){
			roleId = user.getRoleId();
		}
		
		MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
		Method method = methodSignature.getMethod();
		
		if (method.isAnnotationPresent(RolesAllowed.class)){
			RolesAllowed annotation = method.getAnnotation(RolesAllowed.class);
			if (annotation != null){
				String rolesStr = annotation.value();
				for (String role : rolesStr.split(",")){
					if (Integer.parseInt(role) == roleId){
						return;
					}
				}
				throw new RuntimeException("用户权限不够。");
			}
		}		
	}
}

这个类有几个需要注意的地方:

1. 必须加上@Component 注解,不然Spring的<mvc:annotation-driven/>扫描不到;

2. 必须使用 MethodSignature,不然无法获得Method 类,也就没办法获得定义其上的 RolesAllowed 注解。

最后就是在 Controller的方法上加上 RolesAllowed 注解,里面标上哪些角色可以访问,为了简单,我直接使用逗号分隔角色ID:

@RolesAllowed("6")
	@RequestMapping(value="{id}",method=RequestMethod.DELETE)
	public BaseResponse deleteUser(@PathVariable Integer id, HttpServletRequest request){
		BaseResponse resp = new BaseResponse<>(RESPONSE_STATUS.SUCCESS);
		
		int result = userService.deleteUser(id);
		if (result <= 0){
			resp.setStatus(RESPONSE_STATUS.FAIL);
			resp.setMsg("标记用户不可用失败。");
		} else {
			resp.setMsg("成功标记用户不可用。");
		}
		return resp;
	}

稍微补充下,可以定义一个专门拦截Controller 的拦截器,Spring 有个 @ControllerAdvice 注解,使用它就可以拦截所有Controller的事件,下面的代码只是拦截 Controller 里面抛出的异常。我们项目组开发是前后端分离的,所以只需要返回一个JSON字符串即可:

@ControllerAdvice
public class GlobalExceptionHandler {
	private static final Logger logger = Logger.getLogger(GlobalExceptionHandler.class);
	
	@ResponseBody
    @ExceptionHandler(value = Throwable.class)
    public BaseResponse<String> defaultErrorHandler(HttpServletResponse response, Throwable ex) throws Exception {
		BaseResponse<String> resp = new BaseResponse<>(RESPONSE_STATUS.FAIL);
		resp.setMsg(ex.getMessage());
		logger.debug("error occurs: ", ex);
		return resp;
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值