├── .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 extends AuthenticatingRealm>... 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 extends AuthenticatingRealm>... 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