com.janeluo.jfinalplus.plugin.shiro.ShiroPlugin Maven / Gradle / Ivy
/**
* Copyright (c) 2011-2013, dafei 李飞 (myaniu AT gmail DOT com)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.janeluo.jfinalplus.plugin.shiro;
import com.jfinal.config.Routes;
import com.jfinal.core.ActionKey;
import com.jfinal.core.Controller;
import com.jfinal.plugin.IPlugin;
import org.apache.shiro.authz.annotation.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* Shiro插件,启动时加载所有Shiro访问控制注解。
* @author dafei
*
*/
@SuppressWarnings("unchecked")
public class ShiroPlugin implements IPlugin {
private static final String SLASH = "/";
/**
* 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 = new ConcurrentHashMap();
//逐个访问所有注册的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 = new ArrayList(5);
for (int index = 0; index < 5; index++) {
authzHandlers.add(null);
}
// 逐个扫描注解,若是相应的注解则在相应的位置赋值。
scanAnnotation(authzHandlers, controllerAnnotations);
// 逐个扫描注解,若是相应的注解则在相应的位置赋值。函数的注解优先级高于Controller
scanAnnotation(authzHandlers, methodAnnotations);
// 去除空值
List finalAuthzHandlers = new ArrayList();
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
*
* @param authzArray
* @param annotations
*/
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中的实现。
*
* @param controllerClass
* @param method
* @param controllerKey
* @return
*/
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 ("".equals(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;
}
/**
* 返回该方法的所有访问控制注解
*
* @param method
* @return
*/
private List getAuthzAnnotations(Method method) {
List annotations = new ArrayList();
for (Class extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = method.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}
/**
* 返回该Controller的所有访问控制注解
*
* @param method
* @return
*/
private List getAuthzAnnotations(
Class extends Controller> targetClass) {
List annotations = new ArrayList();
for (Class extends Annotation> annClass : AUTHZ_ANNOTATION_CLASSES) {
Annotation a = targetClass.getAnnotation(annClass);
if (a != null) {
annotations.add(a);
}
}
return annotations;
}
/**
* 该方法上是否有ClearShiro注解
* @param method
* @return
*/
private boolean isClearShiroAnnotationPresent(Method method) {
Annotation a = method.getAnnotation(ClearShiro.class);
if (a != null) {
return true;
}
return false;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy