├── .gitignore ├── README.md ├── pom.xml ├── shiro-spring-boot-autoconfigure ├── .gitignore ├── pom.xml └── src │ ├── main │ └── java │ │ └── cn │ │ └── ocoop │ │ └── framework │ │ ├── ShiroAutoConfiguration.java │ │ ├── ShiroConfiguration.java │ │ ├── authz │ │ ├── ModularSourceRealmAuthorizer.java │ │ └── SimpleAuthorizationInfoOrdered.java │ │ ├── cache │ │ ├── RedisCache.java │ │ ├── RedisCacheManager.java │ │ └── ShiroRealmCacheManager.java │ │ ├── config │ │ ├── RequestProperties.java │ │ └── ShiroProperties.java │ │ ├── converter │ │ └── String2ObjectGenericConverter.java │ │ ├── filter │ │ ├── AnyRolesAuthorizationFilter.java │ │ ├── AuthorizationWithStatusCodeFilter.java │ │ ├── BasicHttpAuthenticationFilter.java │ │ ├── DefaultFilter.java │ │ ├── FormAuthenticationFilter.java │ │ ├── HttpMethodPermissionFilter.java │ │ ├── LogoutFilter.java │ │ ├── PermissionsAuthorizationFilter.java │ │ ├── RolesAuthorizationFilter.java │ │ └── UserFilter.java │ │ ├── session │ │ └── RedisSessionDAO.java │ │ ├── util │ │ ├── RequestUtils.java │ │ └── ResponseUtils.java │ │ └── web │ │ └── mgt │ │ ├── CookieRememberMeManager.java │ │ └── DefaultWebSecurityManager.java │ └── resources │ └── META-INF │ └── spring.factories ├── shiro-spring-boot-starter-example ├── .gitignore ├── pom.xml └── src │ └── main │ ├── java │ └── cn │ │ ├── App.java │ │ ├── RedisCachingConfigure.java │ │ └── ocoop │ │ └── demo │ │ ├── DemoController.java │ │ └── DemoRealm.java │ └── resources │ └── application.yml └── shiro-spring-boot-starter ├── .gitignore ├── pom.xml └── src └── main └── resources └── META-INF └── spring.provides /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.iml 3 | .idea 4 | target 5 | .DS_Store 6 | *.log 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shiro-spring-boot-starter 2 | =============================== 3 | 4 | 一、项目说明 5 | ------- 6 | 1. 为简化Apache Shiro权限框架和SpringBoot整合,本项目为SpringBoot和Shiro整合starter,引用shiro-spring-boot-starter即可自动配置Shiro。 7 | 8 | 2. 项目默认实现并配置了基于Redis分布式会话管理,所以使用该项目请确保已经添加了spring-boot-starter-data-redis并正确配置了该starter所需的配置项。 9 | 10 | 3. 项目默认使用`ModularRealmAuthorizer`的另一个实现`ModularSourceRealmAuthorizer`,该实现在多Realm登录时,验证权限时仅从已通过身份验证的Realm获取权限并验证。 11 | 12 | 此外, `ModularSourceRealmAuthorizer`提供了获取单个用户所有权限,所有角色的接口。 13 | 如你不需要这些扩展可通过配置自己的`ModularRealmAuthorizer`实现覆盖。 14 | 15 | 4. 项目提供了一个缓存管理`ShiroRealmCacheManager`,该类提供了清除用户认证缓存,权限缓存等静态方法,你可直接调用,这在用户权限和认证信息发生变更时很有用。 16 | 17 | 使用: 18 | ```xml 19 | 20 | cn.ocoop.framework 21 | shiro-spring-boot-starter 22 | 1.0.1 23 | 24 | ``` 25 | 26 | 二、配置说明 27 | ---------- 28 | **1.配置文件** 29 | 30 | 强烈建议使用yml作为配置文件,以下也使用yml作为示例。目前该项目提供可配置的部分配置项如下: 31 | 32 | ```yaml 33 | #shiro配置开始 34 | shiro: 35 | #session配置 36 | session: 37 | sessionIdCookie: 38 | name: session-id 39 | path: / 40 | max-age: -1 41 | session-id-cookie-enabled: true 42 | session-id-url-rewriting-enabled: true 43 | global-session-timeout: 1800000 44 | session-cache-name: "shiro:session:" 45 | 46 | #realm配置 47 | realms: 48 | #realm类全路径 49 | - realm: 50 | target: org.apache.shiro.realm.jdbc.JdbcRealm 51 | property: 52 | cachingEnabled: true 53 | authenticationCachingEnabled: true 54 | authorizationCachingEnabled: true 55 | authenticationCacheName: usernamePasswordRealm2:authenticationCache 56 | authorizationCacheName: usernamePasswordRealm2:authorizationCache 57 | 58 | #凭证匹配器配置 59 | credentials-matcher: 60 | #凭证匹配器全路径 61 | target: org.apache.shiro.authc.credential.HashedCredentialsMatcher 62 | property: 63 | hashAlgorithmName: MD5 64 | hashIterations: 2 65 | storedCredentialsHexEncoded: true 66 | 67 | 68 | #记住我功能配置 69 | remember-me: 70 | cipher-key: this is ur cipher-key 71 | cookie: 72 | name: remember-me 73 | path: / 74 | max-age: 31536000 75 | 76 | #登录地址 77 | login-url: /login 78 | #登录成功默认跳转地址 79 | success-url: /index 80 | #无权限跳转地址 81 | unauthorized-url: /unauthorized 82 | #未登录响应状态码 83 | invalid-login-code: 418 84 | #未登录响应状态码 85 | invalid-permission-code: 401 86 | #定义系统是否只提供服务 87 | service-oriented: false 88 | #登录、登录失败、登出时返回的 json:{key:true/false}的key 89 | log-in-out-response-key: success 90 | #自定义filter配置 91 | filters: 92 | anon: org.apache.shiro.web.filter.authc.AnonymousFilter 93 | 94 | #自定义URL拦截器 95 | filter-chain-definitions: 96 | /** = anon 97 | ``` 98 | > _**这里是给出部分配置项,其他配置项参考ShiroAutoConfiguration中配置的类的具体属性。 99 | 如果你还不熟悉@ConfigurationProperties注解的意思,建议先阅读SpringBoot官方文档。**_ 100 | 101 | **2.session配置** 102 | 103 | 项目默认实现并配置了基于Redis的分布式会话管理扩展,以下为会话相关配置项: 104 | ```yaml 105 | shiro: 106 | 107 | #session配置 108 | session: 109 | sessionIdCookie: 110 | name: session-id 111 | path: / 112 | max-age: -1 113 | session-id-cookie-enabled: true 114 | session-id-url-rewriting-enabled: true 115 | global-session-timeout: 1800000 116 | session-cache-name: "shiro:session:" 117 | ``` 118 | >_**其他配置项参考ShiroAutoConfiguration中配置的类的具体属性。 119 | 请先请确保已经添加了spring-boot-starter-data-redis并正确配置了该starter所需的配置项。**_ 120 | 121 | **3.realm配置** 122 | 123 | 默认情况下没有提供任何realm的实现配置,请根据你自己的需求来配置多个realm。 124 | ```yaml 125 | shiro: 126 | 127 | #realm配置 128 | realms: 129 | - realm: 130 | #realm类全路径 131 | target: org.apache.shiro.realm.jdbc.JdbcRealm 132 | #设置realm的属性 133 | property: 134 | cachingEnabled: true 135 | authenticationCachingEnabled: true 136 | authorizationCachingEnabled: true 137 | authenticationCacheName: usernamePasswordRealm2:authenticationCache 138 | authorizationCacheName: usernamePasswordRealm2:authorizationCache 139 | 140 | #该realm使用的凭证匹配器配置 141 | credentials-matcher: 142 | #凭证匹配器全路径 143 | target: org.apache.shiro.authc.credential.HashedCredentialsMatcher 144 | property: 145 | hashAlgorithmName: MD5 146 | hashIterations: 2 147 | storedCredentialsHexEncoded: true 148 | ``` 149 | 150 | **4.记住我功能配置** 151 | 152 | ```yaml 153 | shiro: 154 | 155 | #记住我功能配置 156 | remember-me: 157 | cipher-key: this is ur cipher-key 158 | cookie: 159 | name: remember-me 160 | path: / 161 | max-age: 31536000 162 | ``` 163 | 164 | 165 | **5.自定义Filter** 166 | 167 | 默认覆盖了Shiro提供的`BasicHttpAuthenticationFilter`,`FormAuthenticationFilter`,`HttpMethodPermissionFilter`, 168 | `LogoutFilter`, `PermissionsAuthorizationFilter`,`RolesAuthorizationFilter`,为这些过滤器添加了对AJAX请求的处理。 169 | 170 | 此外,还提供了`AnyRolesAuthorizationFilter`,用于校验用户是否具有角色列表中的任意一个,默认注册的filter名称为:`anyRoles`。 171 | 这些预定义的拦截器都定义在了`cn.ocoop.framework.filter.DefaultFilter`中。 172 | 173 | 如果预定义的filter不能满足你的需求,你也可以注册自定义Filter: 174 | ```yaml 175 | shiro: 176 | #自定义filter配置 177 | filters: 178 | filter名称:filter对应Class全路径 179 | ``` 180 | >如果你的Filter名称和默认的相同,将会覆盖默认的。 181 | 182 | 183 | **6.自定义状态码** 184 | 185 | 你可以为每个Filter自定义未登录(默认:HTTP StatusCode:418)及无权限(默认:HTTP StatusCode:401)情况下的http响应状态码: 186 | ```yaml 187 | shiro: 188 | #未登录响应状态码 189 | invalid-login-code: 418 190 | #未登录响应状态码 191 | invalid-permission-code: 401 192 | ``` 193 | > _**此处定义的statusCode仅在ajax或`shiro.service-oriented:true`请求时有效,因为普通http请求通常会跳转到配置的login-url和success-url**_ 194 | 195 | **7.登录成功/失败、登出操作** 196 | 197 | 198 | ```yaml 199 | shiro: 200 | log-in-out-response-key: success 201 | ``` 202 | 当你登录/登出系统时,系统会自动响应客户端请求内容,通过设定的`log-in-out-response-key`来响应操作结果,响应结果为json格式,如: 203 | * 登录:响应 204 | ```json 205 | {"success":true} 206 | ``` 207 | 表示登录成功 208 | * 登录:响应 209 | ```json 210 | {"success":false} 211 | ``` 212 | 表示登录失败 213 | * 登出:响应 214 | ```json 215 | {"success":true} 216 | ``` 217 | 表示登出成功 218 | 219 | 220 | 221 | **8.其他配置** 222 | ```yaml 223 | shiro: 224 | service-oriented:true/false(default) 225 | ``` 226 | 这个配置项对于只提供服务/前后端分离的系统很有帮助,因为这些系统并不需要返回页面。 227 | 当你开启这个配置项时`login-url`,`success-url`,`unauthorized-url`将变得没有任何意义,因为Shiro的Filter不会发生重定向, 228 | 取而代之的是通过状态码及具体的内容来响应调用方。 229 | 230 | **9.关于注解** 231 | 232 | 有时,我们经常使用在springMVC的方法上使用Shiro提供的注解`RequiresPermissions.class`, `RequiresRoles.class`, 233 | `RequiresUser.class`, `RequiresGuest.class`, `RequiresAuthentication.class`,这为我们开发提供了方便,但使用注解的同时,你应该知道的是 234 | ,这些注解在检查权限是是基于aop的,并且格外需要注意的是这些注解在权限不匹配时会抛出`AuthorizationException`,在登录状态不匹配时会抛出`UnauthenticatedException`, 235 | 如果你正在开发web应用,可能这并不是理想的处理方式,你可以使用spring的`@RestControllerAdvice`,`@ControllerAdvice`,`@ExceptionHandler`等注解全局捕获这些异常并为这些异常设置一个全局的返回内容。 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | cn.ocoop.framework 6 | spring-boot-starter 7 | 1.0.1 8 | pom 9 | 10 | Shiro Spring Boot Stater Build 11 | Shiro Spring Boot Stater Build 12 | 13 | https://github.com/liolay/shiro-spring-boot-starter 14 | 15 | 16 | 17 | The Apache Software License, Version 2.0 18 | http://www.apache.org/licenses/LICENSE-2.0.txt 19 | repo 20 | 21 | 22 | 23 | 24 | master 25 | https://github.com/liolay/shiro-spring-boot-starter 26 | scm:git:git://github.com/liolay/shiro-spring-boot-starter.git 27 | scm:git:ssh://github.com/liolay/shiro-spring-boot-starter.git 28 | 29 | 30 | 31 | 32 | liolay 33 | 794075795@qq.com 34 | ocoop 35 | 36 | 37 | 38 | 39 | 40 | release 41 | 42 | gpg 43 | 44 | 45 | 46 | 47 | 48 | org.apache.maven.plugins 49 | maven-source-plugin 50 | 2.2.1 51 | 52 | 53 | package 54 | 55 | jar-no-fork 56 | 57 | 58 | 59 | 60 | 61 | 62 | org.apache.maven.plugins 63 | maven-javadoc-plugin 64 | 2.9.1 65 | 66 | 67 | package 68 | 69 | jar 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.apache.maven.plugins 77 | maven-gpg-plugin 78 | 1.5 79 | 80 | 81 | verify 82 | 83 | sign 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | oss 93 | https://oss.sonatype.org/content/repositories/snapshots/ 94 | 95 | 96 | oss 97 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 98 | 99 | 100 | 101 | 102 | 103 | 104 | UTF-8 105 | 1.8 106 | 1.8 107 | 1.5.4.RELEASE 108 | 109 | 110 | 111 | 112 | 113 | org.springframework.boot 114 | spring-boot-dependencies 115 | ${spring-boot.version} 116 | pom 117 | import 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | org.apache.maven.plugins 126 | maven-compiler-plugin 127 | 3.1 128 | 129 | 130 | 131 | 132 | 133 | shiro-spring-boot-starter 134 | shiro-spring-boot-autoconfigure 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.iml 3 | .idea 4 | target 5 | .DS_Store 6 | *.log 7 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | cn.ocoop.framework 7 | spring-boot-starter 8 | 1.0.1 9 | 10 | 11 | shiro-spring-boot-autoconfigure 12 | 13 | Spring Boot AutoConfiguration :: Apache Shiro Starter 14 | https://github.com/liolay/shiro-spring-boot-autoconfigure 15 | 16 | 17 | 1.3.2 18 | 1.2.24 19 | 20.0 20 | 4.3.9.RELEASE 21 | 22 | 23 | 24 | 25 | org.springframework.data 26 | spring-data-redis 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-configuration-processor 35 | true 36 | 37 | 38 | org.apache.shiro 39 | shiro-spring 40 | ${shiro.version} 41 | 42 | 43 | com.alibaba 44 | fastjson 45 | ${fastjson.version} 46 | 47 | 48 | com.google.guava 49 | guava 50 | ${guava.version} 51 | 52 | 53 | javax.servlet 54 | javax.servlet-api 55 | 3.1.0 56 | provided 57 | 58 | 59 | org.springframework 60 | spring-web 61 | ${spring.version} 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/ShiroAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework; 2 | 3 | import cn.ocoop.framework.authz.ModularSourceRealmAuthorizer; 4 | import cn.ocoop.framework.cache.RedisCacheManager; 5 | import cn.ocoop.framework.config.RequestProperties; 6 | import cn.ocoop.framework.config.ShiroProperties; 7 | import cn.ocoop.framework.filter.DefaultFilter; 8 | import cn.ocoop.framework.session.RedisSessionDAO; 9 | import cn.ocoop.framework.web.mgt.CookieRememberMeManager; 10 | import cn.ocoop.framework.web.mgt.DefaultWebSecurityManager; 11 | import org.apache.shiro.authc.AbstractAuthenticator; 12 | import org.apache.shiro.authc.pam.ModularRealmAuthenticator; 13 | import org.apache.shiro.authz.ModularRealmAuthorizer; 14 | import org.apache.shiro.cache.CacheManager; 15 | import org.apache.shiro.mgt.RememberMeManager; 16 | import org.apache.shiro.mgt.SecurityManager; 17 | import org.apache.shiro.session.mgt.eis.SessionDAO; 18 | import org.apache.shiro.spring.web.ShiroFilterFactoryBean; 19 | import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 20 | import org.apache.shiro.web.session.mgt.WebSessionManager; 21 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; 24 | import org.springframework.boot.context.properties.ConfigurationProperties; 25 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 26 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.context.annotation.Configuration; 29 | import org.springframework.context.annotation.Import; 30 | import org.springframework.data.redis.core.RedisTemplate; 31 | 32 | import javax.servlet.Filter; 33 | import java.lang.reflect.InvocationTargetException; 34 | 35 | @Configuration 36 | @ConditionalOnWebApplication 37 | @ConditionalOnBean(value = {RedisTemplate.class}) 38 | @EnableConfigurationProperties({ 39 | ShiroProperties.class, 40 | RequestProperties.class 41 | }) 42 | @Import(ShiroConfiguration.class) 43 | public class ShiroAutoConfiguration { 44 | private final ShiroProperties shiroProperties; 45 | private final RequestProperties requestProperties; 46 | 47 | public ShiroAutoConfiguration(ShiroProperties shiroProperties, RequestProperties requestProperties) { 48 | this.shiroProperties = shiroProperties.afterPropertiesSet(); 49 | this.requestProperties = requestProperties; 50 | } 51 | 52 | @Bean 53 | @ConditionalOnMissingBean(FilterRegistrationBean.class) 54 | public FilterRegistrationBean filterRegistrationBean(ShiroFilterFactoryBean shiroFilterFactoryBean) throws Exception { 55 | FilterRegistrationBean filterRegistration = new FilterRegistrationBean(); 56 | filterRegistration.addInitParameter("targetFilterLifecycle", "true"); 57 | filterRegistration.setFilter((Filter) shiroFilterFactoryBean.getObject()); 58 | filterRegistration.setEnabled(true); 59 | filterRegistration.addUrlPatterns("/*"); 60 | return filterRegistration; 61 | } 62 | 63 | @Bean 64 | @ConfigurationProperties(prefix = "shiro") 65 | @ConditionalOnMissingBean(ShiroFilterFactoryBean.class) 66 | public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) throws InvocationTargetException, IllegalAccessException { 67 | ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); 68 | shiroFilterFactoryBean.setSecurityManager(securityManager); 69 | shiroFilterFactoryBean.setFilters(DefaultFilter.createInstanceMap(requestProperties)); 70 | return shiroFilterFactoryBean; 71 | } 72 | 73 | 74 | @Bean 75 | @ConditionalOnMissingBean(SecurityManager.class) 76 | public SecurityManager securityManager( 77 | WebSessionManager sessionManager, 78 | AbstractAuthenticator authenticator, 79 | CacheManager cacheManager, 80 | RememberMeManager rememberMeManager, 81 | ModularRealmAuthorizer modularRealmAuthorizer 82 | ) { 83 | DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); 84 | securityManager.setAuthenticator(authenticator); 85 | securityManager.setSessionManager(sessionManager); 86 | securityManager.setCacheManager(cacheManager); 87 | securityManager.setRememberMeManager(rememberMeManager); 88 | securityManager.setAuthorizer(modularRealmAuthorizer); 89 | securityManager.setRealms(shiroProperties.realms()); 90 | return securityManager; 91 | } 92 | 93 | @Bean 94 | @ConditionalOnMissingBean(ModularRealmAuthorizer.class) 95 | public ModularRealmAuthorizer modularRealmAuthorizer() { 96 | return new ModularSourceRealmAuthorizer(); 97 | } 98 | 99 | @Bean 100 | @ConfigurationProperties(prefix = "shiro.remember-me") 101 | @ConditionalOnMissingBean(RememberMeManager.class) 102 | public RememberMeManager rememberMeManager() { 103 | return new CookieRememberMeManager(); 104 | } 105 | 106 | @Bean("shiroCacheManager") 107 | @ConditionalOnMissingBean(CacheManager.class) 108 | public CacheManager cacheManager(RedisTemplate redisTemplate) { 109 | return new RedisCacheManager(redisTemplate); 110 | } 111 | 112 | @Bean 113 | @ConfigurationProperties(prefix = "shiro.session") 114 | @ConditionalOnMissingBean(WebSessionManager.class) 115 | public WebSessionManager sessionManager(SessionDAO sessionDAO) { 116 | DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager(); 117 | defaultWebSessionManager.setSessionDAO(sessionDAO); 118 | return defaultWebSessionManager; 119 | } 120 | 121 | @Bean 122 | @ConfigurationProperties(prefix = "shiro.session") 123 | @ConditionalOnMissingBean(SessionDAO.class) 124 | public SessionDAO sessionDAO(RedisTemplate redisTemplate) { 125 | return new RedisSessionDAO(redisTemplate); 126 | } 127 | 128 | @Bean 129 | @ConditionalOnMissingBean(AbstractAuthenticator.class) 130 | public AbstractAuthenticator authenticator() { 131 | return new ModularRealmAuthenticator(); 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/ShiroConfiguration.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework; 2 | 3 | import org.apache.shiro.mgt.SecurityManager; 4 | import org.apache.shiro.spring.LifecycleBeanPostProcessor; 5 | import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; 6 | import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | public class ShiroConfiguration { 11 | 12 | @Bean 13 | @ConditionalOnMissingBean(LifecycleBeanPostProcessor.class) 14 | public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { 15 | return new LifecycleBeanPostProcessor(); 16 | } 17 | 18 | @Bean 19 | @ConditionalOnMissingBean(DefaultAdvisorAutoProxyCreator.class) 20 | public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(LifecycleBeanPostProcessor lifecycleBeanPostProcessor) { 21 | DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); 22 | defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); 23 | return defaultAdvisorAutoProxyCreator; 24 | } 25 | 26 | @Bean 27 | @ConditionalOnMissingBean(AuthorizationAttributeSourceAdvisor.class) 28 | public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { 29 | AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); 30 | authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); 31 | return authorizationAttributeSourceAdvisor; 32 | } 33 | 34 | 35 | } 36 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/authz/ModularSourceRealmAuthorizer.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.authz; 2 | 3 | import org.apache.shiro.SecurityUtils; 4 | import org.apache.shiro.authz.AuthorizationInfo; 5 | import org.apache.shiro.authz.Authorizer; 6 | import org.apache.shiro.authz.ModularRealmAuthorizer; 7 | import org.apache.shiro.authz.Permission; 8 | import org.apache.shiro.realm.Realm; 9 | import org.apache.shiro.subject.PrincipalCollection; 10 | import org.springframework.util.ClassUtils; 11 | 12 | import java.lang.reflect.InvocationTargetException; 13 | import java.lang.reflect.Method; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class ModularSourceRealmAuthorizer extends ModularRealmAuthorizer { 18 | 19 | public boolean hasRole(PrincipalCollection principals, String roleIdentifier) { 20 | assertRealmsConfigured(); 21 | for (Realm realm : getRealms()) { 22 | if (!(realm instanceof Authorizer) || principals.fromRealm(realm.getName()).isEmpty()) continue; 23 | if (((Authorizer) realm).hasRole(principals, roleIdentifier)) return true; 24 | } 25 | return false; 26 | } 27 | 28 | public boolean isPermitted(PrincipalCollection principals, Permission permission) { 29 | assertRealmsConfigured(); 30 | for (Realm realm : getRealms()) { 31 | if (!(realm instanceof Authorizer) || principals.fromRealm(realm.getName()).isEmpty()) continue; 32 | if (((Authorizer) realm).isPermitted(principals, permission)) return true; 33 | } 34 | return false; 35 | } 36 | 37 | @Override 38 | public boolean isPermitted(PrincipalCollection principals, String permission) { 39 | assertRealmsConfigured(); 40 | for (Realm realm : getRealms()) { 41 | if (!(realm instanceof Authorizer) || principals.fromRealm(realm.getName()).isEmpty()) continue; 42 | if (((Authorizer) realm).isPermitted(principals, permission)) { 43 | return true; 44 | } 45 | } 46 | return false; 47 | } 48 | 49 | public List getRoles() throws InvocationTargetException, IllegalAccessException { 50 | assertRealmsConfigured(); 51 | PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); 52 | List roles = new ArrayList<>(); 53 | for (Realm realm : getRealms()) { 54 | if (!(realm instanceof Authorizer) || principals.fromRealm(realm.getName()).isEmpty()) continue; 55 | 56 | Method getAuthorizationInfoMethod = ClassUtils.getMethod(realm.getClass(), "getAuthorizationInfo", PrincipalCollection.class); 57 | getAuthorizationInfoMethod.setAccessible(true); 58 | roles.addAll(((AuthorizationInfo) getAuthorizationInfoMethod.invoke(realm, principals)).getRoles()); 59 | } 60 | return roles; 61 | } 62 | 63 | public List getPermissions() throws InvocationTargetException, IllegalAccessException { 64 | assertRealmsConfigured(); 65 | PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals(); 66 | List permissions = new ArrayList<>(); 67 | for (Realm realm : getRealms()) { 68 | if (!(realm instanceof Authorizer) || principals.fromRealm(realm.getName()).isEmpty()) continue; 69 | 70 | Method getAuthorizationInfoMethod = ClassUtils.getMethod(realm.getClass(), "getAuthorizationInfo", PrincipalCollection.class); 71 | getAuthorizationInfoMethod.setAccessible(true); 72 | permissions.addAll(((AuthorizationInfo) getAuthorizationInfoMethod.invoke(realm, principals)).getStringPermissions()); 73 | } 74 | return permissions; 75 | } 76 | } -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/authz/SimpleAuthorizationInfoOrdered.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.authz; 2 | 3 | 4 | import org.apache.shiro.authz.AuthorizationInfo; 5 | import org.apache.shiro.authz.Permission; 6 | 7 | import java.util.Collection; 8 | import java.util.LinkedHashSet; 9 | 10 | public class SimpleAuthorizationInfoOrdered implements AuthorizationInfo { 11 | /** 12 | * The internal roles collection. 13 | */ 14 | protected Collection roles; 15 | 16 | /** 17 | * Collection of all string-based permissions associated with the account. 18 | */ 19 | protected Collection stringPermissions; 20 | 21 | /** 22 | * Collection of all object-based permissions associaed with the account. 23 | */ 24 | protected Collection objectPermissions; 25 | 26 | /** 27 | * Default no-argument constructor. 28 | */ 29 | public SimpleAuthorizationInfoOrdered() { 30 | } 31 | 32 | /** 33 | * Creates a new instance with the specified roles and no permissions. 34 | * 35 | * @param roles the roles assigned to the realm account. 36 | */ 37 | public SimpleAuthorizationInfoOrdered(Collection roles) { 38 | this.roles = roles; 39 | } 40 | 41 | public Collection getRoles() { 42 | return roles; 43 | } 44 | 45 | /** 46 | * Sets the roles assigned to the account. 47 | * 48 | * @param roles the roles assigned to the account. 49 | */ 50 | public void setRoles(Collection roles) { 51 | this.roles = roles; 52 | } 53 | 54 | /** 55 | * Adds (assigns) a role to those associated with the account. If the account doesn't yet have any roles, a 56 | * new roles collection (a Set) will be created automatically. 57 | * 58 | * @param role the role to add to those associated with the account. 59 | */ 60 | public void addRole(String role) { 61 | if (this.roles == null) { 62 | this.roles = new LinkedHashSet<>(); 63 | } 64 | this.roles.add(role); 65 | } 66 | 67 | /** 68 | * Adds (assigns) multiple roles to those associated with the account. If the account doesn't yet have any roles, a 69 | * new roles collection (a Set) will be created automatically. 70 | * 71 | * @param roles the roles to add to those associated with the account. 72 | */ 73 | public void addRoles(Collection roles) { 74 | if (this.roles == null) { 75 | this.roles = new LinkedHashSet<>(); 76 | } 77 | this.roles.addAll(roles); 78 | } 79 | 80 | public Collection getStringPermissions() { 81 | return stringPermissions; 82 | } 83 | 84 | /** 85 | * Sets the string-based permissions assigned directly to the account. The permissions set here, in addition to any 86 | * {@link #getObjectPermissions() object permissions} constitute the total permissions assigned directly to the 87 | * account. 88 | * 89 | * @param stringPermissions the string-based permissions assigned directly to the account. 90 | */ 91 | public void setStringPermissions(Collection stringPermissions) { 92 | this.stringPermissions = stringPermissions; 93 | } 94 | 95 | /** 96 | * Adds (assigns) a permission to those directly associated with the account. If the account doesn't yet have any 97 | * direct permissions, a new permission collection (a Set<String>) will be created automatically. 98 | * 99 | * @param permission the permission to add to those directly assigned to the account. 100 | */ 101 | public void addStringPermission(String permission) { 102 | if (this.stringPermissions == null) { 103 | this.stringPermissions = new LinkedHashSet<>(); 104 | } 105 | this.stringPermissions.add(permission); 106 | } 107 | 108 | /** 109 | * Adds (assigns) multiple permissions to those associated directly with the account. If the account doesn't yet 110 | * have any string-based permissions, a new permissions collection (a Set<String>) will be created automatically. 111 | * 112 | * @param permissions the permissions to add to those associated directly with the account. 113 | */ 114 | public void addStringPermissions(Collection permissions) { 115 | if (this.stringPermissions == null) { 116 | this.stringPermissions = new LinkedHashSet<>(); 117 | } 118 | this.stringPermissions.addAll(permissions); 119 | } 120 | 121 | public Collection getObjectPermissions() { 122 | return objectPermissions; 123 | } 124 | 125 | /** 126 | * Sets the object-based permissions assigned directly to the account. The permissions set here, in addition to any 127 | * {@link #getStringPermissions() string permissions} constitute the total permissions assigned directly to the 128 | * account. 129 | * 130 | * @param objectPermissions the object-based permissions assigned directly to the account. 131 | */ 132 | public void setObjectPermissions(Collection objectPermissions) { 133 | this.objectPermissions = objectPermissions; 134 | } 135 | 136 | /** 137 | * Adds (assigns) a permission to those directly associated with the account. If the account doesn't yet have any 138 | * direct permissions, a new permission collection (a Set<{@link Permission Permission}>) will be created automatically. 139 | * 140 | * @param permission the permission to add to those directly assigned to the account. 141 | */ 142 | public void addObjectPermission(Permission permission) { 143 | if (this.objectPermissions == null) { 144 | this.objectPermissions = new LinkedHashSet<>(); 145 | } 146 | this.objectPermissions.add(permission); 147 | } 148 | 149 | /** 150 | * Adds (assigns) multiple permissions to those associated directly with the account. If the account doesn't yet 151 | * have any object-based permissions, a new permissions collection (a Set<{@link Permission Permission}>) 152 | * will be created automatically. 153 | * 154 | * @param permissions the permissions to add to those associated directly with the account. 155 | */ 156 | public void addObjectPermissions(Collection permissions) { 157 | if (this.objectPermissions == null) { 158 | this.objectPermissions = new LinkedHashSet<>(); 159 | } 160 | this.objectPermissions.addAll(permissions); 161 | } 162 | } -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/cache/RedisCache.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.cache; 2 | 3 | import org.apache.shiro.cache.Cache; 4 | import org.apache.shiro.cache.CacheException; 5 | import org.springframework.data.redis.core.RedisTemplate; 6 | 7 | import java.util.Collection; 8 | import java.util.Set; 9 | 10 | /** 11 | * Created by liolay on 2017/6/22. 12 | */ 13 | public class RedisCache implements Cache { 14 | private final String name; 15 | private final RedisTemplate redisTemplate; 16 | 17 | public RedisCache(String name, RedisTemplate redisTemplate) { 18 | this.name = name; 19 | this.redisTemplate = redisTemplate; 20 | } 21 | 22 | @Override 23 | public V get(K key) throws CacheException { 24 | return (V) redisTemplate.opsForValue().get(getKey(key)); 25 | } 26 | 27 | private String getKey(K key) { 28 | return name + ":" + key; 29 | } 30 | 31 | @Override 32 | public V put(K key, V value) throws CacheException { 33 | V ret = get(key); 34 | redisTemplate.opsForValue().set(getKey(key), value); 35 | return ret; 36 | } 37 | 38 | @Override 39 | public V remove(K key) throws CacheException { 40 | V ret = get(key); 41 | redisTemplate.delete(key); 42 | return ret; 43 | } 44 | 45 | @Override 46 | public void clear() throws CacheException { 47 | redisTemplate.delete(keys()); 48 | } 49 | 50 | @Override 51 | public int size() { 52 | return keys().size(); 53 | } 54 | 55 | @Override 56 | public Set keys() { 57 | return redisTemplate.keys(name + ":*"); 58 | } 59 | 60 | @Override 61 | public Collection values() { 62 | return redisTemplate.opsForValue().multiGet(keys()); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/cache/RedisCacheManager.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.cache; 2 | 3 | import org.apache.shiro.cache.AbstractCacheManager; 4 | import org.apache.shiro.cache.Cache; 5 | import org.apache.shiro.cache.CacheException; 6 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 7 | import org.springframework.data.redis.core.RedisTemplate; 8 | 9 | public class RedisCacheManager extends AbstractCacheManager { 10 | private final RedisTemplate redisTemplate; 11 | 12 | public RedisCacheManager(RedisTemplate redisTemplate) { 13 | this.redisTemplate = redisTemplate; 14 | } 15 | 16 | @Override 17 | protected Cache createCache(String name) throws CacheException { 18 | return new RedisCache(name, redisTemplate); 19 | } 20 | 21 | @Override 22 | public void destroy() throws Exception { 23 | super.destroy(); 24 | try { 25 | ((JedisConnectionFactory) redisTemplate.getConnectionFactory()).destroy(); 26 | } catch (Throwable e) { 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/cache/ShiroRealmCacheManager.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.cache; 2 | 3 | import org.apache.shiro.authc.AuthenticationInfo; 4 | import org.apache.shiro.authz.AuthorizationInfo; 5 | import org.apache.shiro.cache.Cache; 6 | import org.apache.shiro.cache.CacheManager; 7 | import org.apache.shiro.realm.AuthenticatingRealm; 8 | import org.apache.shiro.realm.AuthorizingRealm; 9 | import org.apache.shiro.realm.Realm; 10 | import org.apache.shiro.subject.PrincipalCollection; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | 14 | import java.util.Collection; 15 | import java.util.Optional; 16 | 17 | public class ShiroRealmCacheManager { 18 | private static final Logger log = LoggerFactory.getLogger(ShiroRealmCacheManager.class); 19 | private static Collection realms; 20 | 21 | public static void clearCachedAuthenticationInfo(PrincipalCollection principals) { 22 | if (principals == null) return; 23 | 24 | getRealms().forEach(realm -> { 25 | if (realm instanceof AuthenticatingRealm) { 26 | Optional.ofNullable(getAuthenticationCache((AuthenticatingRealm) realm)) 27 | .ifPresent(cache -> cache.remove(principals)); 28 | } 29 | }); 30 | } 31 | 32 | public static void clearCachedAuthenticationInfo(PrincipalCollection principals, Class... realms) { 33 | if (principals == null) return; 34 | getRealms().forEach(realm -> { 35 | for (Class realmClass : realms) { 36 | if (realmClass.isAssignableFrom(realm.getClass())) { 37 | Optional.ofNullable(getAuthenticationCache((AuthenticatingRealm) realm)) 38 | .ifPresent(cache -> cache.remove(principals)); 39 | } 40 | } 41 | }); 42 | } 43 | 44 | public static void clearCachedAuthenticationInfo(Class... realms) { 45 | getRealms().forEach(realm -> { 46 | for (Class realmClass : realms) { 47 | if (realmClass.isAssignableFrom(realm.getClass())) { 48 | Optional.ofNullable(getAuthenticationCache((AuthenticatingRealm) realm)) 49 | .ifPresent(cache -> cache.clear()); 50 | } 51 | } 52 | }); 53 | } 54 | 55 | public static void clearAllCachedAuthenticationInfo() { 56 | getRealms().forEach(realm -> { 57 | if (realm instanceof AuthenticatingRealm) { 58 | Optional.ofNullable(getAuthenticationCache((AuthenticatingRealm) realm)) 59 | .ifPresent(cache -> cache.clear()); 60 | } 61 | }); 62 | } 63 | 64 | private static Cache getAuthenticationCache(AuthenticatingRealm realm) { 65 | AuthenticatingRealm authenticatingRealm = realm; 66 | Cache cache = authenticatingRealm.getAuthenticationCache(); 67 | boolean authcCachingEnabled = authenticatingRealm.isAuthenticationCachingEnabled(); 68 | if (cache == null && authcCachingEnabled) { 69 | cache = getAuthenticationCacheLazy(authenticatingRealm); 70 | } 71 | return cache; 72 | } 73 | 74 | private static Cache getAuthenticationCacheLazy(AuthenticatingRealm realm) { 75 | 76 | if (realm.getAuthenticationCache() == null) { 77 | 78 | log.trace("No authenticationCache instance set. Checking for a cacheManager..."); 79 | 80 | CacheManager cacheManager = realm.getCacheManager(); 81 | 82 | if (cacheManager != null) { 83 | String cacheName = realm.getAuthenticationCacheName(); 84 | log.debug("CacheManager [{}] configured. Building authentication cache '{}'", cacheManager, cacheName); 85 | realm.setAuthenticationCache(cacheManager.getCache(cacheName)); 86 | } 87 | } 88 | 89 | return realm.getAuthenticationCache(); 90 | } 91 | 92 | public static void clearCachedAuthorizationInfo(PrincipalCollection principals) { 93 | if (principals == null) return; 94 | getRealms().forEach(realm -> { 95 | if (realm instanceof AuthorizingRealm) { 96 | Optional.ofNullable(getAuthorizationCache((AuthorizingRealm) realm)) 97 | .ifPresent(cache -> cache.remove(principals)); 98 | } 99 | }); 100 | } 101 | 102 | public static void clearCachedAuthorizationInfo(PrincipalCollection principals, Class... realms) { 103 | if (principals == null) return; 104 | 105 | getRealms().forEach(realm -> { 106 | for (Class realmClass : realms) { 107 | if (realmClass.isAssignableFrom(realm.getClass())) { 108 | Optional.ofNullable(getAuthorizationCache((AuthorizingRealm) realm)) 109 | .ifPresent(cache -> cache.remove(principals)); 110 | } 111 | } 112 | }); 113 | } 114 | 115 | public static void clearCachedAuthorizationInfo(Class... realms) { 116 | getRealms().forEach(realm -> { 117 | for (Class realmClass : realms) { 118 | if (realmClass.isAssignableFrom(realm.getClass())) { 119 | Optional.ofNullable(getAuthorizationCache((AuthorizingRealm) realm)) 120 | .ifPresent(cache -> cache.clear()); 121 | } 122 | } 123 | }); 124 | } 125 | 126 | public static void clearAllCachedAuthorizationInfo() { 127 | getRealms().forEach(realm -> { 128 | if (realm instanceof AuthorizingRealm) { 129 | Optional.ofNullable(getAuthorizationCache((AuthorizingRealm) realm)) 130 | .ifPresent(cache -> cache.clear()); 131 | } 132 | }); 133 | } 134 | 135 | private static Cache getAuthorizationCache(AuthorizingRealm realm) { 136 | Cache cache = realm.getAuthorizationCache(); 137 | if (cache == null && realm.isAuthorizationCachingEnabled()) { 138 | cache = getAuthorizationCacheLazy(realm); 139 | } 140 | return cache; 141 | } 142 | 143 | private static Cache getAuthorizationCacheLazy(AuthorizingRealm realm) { 144 | 145 | if (realm.getAuthorizationCache() == null) { 146 | 147 | if (log.isDebugEnabled()) { 148 | log.debug("No authorizationCache instance set. Checking for a cacheManager..."); 149 | } 150 | 151 | CacheManager cacheManager = realm.getCacheManager(); 152 | 153 | if (cacheManager != null) { 154 | String cacheName = realm.getAuthorizationCacheName(); 155 | if (log.isDebugEnabled()) { 156 | log.debug("CacheManager [" + cacheManager + "] has been configured. Building " + 157 | "authorization cache named [" + cacheName + "]"); 158 | } 159 | realm.setAuthorizationCache(cacheManager.getCache(cacheName)); 160 | } else { 161 | if (log.isInfoEnabled()) { 162 | log.info("No cache or cacheManager properties have been set. Authorization cache cannot " + 163 | "be obtained."); 164 | } 165 | } 166 | } 167 | 168 | return realm.getAuthorizationCache(); 169 | } 170 | 171 | private static Collection getRealms() { 172 | return realms; 173 | } 174 | 175 | public static void setRealms(Collection realms) { 176 | ShiroRealmCacheManager.realms = realms; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/config/RequestProperties.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = RequestProperties.PREFIX) 6 | public class RequestProperties { 7 | public static final String PREFIX = "shiro"; 8 | 9 | private int invalidLoginCode = 418; 10 | private int invalidPermissionCode = 401; 11 | private boolean serviceOriented = false; 12 | private String logInOutResponseKey = "success"; 13 | 14 | public String getLogInOutResponseKey() { 15 | return logInOutResponseKey; 16 | } 17 | 18 | public void setLogInOutResponseKey(String logInOutResponseKey) { 19 | this.logInOutResponseKey = logInOutResponseKey; 20 | } 21 | 22 | public boolean isServiceOriented() { 23 | return serviceOriented; 24 | } 25 | 26 | public void setServiceOriented(boolean serviceOriented) { 27 | this.serviceOriented = serviceOriented; 28 | } 29 | 30 | public int getInvalidLoginCode() { 31 | return invalidLoginCode; 32 | } 33 | 34 | public void setInvalidLoginCode(int invalidLoginCode) { 35 | this.invalidLoginCode = invalidLoginCode; 36 | } 37 | 38 | public int getInvalidPermissionCode() { 39 | return invalidPermissionCode; 40 | } 41 | 42 | public void setInvalidPermissionCode(int invalidPermissionCode) { 43 | this.invalidPermissionCode = invalidPermissionCode; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/config/ShiroProperties.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.config; 2 | 3 | import org.apache.shiro.authc.credential.CredentialsMatcher; 4 | import org.apache.shiro.realm.AuthenticatingRealm; 5 | import org.apache.shiro.realm.Realm; 6 | import org.springframework.boot.context.properties.ConfigurationProperties; 7 | 8 | import java.lang.reflect.InvocationTargetException; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | import java.util.stream.Collectors; 13 | 14 | @ConfigurationProperties(prefix = ShiroProperties.PREFIX) 15 | public class ShiroProperties { 16 | public static final String PREFIX = "shiro"; 17 | private List realms = new ArrayList<>(); 18 | private RequestProperties requestProperties = new RequestProperties(); 19 | 20 | public RequestProperties getRequestProperties() { 21 | return requestProperties; 22 | } 23 | 24 | public void setRequestProperties(RequestProperties requestProperties) { 25 | this.requestProperties = requestProperties; 26 | } 27 | 28 | public List realms() { 29 | return realms.stream() 30 | .map(realmDefinition -> realmDefinition.getRealm().getTarget()) 31 | .collect(Collectors.toList()); 32 | } 33 | 34 | public ShiroProperties afterPropertiesSet() { 35 | for (ShiroProperties.RealmDefinition realmDefinition : this.getRealms()) { 36 | setRealmProperty(realmDefinition); 37 | setCredentialsMatcherProperty(realmDefinition); 38 | setReamCredentialsMatcher(realmDefinition); 39 | } 40 | return this; 41 | } 42 | 43 | private void setReamCredentialsMatcher(RealmDefinition realmDefinition) { 44 | if (realmDefinition.getRealm().getTarget() instanceof AuthenticatingRealm) { 45 | ((AuthenticatingRealm) realmDefinition.getRealm().getTarget()).setCredentialsMatcher(realmDefinition.getRealm().getCredentialsMatcher().getTarget()); 46 | } 47 | } 48 | 49 | private void setCredentialsMatcherProperty(RealmDefinition realmDefinition) { 50 | RealmProperty.CredentialsMatcherDefinition credentialsMatcherDefinition = realmDefinition.getRealm().getCredentialsMatcher(); 51 | CredentialsMatcher matcher = credentialsMatcherDefinition.getTarget(); 52 | credentialsMatcherDefinition.getProperty().forEach((propertyName, propertyValue) -> { 53 | try { 54 | org.apache.commons.beanutils.BeanUtils.setProperty(matcher, propertyName, propertyValue); 55 | } catch (IllegalAccessException | InvocationTargetException e) { 56 | e.printStackTrace(); 57 | } 58 | }); 59 | } 60 | 61 | private void setRealmProperty(RealmDefinition realmDefinition) { 62 | realmDefinition.getRealm().getProperty().forEach((propertyName, propertyValue) -> { 63 | try { 64 | org.apache.commons.beanutils.BeanUtils.setProperty(realmDefinition, propertyName, propertyValue); 65 | } catch (IllegalAccessException | InvocationTargetException e) { 66 | e.printStackTrace(); 67 | } 68 | }); 69 | } 70 | 71 | public List getRealms() { 72 | return this.realms; 73 | } 74 | 75 | public void setRealms(List realms) { 76 | this.realms = realms; 77 | } 78 | 79 | public static class RealmProperty { 80 | private Realm target; 81 | private Map property; 82 | private CredentialsMatcherDefinition credentialsMatcher; 83 | 84 | public Realm getTarget() { 85 | return target; 86 | } 87 | 88 | public void setTarget(Realm target) { 89 | this.target = target; 90 | } 91 | 92 | public Map getProperty() { 93 | return property; 94 | } 95 | 96 | public void setProperty(Map property) { 97 | this.property = property; 98 | } 99 | 100 | public CredentialsMatcherDefinition getCredentialsMatcher() { 101 | return credentialsMatcher; 102 | } 103 | 104 | public void setCredentialsMatcher(CredentialsMatcherDefinition credentialsMatcher) { 105 | this.credentialsMatcher = credentialsMatcher; 106 | } 107 | 108 | public static class CredentialsMatcherDefinition { 109 | private CredentialsMatcher target; 110 | private Map property; 111 | 112 | public CredentialsMatcher getTarget() { 113 | return target; 114 | } 115 | 116 | public void setTarget(CredentialsMatcher target) { 117 | this.target = target; 118 | } 119 | 120 | public Map getProperty() { 121 | return property; 122 | } 123 | 124 | public void setProperty(Map property) { 125 | this.property = property; 126 | } 127 | } 128 | } 129 | 130 | public static class RealmDefinition { 131 | private RealmProperty realm; 132 | 133 | 134 | public RealmProperty getRealm() { 135 | return realm; 136 | } 137 | 138 | public void setRealm(RealmProperty realm) { 139 | this.realm = realm; 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/converter/String2ObjectGenericConverter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.converter; 2 | 3 | import org.apache.shiro.authc.credential.CredentialsMatcher; 4 | import org.apache.shiro.realm.Realm; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.BeanUtils; 8 | import org.springframework.boot.context.properties.ConfigurationPropertiesBinding; 9 | import org.springframework.core.convert.TypeDescriptor; 10 | import org.springframework.core.convert.converter.GenericConverter; 11 | import org.springframework.stereotype.Component; 12 | import org.springframework.util.ObjectUtils; 13 | 14 | import javax.servlet.Filter; 15 | import java.util.Collections; 16 | import java.util.HashSet; 17 | import java.util.Set; 18 | 19 | @Component 20 | @ConfigurationPropertiesBinding 21 | public class String2ObjectGenericConverter implements GenericConverter { 22 | 23 | private static final Logger log = LoggerFactory.getLogger(String2ObjectGenericConverter.class); 24 | 25 | private static final Set CONVERTIBLE_TYPES; 26 | 27 | static { 28 | Set convertiblePairs = new HashSet<>(); 29 | convertiblePairs.add(new ConvertiblePair(String.class, CredentialsMatcher.class)); 30 | convertiblePairs.add(new ConvertiblePair(String.class, Filter.class)); 31 | convertiblePairs.add(new ConvertiblePair(String.class, Realm.class)); 32 | convertiblePairs.add(new ConvertiblePair(String.class, byte[].class)); 33 | CONVERTIBLE_TYPES = Collections.unmodifiableSet(convertiblePairs); 34 | } 35 | 36 | @Override 37 | public Set getConvertibleTypes() { 38 | return CONVERTIBLE_TYPES; 39 | } 40 | 41 | @Override 42 | public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType) { 43 | try { 44 | if (targetType.getObjectType().isAssignableFrom(byte[].class)) return source.toString().getBytes(); 45 | return BeanUtils.instantiate((Class) Class.forName(ObjectUtils.nullSafeToString(source))); 46 | } catch (ClassNotFoundException e) { 47 | log.error("can't convert {} from {} to {}", source, sourceType.getName(), targetType.getName(), e); 48 | } 49 | return null; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/AnyRolesAuthorizationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import org.apache.shiro.subject.Subject; 4 | 5 | import javax.servlet.ServletRequest; 6 | import javax.servlet.ServletResponse; 7 | import java.io.IOException; 8 | import java.util.stream.Stream; 9 | 10 | public class AnyRolesAuthorizationFilter extends AuthorizationWithStatusCodeFilter { 11 | 12 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { 13 | 14 | Subject subject = getSubject(request, response); 15 | String[] rolesArray = (String[]) mappedValue; 16 | 17 | if (rolesArray == null || rolesArray.length == 0) { 18 | //no roles specified, so nothing to check - allow access. 19 | return true; 20 | } 21 | 22 | return Stream.of(rolesArray).anyMatch(subject::hasRole); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/AuthorizationWithStatusCodeFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import cn.ocoop.framework.config.RequestProperties; 4 | import cn.ocoop.framework.util.RequestUtils; 5 | import cn.ocoop.framework.util.ResponseUtils; 6 | import org.apache.shiro.subject.Subject; 7 | import org.apache.shiro.web.filter.authz.AuthorizationFilter; 8 | 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | import java.io.IOException; 12 | 13 | public abstract class AuthorizationWithStatusCodeFilter extends AuthorizationFilter { 14 | private RequestProperties requestProperties; 15 | 16 | public RequestProperties getRequestProperties() { 17 | return requestProperties; 18 | } 19 | 20 | public void setRequestProperties(RequestProperties requestProperties) { 21 | this.requestProperties = requestProperties; 22 | } 23 | 24 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException { 25 | 26 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) 27 | return super.onAccessDenied(request, response); 28 | 29 | Subject subject = getSubject(request, response); 30 | 31 | if (subject.getPrincipal() == null) { 32 | ResponseUtils.responseInvalidLogin(response, requestProperties.getInvalidLoginCode()); 33 | } else { 34 | ResponseUtils.responseInvalidPermission(response, requestProperties.getInvalidPermissionCode()); 35 | } 36 | return false; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/BasicHttpAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import javax.servlet.ServletRequest; 4 | import javax.servlet.ServletResponse; 5 | 6 | public class BasicHttpAuthenticationFilter extends org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter { 7 | @Override 8 | protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) { 9 | //force to valid token every request,when u developer a webapp,this is very useful 10 | return false; 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/DefaultFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | 4 | import cn.ocoop.framework.config.RequestProperties; 5 | import org.apache.commons.beanutils.BeanUtils; 6 | import org.apache.shiro.util.ClassUtils; 7 | import org.apache.shiro.web.filter.authc.AnonymousFilter; 8 | import org.apache.shiro.web.filter.session.NoSessionCreationFilter; 9 | 10 | import javax.servlet.Filter; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.LinkedHashMap; 13 | import java.util.Map; 14 | 15 | public enum DefaultFilter { 16 | 17 | anon(AnonymousFilter.class), 18 | authc(FormAuthenticationFilter.class), 19 | authcBasic(BasicHttpAuthenticationFilter.class), 20 | logout(LogoutFilter.class), 21 | noSessionCreation(NoSessionCreationFilter.class), 22 | perms(PermissionsAuthorizationFilter.class), 23 | rest(HttpMethodPermissionFilter.class), 24 | roles(RolesAuthorizationFilter.class), 25 | anyRoles(AnyRolesAuthorizationFilter.class), 26 | user(UserFilter.class); 27 | 28 | private final Class filterClass; 29 | 30 | DefaultFilter(Class filterClass) { 31 | this.filterClass = filterClass; 32 | } 33 | 34 | public static Map createInstanceMap(RequestProperties requestProperties) throws InvocationTargetException, IllegalAccessException { 35 | Map filters = new LinkedHashMap<>(values().length); 36 | for (DefaultFilter defaultFilter : values()) { 37 | Filter filter = defaultFilter.newInstance(); 38 | BeanUtils.setProperty(filter, "requestProperties", requestProperties); 39 | filters.put(defaultFilter.name(), filter); 40 | } 41 | return filters; 42 | } 43 | 44 | public Filter newInstance() { 45 | return (Filter) ClassUtils.newInstance(this.filterClass); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/FormAuthenticationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import cn.ocoop.framework.config.RequestProperties; 4 | import cn.ocoop.framework.util.RequestUtils; 5 | import cn.ocoop.framework.util.ResponseUtils; 6 | import com.google.common.collect.Maps; 7 | import org.apache.shiro.authc.AuthenticationException; 8 | import org.apache.shiro.authc.AuthenticationToken; 9 | import org.apache.shiro.subject.Subject; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import javax.servlet.ServletRequest; 14 | import javax.servlet.ServletResponse; 15 | import javax.servlet.http.HttpServletResponse; 16 | import java.io.IOException; 17 | 18 | public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter { 19 | private static final Logger log = LoggerFactory.getLogger(FormAuthenticationFilter.class); 20 | private RequestProperties requestProperties; 21 | 22 | public RequestProperties getRequestProperties() { 23 | return requestProperties; 24 | } 25 | 26 | public void setRequestProperties(RequestProperties requestProperties) { 27 | this.requestProperties = requestProperties; 28 | } 29 | 30 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { 31 | if (this.isLoginRequest(request, response)) { 32 | if (this.isLoginSubmission(request, response)) { 33 | if (log.isTraceEnabled()) { 34 | log.trace("Login submission detected. Attempting to execute login."); 35 | } 36 | 37 | return this.executeLogin(request, response); 38 | } else { 39 | if (log.isTraceEnabled()) { 40 | log.trace("Login page view."); 41 | } 42 | 43 | return true; 44 | } 45 | } else { 46 | if (log.isTraceEnabled()) { 47 | log.trace("Attempting to access a path which requires authentication. Forwarding to the Authentication url [" + this.getLoginUrl() + "]"); 48 | } 49 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) { 50 | this.saveRequestAndRedirectToLogin(request, response); 51 | } else { 52 | ResponseUtils.responseInvalidLogin(response, requestProperties.getInvalidLoginCode()); 53 | } 54 | return false; 55 | } 56 | } 57 | 58 | protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception { 59 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) { 60 | this.issueSuccessRedirect(request, response); 61 | } else { 62 | ResponseUtils.responseJson(response, HttpServletResponse.SC_OK, Maps.immutableEntry(requestProperties.getLogInOutResponseKey(), true)); 63 | } 64 | return false; 65 | } 66 | 67 | protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) { 68 | if (log.isDebugEnabled()) { 69 | log.debug("Authentication exception", e); 70 | } 71 | 72 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) { 73 | this.setFailureAttribute(request, e); 74 | return true; 75 | } 76 | 77 | try { 78 | ResponseUtils.responseJson(response, HttpServletResponse.SC_OK, Maps.immutableEntry(requestProperties.getLogInOutResponseKey(), false)); 79 | } catch (IOException e1) { 80 | log.error("response login fail fails", e1); 81 | } 82 | return false; 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/HttpMethodPermissionFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import org.apache.shiro.util.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import javax.servlet.ServletRequest; 8 | import javax.servlet.ServletResponse; 9 | import javax.servlet.http.HttpServletRequest; 10 | import java.io.IOException; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | public class HttpMethodPermissionFilter extends PermissionsAuthorizationFilter { 15 | private static final Logger log = LoggerFactory.getLogger(HttpMethodPermissionFilter.class); 16 | private final Map httpMethodActions = new HashMap(); 17 | 18 | public HttpMethodPermissionFilter() { 19 | HttpMethodPermissionFilter.HttpMethodAction[] var1 = HttpMethodPermissionFilter.HttpMethodAction.values(); 20 | int var2 = var1.length; 21 | 22 | for (int var3 = 0; var3 < var2; ++var3) { 23 | HttpMethodPermissionFilter.HttpMethodAction methodAction = var1[var3]; 24 | this.httpMethodActions.put(methodAction.name().toLowerCase(), methodAction.getAction()); 25 | } 26 | 27 | } 28 | 29 | protected Map getHttpMethodActions() { 30 | return this.httpMethodActions; 31 | } 32 | 33 | protected String getHttpMethodAction(ServletRequest request) { 34 | String method = ((HttpServletRequest) request).getMethod(); 35 | return this.getHttpMethodAction(method); 36 | } 37 | 38 | protected String getHttpMethodAction(String method) { 39 | String lc = method.toLowerCase(); 40 | String resolved = this.getHttpMethodActions().get(lc); 41 | return resolved != null ? resolved : method; 42 | } 43 | 44 | protected String[] buildPermissions(String[] configuredPerms, String action) { 45 | if (configuredPerms != null && configuredPerms.length > 0 && StringUtils.hasText(action)) { 46 | String[] mappedPerms = new String[configuredPerms.length]; 47 | 48 | for (int i = 0; i < configuredPerms.length; ++i) { 49 | mappedPerms[i] = configuredPerms[i] + ":" + action; 50 | } 51 | 52 | if (log.isTraceEnabled()) { 53 | StringBuilder sb = new StringBuilder(); 54 | 55 | for (int i = 0; i < mappedPerms.length; ++i) { 56 | if (i > 0) { 57 | sb.append(", "); 58 | } 59 | 60 | sb.append(mappedPerms[i]); 61 | } 62 | 63 | log.trace("MAPPED '{}' action to permission(s) '{}'", action, sb); 64 | } 65 | 66 | return mappedPerms; 67 | } else { 68 | return configuredPerms; 69 | } 70 | } 71 | 72 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { 73 | String[] perms = (String[]) (mappedValue); 74 | String action = this.getHttpMethodAction(request); 75 | String[] resolvedPerms = this.buildPermissions(perms, action); 76 | return super.isAccessAllowed(request, response, resolvedPerms); 77 | } 78 | 79 | private enum HttpMethodAction { 80 | DELETE("delete"), 81 | GET("read"), 82 | HEAD("read"), 83 | MKCOL("create"), 84 | OPTIONS("read"), 85 | POST("create"), 86 | PUT("update"), 87 | TRACE("read"); 88 | 89 | private final String action; 90 | 91 | HttpMethodAction(String action) { 92 | this.action = action; 93 | } 94 | 95 | public String getAction() { 96 | return this.action; 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/LogoutFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import cn.ocoop.framework.config.RequestProperties; 4 | import cn.ocoop.framework.util.RequestUtils; 5 | import cn.ocoop.framework.util.ResponseUtils; 6 | import com.google.common.collect.Maps; 7 | import org.apache.shiro.session.SessionException; 8 | import org.apache.shiro.subject.Subject; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import javax.servlet.ServletRequest; 13 | import javax.servlet.ServletResponse; 14 | import javax.servlet.http.HttpServletResponse; 15 | 16 | public class LogoutFilter extends org.apache.shiro.web.filter.authc.LogoutFilter { 17 | private static final Logger log = LoggerFactory.getLogger(LogoutFilter.class); 18 | private RequestProperties requestProperties; 19 | 20 | public RequestProperties getRequestProperties() { 21 | return requestProperties; 22 | } 23 | 24 | public void setRequestProperties(RequestProperties requestProperties) { 25 | this.requestProperties = requestProperties; 26 | } 27 | 28 | protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { 29 | Subject subject = this.getSubject(request, response); 30 | String redirectUrl = this.getRedirectUrl(request, response, subject); 31 | 32 | try { 33 | subject.logout(); 34 | } catch (SessionException var6) { 35 | log.debug("Encountered session exception during logout. This can generally safely be ignored.", var6); 36 | } 37 | 38 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) { 39 | this.issueRedirect(request, response, redirectUrl); 40 | } else { 41 | ResponseUtils.responseJson(response, HttpServletResponse.SC_OK, Maps.immutableEntry(requestProperties.getLogInOutResponseKey(), true)); 42 | } 43 | 44 | return false; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/PermissionsAuthorizationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import org.apache.shiro.subject.Subject; 4 | 5 | import javax.servlet.ServletRequest; 6 | import javax.servlet.ServletResponse; 7 | import java.io.IOException; 8 | 9 | public class PermissionsAuthorizationFilter extends AuthorizationWithStatusCodeFilter { 10 | 11 | 12 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { 13 | Subject subject = this.getSubject(request, response); 14 | String[] perms = (String[]) mappedValue; 15 | boolean isPermitted = true; 16 | if (perms != null && perms.length > 0) { 17 | if (perms.length == 1) { 18 | if (!subject.isPermitted(perms[0])) { 19 | isPermitted = false; 20 | } 21 | } else if (!subject.isPermittedAll(perms)) { 22 | isPermitted = false; 23 | } 24 | } 25 | 26 | return isPermitted; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/RolesAuthorizationFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import org.apache.shiro.subject.Subject; 4 | import org.apache.shiro.util.CollectionUtils; 5 | 6 | import javax.servlet.ServletRequest; 7 | import javax.servlet.ServletResponse; 8 | import java.io.IOException; 9 | import java.util.Set; 10 | 11 | public class RolesAuthorizationFilter extends AuthorizationWithStatusCodeFilter { 12 | 13 | public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException { 14 | Subject subject = this.getSubject(request, response); 15 | String[] rolesArray = (String[]) mappedValue; 16 | if (rolesArray != null && rolesArray.length != 0) { 17 | Set roles = CollectionUtils.asSet(rolesArray); 18 | return subject.hasAllRoles(roles); 19 | } else { 20 | return true; 21 | } 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/filter/UserFilter.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.filter; 2 | 3 | import cn.ocoop.framework.config.RequestProperties; 4 | import cn.ocoop.framework.util.RequestUtils; 5 | import cn.ocoop.framework.util.ResponseUtils; 6 | 7 | import javax.servlet.ServletRequest; 8 | import javax.servlet.ServletResponse; 9 | 10 | public class UserFilter extends org.apache.shiro.web.filter.authc.UserFilter { 11 | private RequestProperties requestProperties; 12 | 13 | public RequestProperties getRequestProperties() { 14 | return requestProperties; 15 | } 16 | 17 | public void setRequestProperties(RequestProperties requestProperties) { 18 | this.requestProperties = requestProperties; 19 | } 20 | 21 | @Override 22 | protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { 23 | if (RequestUtils.shouldUseNormalHttpRequestToProcess(request, requestProperties.isServiceOriented())) 24 | return super.onAccessDenied(request, response); 25 | 26 | ResponseUtils.responseInvalidLogin(response, requestProperties.getInvalidLoginCode()); 27 | return false; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/session/RedisSessionDAO.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.session; 2 | 3 | import org.apache.commons.collections.CollectionUtils; 4 | import org.apache.shiro.session.Session; 5 | import org.apache.shiro.session.UnknownSessionException; 6 | import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; 7 | import org.springframework.dao.DataAccessException; 8 | import org.springframework.data.redis.core.RedisOperations; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.data.redis.core.SessionCallback; 11 | 12 | import java.io.Serializable; 13 | import java.util.Collection; 14 | import java.util.List; 15 | import java.util.Set; 16 | import java.util.concurrent.TimeUnit; 17 | 18 | public class RedisSessionDAO extends AbstractSessionDAO { 19 | private RedisTemplate redisTemplate; 20 | private String sessionCacheName = "shiro:session:"; 21 | 22 | public RedisSessionDAO() { 23 | } 24 | 25 | public RedisSessionDAO(RedisTemplate redisTemplate) { 26 | this.redisTemplate = redisTemplate; 27 | } 28 | 29 | public String getSessionCacheName() { 30 | return sessionCacheName; 31 | } 32 | 33 | public void setSessionCacheName(String sessionCacheName) { 34 | this.sessionCacheName = sessionCacheName; 35 | } 36 | 37 | @Override 38 | protected Serializable doCreate(Session session) { 39 | Serializable sessionId = this.generateSessionId(session); 40 | this.assignSessionId(session, sessionId); 41 | saveSession(session); 42 | return sessionId; 43 | } 44 | 45 | private void saveSession(Session session) { 46 | if (session == null || session.getId() == null) return; 47 | 48 | final Long expireValue = Long.valueOf(session.getTimeout() / 1000L); 49 | final String sessionKey = getSessionKey(session.getId()); 50 | this.redisTemplate.execute(new SessionCallback>() { 51 | public List execute(RedisOperations operations) throws DataAccessException { 52 | operations.multi(); 53 | operations.opsForValue().set(sessionKey, session); 54 | operations.expire(sessionKey, expireValue.longValue(), TimeUnit.SECONDS); 55 | return operations.exec(); 56 | } 57 | }); 58 | } 59 | 60 | private String getSessionKey(Serializable sessionId) { 61 | return sessionCacheName + sessionId; 62 | } 63 | 64 | @Override 65 | protected Session doReadSession(Serializable sessionId) { 66 | if (sessionId == null) return null; 67 | return (Session) redisTemplate.opsForValue().get(getSessionKey(sessionId)); 68 | } 69 | 70 | @Override 71 | public void update(Session session) throws UnknownSessionException { 72 | saveSession(session); 73 | } 74 | 75 | @Override 76 | public void delete(Session session) { 77 | if (session.getId() == null) return; 78 | redisTemplate.delete(getSessionKey(session.getId())); 79 | } 80 | 81 | @Override 82 | public Collection getActiveSessions() { 83 | Set keys = redisTemplate.keys(sessionCacheName + "*"); 84 | if (CollectionUtils.isEmpty(keys)) return null; 85 | return redisTemplate.opsForValue().multiGet(keys); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/util/RequestUtils.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.util; 2 | 3 | import org.apache.shiro.web.util.WebUtils; 4 | 5 | import javax.servlet.ServletRequest; 6 | 7 | public class RequestUtils { 8 | 9 | public static boolean isAjaxRequest(ServletRequest request) { 10 | 11 | String requestHeader = WebUtils.toHttp(request).getHeader("X-Requested-With"); 12 | return requestHeader != null && "XMLHttpRequest".equals(requestHeader); 13 | } 14 | 15 | public static boolean shouldUseNormalHttpRequestToProcess(ServletRequest request, boolean serviceOriented) { 16 | return !isAjaxRequest(request) && !serviceOriented; 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/util/ResponseUtils.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.util; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import org.apache.shiro.web.util.WebUtils; 5 | import org.springframework.http.MediaType; 6 | 7 | import javax.servlet.ServletResponse; 8 | import javax.servlet.http.HttpServletResponse; 9 | import java.io.IOException; 10 | import java.io.PrintWriter; 11 | 12 | public class ResponseUtils { 13 | 14 | public static void response(ServletResponse response, MediaType mediaType, int statusCode, String message) throws IOException { 15 | HttpServletResponse resp = WebUtils.toHttp(response); 16 | resp.setContentType(mediaType.toString()); 17 | resp.setCharacterEncoding("UTF-8"); 18 | resp.setHeader("Cache-Control", "no-cache"); 19 | resp.setStatus(statusCode); 20 | PrintWriter writer = resp.getWriter(); 21 | writer.write(message); 22 | writer.flush(); 23 | } 24 | 25 | public static void responseJson(ServletResponse response, int statusCode, Object message) throws IOException { 26 | response(response, MediaType.APPLICATION_JSON_UTF8, statusCode, JSON.toJSONString(message)); 27 | } 28 | 29 | public static void responseInvalidLogin(ServletResponse response, int statusCode) throws IOException { 30 | response(response, MediaType.ALL, statusCode, "login state is invalid"); 31 | } 32 | 33 | public static void responseInvalidPermission(ServletResponse response, int statusCode) throws IOException { 34 | response(response, MediaType.ALL, statusCode, "you have no enough permission to access"); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/web/mgt/CookieRememberMeManager.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.web.mgt; 2 | 3 | import org.springframework.expression.spel.standard.SpelExpressionParser; 4 | 5 | public class CookieRememberMeManager extends org.apache.shiro.web.mgt.CookieRememberMeManager { 6 | private static final SpelExpressionParser SPEL_EXPRESSION_PARSER = new SpelExpressionParser(); 7 | private String cookieCipherKey; 8 | 9 | public String getCookieCipherKey() { 10 | return cookieCipherKey; 11 | } 12 | 13 | public void setCookieCipherKey(String cookieCipherKey) { 14 | super.setCipherKey( 15 | String.valueOf( 16 | SPEL_EXPRESSION_PARSER.parseExpression( 17 | new String(cookieCipherKey) 18 | ).getValue() 19 | ).getBytes() 20 | ); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/main/java/cn/ocoop/framework/web/mgt/DefaultWebSecurityManager.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.framework.web.mgt; 2 | 3 | import cn.ocoop.framework.cache.ShiroRealmCacheManager; 4 | 5 | public class DefaultWebSecurityManager extends org.apache.shiro.web.mgt.DefaultWebSecurityManager { 6 | @Override 7 | protected void afterRealmsSet() { 8 | super.afterRealmsSet(); 9 | ShiroRealmCacheManager.setRealms(getRealms()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /shiro-spring-boot-autoconfigure/src/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ 2 | cn.ocoop.framework.ShiroAutoConfiguration -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.iml 3 | .idea 4 | target 5 | .DS_Store 6 | *.log 7 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | cn.ocoop.example 7 | shiro-spring-boot-starter-example 8 | 1.0.1 9 | 10 | shiro-spring-boot-starter-example 11 | http://maven.apache.org 12 | 13 | 14 | 1.8 15 | 2.8.9 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-parent 20 | 1.5.3.RELEASE 21 | 22 | 23 | 24 | 25 | 26 | org.springframework.boot 27 | spring-boot-starter-web 28 | 29 | 30 | org.springframework.boot 31 | spring-boot-starter-data-redis 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-configuration-processor 36 | true 37 | 38 | 39 | 40 | cn.ocoop.framework 41 | shiro-spring-boot-starter 42 | 1.0.1 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-maven-plugin 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/src/main/java/cn/App.java: -------------------------------------------------------------------------------- 1 | package cn; 2 | 3 | import org.springframework.boot.Banner; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * Hello world! 9 | */ 10 | @SpringBootApplication 11 | public class App { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication springApplication = new SpringApplication(App.class); 15 | springApplication.setBannerMode(Banner.Mode.OFF); 16 | springApplication.run(args); 17 | } 18 | 19 | 20 | } 21 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/src/main/java/cn/RedisCachingConfigure.java: -------------------------------------------------------------------------------- 1 | package cn; 2 | 3 | import org.springframework.cache.CacheManager; 4 | import org.springframework.cache.annotation.CachingConfigurerSupport; 5 | import org.springframework.cache.annotation.EnableCaching; 6 | import org.springframework.cache.interceptor.CacheResolver; 7 | import org.springframework.cache.interceptor.KeyGenerator; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.data.redis.cache.RedisCacheManager; 11 | import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; 12 | import org.springframework.data.redis.core.RedisTemplate; 13 | import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; 14 | import org.springframework.data.redis.serializer.StringRedisSerializer; 15 | 16 | @Configuration 17 | @EnableCaching 18 | public class RedisCachingConfigure extends CachingConfigurerSupport { 19 | 20 | @Bean 21 | public RedisTemplate redisTemplate(JedisConnectionFactory connectionFactory) { 22 | RedisTemplate template = new RedisTemplate(); 23 | template.setConnectionFactory(connectionFactory); 24 | template.setDefaultSerializer(new JdkSerializationRedisSerializer()); 25 | template.setKeySerializer(new StringRedisSerializer()); 26 | template.afterPropertiesSet(); 27 | return template; 28 | } 29 | 30 | @Bean 31 | public CacheManager cacheManager(RedisTemplate redisTemplate) { 32 | RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate, null, true); 33 | redisCacheManager.setUsePrefix(true); 34 | redisCacheManager.setDefaultExpiration(600L); 35 | return redisCacheManager; 36 | } 37 | 38 | @Override 39 | public CacheResolver cacheResolver() { 40 | return super.cacheResolver(); 41 | } 42 | 43 | public KeyGenerator keyGenerator() { 44 | // configure and return an implementation of Spring's KeyGenerator SPI 45 | return (target, method, params) -> { 46 | StringBuilder sb = new StringBuilder(); 47 | sb.append(target.getClass().getName()); 48 | sb.append("."); 49 | sb.append(method.getName()); 50 | for (Object obj : params) { 51 | sb.append("_"); 52 | if (obj == null) sb.append("NULL"); 53 | else if (obj == "") sb.append("EMPTY_STRING"); 54 | else sb.append(obj.toString()); 55 | } 56 | return sb.toString(); 57 | }; 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/src/main/java/cn/ocoop/demo/DemoController.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.demo; 2 | 3 | import org.apache.shiro.authz.annotation.RequiresGuest; 4 | import org.apache.shiro.authz.annotation.RequiresPermissions; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RestController; 7 | 8 | @RestController 9 | public class DemoController { 10 | 11 | @RequestMapping("/a") 12 | public void a() { 13 | } 14 | 15 | @RequestMapping("/b") 16 | public void b() { 17 | } 18 | 19 | 20 | @RequiresPermissions("permissionC") 21 | @RequestMapping("/c") 22 | public void c() { 23 | } 24 | 25 | @RequiresGuest 26 | @RequestMapping("/d") 27 | public void d() { 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/src/main/java/cn/ocoop/demo/DemoRealm.java: -------------------------------------------------------------------------------- 1 | package cn.ocoop.demo; 2 | 3 | import cn.ocoop.framework.authz.SimpleAuthorizationInfoOrdered; 4 | import org.apache.shiro.authc.AuthenticationException; 5 | import org.apache.shiro.authc.AuthenticationInfo; 6 | import org.apache.shiro.authc.AuthenticationToken; 7 | import org.apache.shiro.authc.SimpleAuthenticationInfo; 8 | import org.apache.shiro.authz.AuthorizationInfo; 9 | import org.apache.shiro.realm.AuthorizingRealm; 10 | import org.apache.shiro.subject.PrincipalCollection; 11 | import org.apache.shiro.util.SimpleByteSource; 12 | 13 | import java.util.Arrays; 14 | 15 | public class DemoRealm extends AuthorizingRealm { 16 | @Override 17 | protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { 18 | //有序的角色,权限集合实现 19 | SimpleAuthorizationInfoOrdered authorizationInfo = new SimpleAuthorizationInfoOrdered(); 20 | authorizationInfo.setRoles(Arrays.asList("角色1", "角色2")); 21 | authorizationInfo.setStringPermissions(Arrays.asList("权限1", "权限2")); 22 | return authorizationInfo; 23 | } 24 | 25 | @Override 26 | protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { 27 | return new SimpleAuthenticationInfo( 28 | "用户名", 29 | "密码密文", 30 | new SimpleByteSource("盐值"), 31 | this.getName() 32 | ); 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter-example/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | #redis 配置 2 | spring: 3 | redis: 4 | database: 0 5 | host: 127.0.0.1 6 | password: 7 | port: 6379 8 | timeout: 100 9 | jedis: 10 | pool: 11 | max-active: 8 12 | max-idle: 8 13 | max-wait: -1 14 | min-idle: 0 15 | 16 | # shiro配置 17 | shiro: 18 | session: 19 | sessionIdCookie: 20 | name: session-id 21 | path: / 22 | max-age: -1 23 | session-id-cookie-enabled: true 24 | session-id-url-rewriting-enabled: true 25 | global-session-timeout: 1800000 26 | session-cache-name: "shiro:session:" 27 | 28 | realms: 29 | - realm: 30 | target: cn.ocoop.demo.DemoRealm 31 | property: 32 | cachingEnabled: true 33 | authenticationCachingEnabled: true 34 | authorizationCachingEnabled: true 35 | authenticationCacheName: DemoRealm:authenticationCache 36 | authorizationCacheName: DemoRealm:authorizationCache 37 | credentials-matcher: 38 | target: org.apache.shiro.authc.credential.HashedCredentialsMatcher 39 | property: 40 | hashAlgorithmName: MD5 41 | hashIterations: 2 42 | storedCredentialsHexEncoded: true 43 | 44 | remember-me: 45 | cookie-cipher-key: T(org.apache.shiro.codec.Base64).decode('xVmmoltfpb8tTceuT5R7Bw==') 46 | cookie: 47 | name: remember-me 48 | path: / 49 | max-age: 31536000 50 | 51 | login-url: /login 52 | success-url: /index 53 | unauthorized-url: /unauthorized 54 | invalid-login-code: 418 55 | invalid-permission-code: 401 56 | service-oriented: false 57 | log-in-out-response-key: success 58 | 59 | #filters: 60 | # anon: org.apache.shiro.web.filter.authc.AnonymousFilter 61 | 62 | filter-chain-definitions-map: 63 | /a : authc 64 | /** : anon -------------------------------------------------------------------------------- /shiro-spring-boot-starter/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .gitignore support plugin (hsz.mobi) 2 | *.iml 3 | .idea 4 | target 5 | .DS_Store 6 | *.log 7 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | 6 | cn.ocoop.framework 7 | spring-boot-starter 8 | 1.0.1 9 | 10 | 11 | shiro-spring-boot-starter 12 | 13 | Spring Boot AutoConfiguration :: Apache Shiro Starter 14 | http://maven.apache.org 15 | 16 | 17 | UTF-8 18 | 19 | 20 | 21 | 22 | org.springframework.boot 23 | spring-boot-starter 24 | 25 | 26 | cn.ocoop.framework 27 | shiro-spring-boot-autoconfigure 28 | 1.0 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /shiro-spring-boot-starter/src/main/resources/META-INF/spring.provides: -------------------------------------------------------------------------------- 1 | provides: shiro-spring-boot-autoconfigure --------------------------------------------------------------------------------