权限管理系统
Posted 未来畅想--娜
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了权限管理系统相关的知识,希望对你有一定的参考价值。
权限可以分为两大类:操作权限与数据权限。见此篇博文:http://blog.csdn.net/sharetop/article/details/50281669。
Shiro帮我们实现的大多为操作权限,那么今天我想分享一个数据权限的方案,主要采用的仍是注解+切面拦截。
思路大概是这样的:
- 在controller的方法参数,约定包含一个Map类型的parameters
- 通过注解声明一下当前用户的某个成员属性值需要被插入到这个parameters中,并且声明对应的字段名称
- 在方法体中,就可以将parameters中所有成员拿出来生成SQL,实现数据的筛选。
比如,我们需要根据当前登录用户的名称realName,筛选出saleName为当前用户名称的销售数据,又或者,根据当前登录用户的groupNames[0]为北京,筛选出所有数据字段province为北京的计费数据。
首先,我们定义注解 RequiresData,代码如下:
@Target(ElementType.TYPE, ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresData
String[] props() default "";
String[] fields() default "";
两个属性都是字符串数组,所以我们要使用时可以是这样的:
@RequiresData(props="realName","groupNames[0]",fields="saleName","province")
然后,我们需要修改AuthorizationAttributeSourceAdvisor,同样添加对新注解的支持。
private static final Class<? extends Annotation>[] AUTHZ_ANNOTATION_CLASSES =
new Class[]
RequiresPermissions.class, RequiresRoles.class,
RequiresUser.class, RequiresGuest.class, RequiresAuthentication.class,
RequiresAction.class,RequiresData.class
;
也同样修改我们继承的AopAllianceAnnotationsAuthorizingMethodInterceptor,添加新的DataAnnotationMethodInterceptor支持。
public AopAllianceAnnotationsAuthorizingMethodInterceptor()
super();
this.methodInterceptors.add(new ActionAnnotationMethodInterceptor(new SpringAnnotationResolver()));
this.methodInterceptors.add(new DataAnnotationMethodInterceptor(new SpringAnnotationResolver()));
这次我们的DataAnnotationHandler是不需要做任何事情的,因为我们不是做权限验证,而是要修改方法参数。
所以,我们需要先定义一个接口。
public interface DataParameterRequest
Map<String,String> getParameters();
保证我们在方法参数实现此接口,比如我们的参数是ConditionRequest,那么代码如下:
public class ConditionRequest implements DataParameterRequest
public String author;
private Map<String,String> params = new HashMap<String,String>();
@Override
public Map<String, String> getParameters()
return params;
public void setParameters(Map<String,String> p)
this.params=p;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
然后在Controller的方法是这样的:
@RequiresData(props="realName","groupNames[1]",fields="saleName","province")
@RequestMapping(value = "/data", method = RequestMethod.POST, headers =
"Content-Type=application/json;charset=utf-8", "Accept=application/json" )
public @ResponseBody Map<String,String> showData(@RequestBody ConditionRequest req)
下面讨论一下如何利用AOP修改方法参数,主要是两个地方要修改,一是AopAllianceAnnotationsAuthorizingMethodInterceptor中需要重载invoke,让它能保证在遇到RequiresData时能调用DataAnnotationMethodInterceptor的invoke。
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable
org.apache.shiro.aop.MethodInvocation mi = createMethodInvocation(methodInvocation);
assertAuthorized(mi);
Collection<AuthorizingAnnotationMethodInterceptor> aamis = getMethodInterceptors();
if (aamis != null && !aamis.isEmpty())
for (AuthorizingAnnotationMethodInterceptor aami : aamis)
if (aami.supports(mi))
if(aami instanceof DataAnnotationMethodInterceptor)
return ((DataAnnotationMethodInterceptor)aami).invoke(mi);
return super.invoke(mi);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
再者需要修改DataAnnotationMethodInterceptor,同样重载invoke方法,这是主要功能逻辑所在位置。
@SuppressWarnings("unchecked")
private Map<String,String> _addParameters(String[] props,String[] fields,Class<?> clz,Object principal) throws Exception
Map<String,String> params = new HashMap<String,String>();
for(int i=0;i<props.length;i++)
String prop = props[i];
String field = fields[i];
int index = -1;
String[] strs = StringUtils.tokenizeToStringArray(prop, "[]");
if(strs.length>1)
prop = strs[0];
index = Integer.valueOf(strs[1]);
String propValue = "";
Field p = clz.getDeclaredField(prop);
if(Modifier.PRIVATE==p.getModifiers())
String m_getter_name = "get"+StringUtils.uppercaseFirstChar(prop);
Method method = clz.getDeclaredMethod(m_getter_name);
Object ret = method.invoke(principal);
if(index>-1 && ret instanceof List<?>)
propValue = ((List<Object>)ret).get(index).toString();
else
propValue = ret.toString();
else
Object ret = p.get(principal);
if(index>-1 && ret instanceof List<?>)
propValue = ((List<Object>)ret).get(index).toString();
else
propValue = ret.toString();
System.out.println(propValue);
params.put(field, propValue);
return params;
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable
assertAuthorized(methodInvocation);
Object obj = methodInvocation.getThis();
Object[] args = methodInvocation.getArguments();
RequiresData an = (RequiresData)this.getAnnotation(methodInvocation);
Object principal = this.getSubject().getPrincipal();
Class<?> clz = principal.getClass();
String[] props = an.props();
String[] fields = an.fields();
for(Object o : args)
if( o instanceof DataParameterRequest )
Map<String,String> m = (Map<String,String>)((DataParameterRequest)o).getParameters();
if(m!=null)
Map<String,String> mm = this._addParameters(props, fields, clz, principal);
m.putAll(mm);
return methodInvocation.getMethod().invoke(obj, args);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
大概解释一下,在invoke中,当前登录的用户是这个Object principal = this.getSubject().getPrincipal();
,然后取出方法参数,是个数组,Object[] args = methodInvocation.getArguments();
找到它里面那个DataParameterRequest类型的参数,根据注解声明的属性方法与Map中的字段对应关系,添加到args中的那个DataParameterRequest中的parameters里面去。就可以了。
注意,最后需要将args传入methodInvocation.getMethod().invoke(obj, args);
以上是关于权限管理系统的主要内容,如果未能解决你的问题,请参考以下文章
Linux组管理和权限管理
以编程方式创建文件夹以及使用 java 将内容保存到该位置的权限
怎么在百度地图上看我的位置
Linux组管理和权限管理
权限管理系统
本地化Info.plist权限Key