基于SpringMVC的注解式权限控制

1. 开发目标
在Shiro的权限分配中,存在@RequiresPermissions注解进行权限的控制,该注解规定了所进行了注解的方法,只能被具有某些权限的人进行访问,且权限之间为&的关系。这个权限控制是不符合我们所需要的权限控制需求的。(我们所需要的是具有某些权限之一的用户可以访问,同时具有这些权限的子权限也可以访问与具有这些权限本身和其父权限才能进行访问的这两种情况区分开)。

我们在该博客中所描述的权限控制,是一种类似于Shiro的注解式权限控制。做到使用@ExistPermissions和@HasPermissions来进行权限控制的目的。

2. 配置拦截器配置
配置一个类为SpringMVC的拦截器时,只需要在SpringMVC.xml中添加如下代码即可:

mvc:interceptors
mvc:interceptor

<mvc:mapping path="/**"/>

<mvc:exclude-mapping path="/user/login.do"/>

</mvc:interceptor>
mvc:interceptor
</mvc:interceptors>

其中接口preHandle中的代码会在访问到controller层接口前运行,而afterCompletion与postHandle接口则是在controller层运行完毕后,才会运行代码。因此我们在进行权限处理时,要将权限控制代码写在preHandle方法中。在上述XML配置中,将SecurityFilter 类作为拦截器进行了处理。这个拦截器需要先实现接口HandlerInterceptor 。在该接口中有三个方法,分别为afterCompletion,postHandle,preHandle。

3. 注解配置
在这里我们还需要定义两个注解@ExistPermissions和@HasPermissions。

/**
*

  • @author Administrator
  • 该注解用于进行对权限的控制,
  • 当用户的权限中存在该权限或改权限的子权限时,则予以放行
  • 相关代码需查看SecurityFilter
    /
    @Target(value={ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ExistPermissions {
    /
    *
    • 可以访问所进行注解的权限的数组对象,
    • 当具有该数组对象中任意权限的子权限时,均可以进行访问
      */
      String[] permissions();
      }

/**
*

  • @author Administrator
  • 该注解用于进行对权限的控制,
  • 必须在用户持有某些权限中的一个时,才则予以放行
  • 相关代码需查看SecurityFilter
    /
    @Target(value=ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface HasPermissions {
    /
    *
    • 可以访问所进行注解的权限的数组对象,
    • 当具有该数组对象中的任意一个权限时,可以进行访问
      */
      String[] permissions();
      }
      我们在这两个注解中分别定义了一个方法permissions,这个方法返回类行为String[],用于进行多权限的处理。这样我们就可以一次性对多个权限进行判断。@Target注解定义了这个方法可以用在那些地方,@Retention注解定义了这个方法在什么时候进行使用。

4. preHandle方法
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
}
在方法preHandle 中有三个参数,request,response,handler。前两个参数大家都是十分熟悉的,不做描述,重点在于第三个参数handler。

handler对象是一个object对象,因此,我们需要先通过 handler.getclass()方法来查看这个方法的具体类型。

经过

system.out.println(handler.getclass());

可以发现这个对象本身的类型是

org.springframework.web.method.HandlerMethod

那么此时,我们对这个对象进行强制转换,将其强转为它本身的类型。

5. HandlerMethod 类
HandlerMethod,见名知意,这是一个与method相关类,这个类是SpringMVC中定义的一个用于承载一个方法的相关信息的类。我们可以通过这个类的实例来获取该所进行@requestMapping 注解的方法的相关信息。

我们所需要使用的部分为注解部分的内容。从HandlerMethod中获取我们所需要的@HasPermissions 注解,然后从注解中获得所我们要进行验证的权限的字符串。

HasPermissions hasPermissions = handlerMethod.getMethodAnnotation(HasPermissions.class);
for(String permission : hasPermissions.permissions()){

}

6. preHandle方法逻辑处理

当然,用类似的方法,我们也可以获取这个方法上的其他注解,如requestMapping注解。

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//获取用户权限信息列表
UserInfo user = (UserInfo) request.getSession().getAttribute(“userInfo”);
if(user == null){
return false ;
}
Set permissions = user.getPermissions();
//获取相应权限注解信息
HandlerMethod handlerMethod = (HandlerMethod) handler;
//验证用户是否持有其中一个权限
HasPermissions hasPermissions = handlerMethod.getMethodAnnotation(HasPermissions.class);
boolean hasPer = false;
if(hasPermissions != null){
for(String permission : hasPermissions.permissions()){
if(this.hasPermission(permissions, permission)){
hasPer = true;
break;
}
}
}else{
hasPer = true;
}

	//验证用户是否持有其中一个权限,或者其中一个权限的子权限
	ExistPermissions existPermissions = handlerMethod.getMethodAnnotation(ExistPermissions.class);
	boolean existPer = false;
	if(existPermissions != null){
		for(String permission : existPermissions.permissions()){
			if(this.hasPermission(permissions, permission)){
				existPer = true;
				break;
			}
		}
	}else{
		existPer = true;
	}
	if(hasPer && existPer){
		return true;
	}else{
		System.out.println("用户 "+user.getUserName()+" 越权访问:"+request.getRequestURL().toString());
		return false;
	}
}

/**
* 验证用户是否持有一个权限,或者一个权限的子权限
* @param permissions
* @param permission
* @return
/
public boolean hasPermission(Set permissions, String permission){
for(String userPermission : permissions){
if(permission.substring(0, userPermission.length()).equals(userPermission)){
return true;
}
}
return false;
}
/
*
* 验证用户是否持有一个权限
* @param permissions
* @param permission
* @return
*/
public boolean existPermission(Set permissions, String permission){
for(String userPermission : permissions){
if(userPermission.substring(0, permission.length()).equals(permission)){
return true;
}else if(permission.substring(0, userPermission.length()).equals(userPermission)){
return true;
}
}
return false;

————————————————
版权声明:本文为CSDN博主「周重智」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35427785/article/details/72956472

发布了5 篇原创文章 · 获赞 3 · 访问量 2105

猜你喜欢

转载自blog.csdn.net/qq_26023835/article/details/104245603