goja.plugins.shiro.ShiroPlugin Maven / Gradle / Ivy
The newest version!
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2013-2014 sagyf Yang. The Four Group.
*/
package goja.plugins.shiro;
import com.jfinal.config.Routes;
import com.jfinal.core.ActionKey;
import com.jfinal.core.Controller;
import com.jfinal.plugin.IPlugin;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.authz.annotation.RequiresUser;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import static goja.core.StringPool.SLASH;
/**
* Shiro插件,启动时加载所有Shiro访问控制注解。
*
* @author dafei
*/
@SuppressWarnings("unchecked")
public class ShiroPlugin implements IPlugin {
/**
* Shiro的几种访问控制注解
*/
private static final Class extends Annotation>[] AUTHZ_ANNOTATION_CLASSES = new Class[]{
RequiresPermissions.class, RequiresRoles.class, RequiresUser.class,
RequiresGuest.class, RequiresAuthentication.class};
/**
* 路由设定
*/
private final Routes routes;
/**
* 构造函数
*
* @param routes 路由设定
*/
public ShiroPlugin(Routes routes) {
this.routes = routes;
}
/**
* 停止插件
*/
@Override
public boolean stop() {
return true;
}
/**
* 启动插件
*/
@Override
public boolean start() {
Set excludedMethodName = buildExcludedMethodName();
ConcurrentMap authzMaps = Maps.newConcurrentMap();
//逐个访问所有注册的Controller,解析Controller及action上的所有Shiro注解。
//并依据这些注解,actionKey提前构建好权限检查处理器。
for (Entry> entry : routes.getEntrySet()) {
Class extends Controller> controllerClass = entry.getValue();
String controllerKey = entry.getKey();
// 获取Controller的所有Shiro注解。
List controllerAnnotations = getAuthzAnnotations(controllerClass);
// 逐个遍历方法。
Method[] methods = controllerClass.getMethods();
for (Method method : methods) {
//排除掉Controller基类的所有方法,并且只关注没有参数的Action方法。
if (!excludedMethodName.contains(method.getName())
&& method.getParameterTypes().length == 0) {
//若该方法上存在ClearShiro注解,则对该action不进行访问控制检查。
if (isClearShiroAnnotationPresent(method)) {
continue;
}
//获取方法的所有Shiro注解。
List methodAnnotations = getAuthzAnnotations(method);
//依据Controller的注解和方法的注解来生成访问控制处理器。
AuthzHandler authzHandler = createAuthzHandler(controllerAnnotations, methodAnnotations);
//生成访问控制处理器成功。
if (authzHandler != null) {
//构建ActionKey,参考ActionMapping中实现
String actionKey = createActionKey(controllerClass, method, controllerKey);
//添加映射
authzMaps.put(actionKey, authzHandler);
}
}
}
}
//注入到ShiroKit类中。ShiroKit类以单例模式运行。
ShiroKit.init(authzMaps);
return true;
}
/**
* 从Controller方法中构建出需要排除的方法列表
*
* @return 排除的方法列表
*/
private Set buildExcludedMethodName() {
Set excludedMethodName = new HashSet();
Method[] methods = Controller.class.getMethods();
for (Method m : methods) {
if (m.getParameterTypes().length == 0) {
excludedMethodName.add(m.getName());
}
}
return excludedMethodName;
}
/**
* 依据Controller的注解和方法的注解来生成访问控制处理器。
*
* @param controllerAnnotations Controller的注解
* @param methodAnnotations 方法的注解
* @return 访问控制处理器
*/
private AuthzHandler createAuthzHandler(
List controllerAnnotations,
List methodAnnotations) {
//没有注解
if (controllerAnnotations.size() == 0 && methodAnnotations.size() == 0) {
return null;
}
//至少有一个注解
List authzHandlers = Lists.newArrayListWithCapacity(5);
for (int index = 0; index < 5; index++) {
authzHandlers.add(null);
}
// 逐个扫描注解,若是相应的注解则在相应的位置赋值。
scanAnnotation(authzHandlers, controllerAnnotations);
// 逐个扫描注解,若是相应的注解则在相应的位置赋值。函数的注解优先级高于Controller
scanAnnotation(authzHandlers, methodAnnotations);
// 去除空值
List finalAuthzHandlers = Lists.newArrayList();
for (AuthzHandler a : authzHandlers) {
if (a != null) {
finalAuthzHandlers.add(a);
}
}
authzHandlers = null;
// 存在多个,则构建组合AuthzHandler
if (finalAuthzHandlers.size() > 1) {
return new CompositeAuthzHandler(finalAuthzHandlers);
}
// 一个的话直接返回
return finalAuthzHandlers.get(0);
}
/**
* 逐个扫描注解,若是相应的注解则在相应的位置赋值。 注解的处理是有顺序的,依次为RequiresRoles,RequiresPermissions,
* RequiresAuthentication,RequiresUser,RequiresGuest
*/
private void scanAnnotation(List authzArray,
List annotations) {
if (null == annotations || 0 == annotations.size()) {
return;
}
for (Annotation a : annotations) {
if (a instanceof RequiresRoles) {
authzArray.set(0, new RoleAuthzHandler(a));
} else if (a instanceof RequiresPermissions) {
authzArray.set(1, new PermissionAuthzHandler(a));
} else if (a instanceof RequiresAuthentication) {
authzArray.set(2, AuthenticatedAuthzHandler.me());
} else if (a instanceof RequiresUser) {
authzArray.set(3, UserAuthzHandler.me());
} else if (a instanceof RequiresGuest) {
authzArray.set(4, GuestAuthzHandler.me());
}
}
}
/**
* 构建actionkey,参考ActionMapping中的实现。
*/
private String createActionKey(Class extends Controller> controllerClass,
Method method, String controllerKey) {
String methodName = method.getName();
String actionKey;
ActionKey ak = method.getAnnotation(ActionKey.class);
if (ak != null) {
actionKey = ak.value().trim();
if (Strings.isNullOrEmpty(actionKey)) {
throw new IllegalArgumentException(controllerClass.getName()
+ "."
+ methodName
+ "(): The argument of ActionKey can not be blank.");
}
if (!actionKey.startsWith(SLASH)) {
actionKey = SLASH + actionKey;
}
} else if (methodName.equals("index")) {
actionKey = controllerKey;
} else {
actionKey =
controllerKey.equals(SLASH) ? SLASH + methodName : controllerKey + SLASH + methodName;
}
return actionKey;
}
/**
* 返回该方法的所有访问控制注解
*/
private List getAuthzAnnotations(Method method) {
List annotations = Lists.newArrayList();
for (Class extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = method.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}
/**
* 返回该Controller的所有访问控制注解
*/
private List getAuthzAnnotations(
Class extends Controller> targetClass) {
List annotations = Lists.newArrayList();
for (Class extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = targetClass.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}
/**
* 该方法上是否有ClearShiro注解
*/
private boolean isClearShiroAnnotationPresent(Method method) {
Annotation a = method.getAnnotation(ClearShiro.class);
return a != null;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy