001/** 002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com). 003 * <p> 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * <p> 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * <p> 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package io.jboot.support.shiro; 017 018import com.jfinal.aop.Invocation; 019import com.jfinal.config.Routes; 020import com.jfinal.core.Controller; 021import com.jfinal.template.expr.ast.MethodKeyBuilder; 022import io.jboot.Jboot; 023import io.jboot.exception.JbootIllegalConfigException; 024import io.jboot.support.shiro.processer.*; 025import io.jboot.utils.ArrayUtil; 026import io.jboot.utils.ClassUtil; 027import io.jboot.utils.StrUtil; 028import org.apache.shiro.authz.annotation.*; 029 030import java.lang.annotation.Annotation; 031import java.lang.reflect.Method; 032import java.util.List; 033import java.util.concurrent.ConcurrentHashMap; 034 035/** 036 * shiro 管理器. 037 */ 038public class JbootShiroManager { 039 private final static JbootShiroManager me = new JbootShiroManager(); 040 041 private final JbootShiroConfig jbootShiroConfig = Jboot.config(JbootShiroConfig.class); 042 043 private final ShiroRequiresAuthenticationProcesser requiresAuthenticationProcessor = new ShiroRequiresAuthenticationProcesser(); 044 private final ShiroRequiresUserProcesser requiresUserProcessor = new ShiroRequiresUserProcesser(); 045 private final ShiroRequiresGuestProcesser requiresGuestProcessor = new ShiroRequiresGuestProcesser(); 046 047 private JbootShiroManager() { 048 } 049 050 051 public static JbootShiroManager me() { 052 return me; 053 } 054 055 private ConcurrentHashMap<Long, ShiroAuthorizeProcesserInvoker> invokers = new ConcurrentHashMap<>(); 056 057 058 public void init(List<Routes.Route> routes) { 059 // do nothing 060 } 061 062 /** 063 * 根据类和方法上的注解生成shiro的注解处理器 064 * 065 * @return 返回是否有shiro处理器,ShiroInterceptorBuilder 根据这一结果来决定是否对方法进行拦截 066 */ 067 public boolean buildShiroInvoker(Class clazz, Method method) { 068 if (Controller.class.isAssignableFrom(clazz) && 069 JbootShiroUtil.getControllerExcludedMethodName().contains(method.getName())) { 070 // 忽略 JbootController 中的方法 071 return false; 072 } 073 074 if (method.getAnnotation(ShiroClear.class) != null) { 075 return false; 076 } 077 078 Annotation[] allAnnotations = ArrayUtil.concat(clazz.getAnnotations(), method.getAnnotations()); 079 ShiroAuthorizeProcesserInvoker invoker = new ShiroAuthorizeProcesserInvoker(); 080 for (Annotation annotation : allAnnotations) { 081 if (annotation.annotationType() == RequiresPermissions.class) { 082 ShiroRequiresPermissionsProcesser processor = new ShiroRequiresPermissionsProcesser((RequiresPermissions) annotation); 083 invoker.addProcesser(processor); 084 } else if (annotation.annotationType() == RequiresRoles.class) { 085 ShiroRequiresRolesProcesser processor = new ShiroRequiresRolesProcesser((RequiresRoles) annotation); 086 invoker.addProcesser(processor); 087 } else if (annotation.annotationType() == RequiresUser.class) { 088 invoker.addProcesser(requiresUserProcessor); 089 } else if (annotation.annotationType() == RequiresAuthentication.class) { 090 invoker.addProcesser(requiresAuthenticationProcessor); 091 } else if (annotation.annotationType() == RequiresGuest.class) { 092 invoker.addProcesser(requiresGuestProcessor); 093 } 094 } 095 096 if (invoker.getProcessers() != null && invoker.getProcessers().size() > 0) { 097 invokers.put(getMethodKey(method), invoker); 098 return true; 099 } 100 101 return false; 102 } 103 104 public AuthorizeResult invoke(Invocation invocation) { 105 ShiroAuthorizeProcesserInvoker invoker = invokers.get(getMethodKey(invocation.getMethod())); 106 if (invoker == null) { 107 return AuthorizeResult.ok(); 108 } 109 110 return invoker.invoke(); 111 } 112 113 114 private static MethodKeyBuilder keyBuilder = new MethodKeyBuilder.FastMethodKeyBuilder(); 115 116 public static Long getMethodKey(Method method) { 117 return keyBuilder.getMethodKey(method.getDeclaringClass(), method.getName(), method.getParameterTypes()); 118 } 119 120 121 private JbootShiroInvokeListener invokeListener; 122 123 public JbootShiroInvokeListener getInvokeListener() { 124 125 if (invokeListener != null) { 126 return invokeListener; 127 } 128 129 invokeListener = JbootShiroInvokeListener.DEFAULT; 130 131 if (StrUtil.isNotBlank(jbootShiroConfig.getInvokeListener())) { 132 invokeListener = ClassUtil.newInstance(jbootShiroConfig.getInvokeListener()); 133 if (invokeListener == null) { 134 throw new JbootIllegalConfigException("can not find Class : " + jbootShiroConfig.getInvokeListener() + 135 " please config jboot.shiro.invokeListener correct. "); 136 } 137 } 138 139 return invokeListener; 140 } 141 142}