按照上篇的cas服务端的配置一样,集成shiro+pac4j,其实在1.3还是1.2shiro-cas就过期了,shiro官方也让我们集成pac4j,但是居然居然没有demo,我也是服,,。。

此篇博客将集成springboot+cas5+shiro+pac4j 集成在一起,是宝宝将近一个月的心血,还有老大的帮忙!!!!

开始我的表演:

首先是pom

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>

<groupId>com.bofeng.shiro</groupId>

<artifactId>shiro-cas-pac4j</artifactId>

<version>1.0.0</version>

<properties>

<java.version>1.8</java.version>

<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

<project.build.java.version>1.8</project.build.java.version>

<logback.version>1.1.3</logback.version>

<commons-lang3.version>3.4</commons-lang3.version>

<guava.version>18.0</guava.version>

<fastjson.version>1.2.8</fastjson.version>

<commons-io.version>2.4</commons-io.version>

<commons-codec.version>1.10</commons-codec.version>

<shiro.version>1.4.0</shiro.version>

<buji.version>3.0.0</buji.version>

<pac4j.version>2.1.0</pac4j.version>

<cas-client.version>3.4.1</cas-client.version>

<log4jdbc.remix.version>0.2.7</log4jdbc.remix.version>

<slf4j.version>1.7.21</slf4j.version>

<logback.version>1.1.7</logback.version>

<lombok.version>1.16.20</lombok.version>

</properties>

<dependencies>

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-spring-boot-web-starter</artifactId>

<version>${shiro.version}</version>

</dependency>

<dependency>

<groupId>io.buji</groupId>

<artifactId>buji-pac4j</artifactId>

<version>${buji.version}</version>

</dependency>

<dependency>

<groupId>org.pac4j</groupId>

<artifactId>pac4j-cas</artifactId>

<version>${pac4j.version}</version>

</dependency>

<dependency>

<groupId>org.pac4j</groupId>

<artifactId>pac4j-jwt</artifactId>

<version>${pac4j.version}</version>

</dependency>

<dependency>

<groupId>org.pac4j</groupId>

<artifactId>pac4j-http</artifactId>

<version>${pac4j.version}</version>

</dependency>

<dependency>

<groupId>com.alibaba</groupId>

<artifactId>fastjson</artifactId>

<version>1.2.7</version>

</dependency>

<dependency>

<groupId>org.slf4j</groupId>

<artifactId>slf4j-api</artifactId>

<version>${slf4j.version}</version>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-classic</artifactId>

<version>${logback.version}</version>

</dependency>

<dependency>

<groupId>ch.qos.logback</groupId>

<artifactId>logback-core</artifactId>

<version>${logback.version}</version>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<version>${lombok.version}</version>

<scope>provided</scope>

</dependency>

</dependencies>

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

<configuration>

<executable>true</executable>

</configuration>

</plugin>

</plugins>

</build>

</project>

然后是shiro 的认证,由于集成了pac4j,所以我们只要关心权限

的控制就可以了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Slf4j

public class ShiroPac4jRealm extends Pac4jRealm {

@Override

protected AuthorizationInfo doGetAuthorizationInfo(final PrincipalCollection principals) {

Object user = super.getAvailablePrincipal(principals);

log.info("登录用户:{}", user);

SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

List<String> permissions = new ArrayList<String>();

permissions.add("user:info");

simpleAuthorizationInfo.addStringPermissions(permissions);

return simpleAuthorizationInfo;

}

}

shiro这里不详解,只说集成,shiro的配置如下

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
package com.bofeng.shiro.config;

import io.buji.pac4j.filter.CallbackFilter;

import io.buji.pac4j.filter.SecurityFilter;

import io.buji.pac4j.subject.Pac4jSubjectFactory;

import org.apache.shiro.mgt.SubjectFactory;

import org.apache.shiro.realm.Realm;

import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;

import org.apache.shiro.spring.web.config.AbstractShiroWebFilterConfiguration;

import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;

import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;

import org.apache.shiro.web.mgt.DefaultWebSecurityManager;

import org.jasig.cas.client.session.SingleSignOutFilter;

import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;

import org.pac4j.cas.client.CasClient;

import org.pac4j.cas.client.rest.CasRestFormClient;

import org.pac4j.cas.config.CasConfiguration;

import org.pac4j.cas.config.CasProtocol;

import org.pac4j.core.client.Clients;

import org.pac4j.core.config.Config;

import org.pac4j.core.matching.PathMatcher;

import org.pac4j.http.client.direct.ParameterClient;

import org.pac4j.jwt.config.encryption.SecretEncryptionConfiguration;

import org.pac4j.jwt.config.signature.SecretSignatureConfiguration;

import org.pac4j.jwt.credentials.authenticator.JwtAuthenticator;

import org.pac4j.jwt.profile.JwtGenerator;

import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;

import org.springframework.beans.factory.annotation.Value;

import org.springframework.boot.web.servlet.FilterRegistrationBean;

import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.annotation.DependsOn;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.Order;

import org.springframework.web.filter.DelegatingFilterProxy;

import javax.servlet.Filter;

import java.util.HashMap;

import java.util.Map;

@Configuration

public class ShiroConfiguration extends AbstractShiroWebFilterConfiguration {

@Value("#{ @environment['cas.prefixUrl'] ?: null }")

private String prefixUrl;

@Value("#{ @environment['cas.loginUrl'] ?: null }")

private String casLoginUrl;

@Value("#{ @environment['cas.callbackUrl'] ?: null }")

private String callbackUrl;

@Value("${jwt.salt}")

private String salt;

@SuppressWarnings("rawtypes")

@Bean

protected JwtGenerator jwtGenerator() {

return new JwtGenerator(new SecretSignatureConfiguration(salt), new SecretEncryptionConfiguration(salt));

}

@Bean

protected JwtAuthenticator jwtAuthenticator() {

JwtAuthenticator jwtAuthenticator = new JwtAuthenticator();

jwtAuthenticator.addSignatureConfiguration(new SecretSignatureConfiguration(salt));

jwtAuthenticator.addEncryptionConfiguration(new SecretEncryptionConfiguration(salt));

return jwtAuthenticator;

}

@Bean

public CasConfiguration casConfiguration() {

CasConfiguration casConfiguration = new CasConfiguration(casLoginUrl);

casConfiguration.setProtocol(CasProtocol.CAS20);

casConfiguration.setPrefixUrl(prefixUrl);

return casConfiguration;

}

@Bean

public PathMatcher pathMatcher() {

PathMatcher pathMatcher = new PathMatcher();

pathMatcher.excludePath("/html/**");

return pathMatcher;

}

@Bean(name = "pac4jRealm")

public Realm pac4jRealm() {

return new ShiroPac4jRealm();

}

@Bean

protected CasRestFormClient casRestFormClient(CasConfiguration casConfiguration) {

CasRestFormClient casRestFormClient = new CasRestFormClient();

casRestFormClient.setConfiguration(casConfiguration);

casRestFormClient.setName("rest");

return casRestFormClient;

}

@Bean

public CasClient casClient(CasConfiguration casConfiguration) {

CasClient casClient = new CasClient();

casClient.setConfiguration(casConfiguration);

casClient.setCallbackUrl(callbackUrl);

casClient.setName("cas");

return casClient;

}

@Bean

protected Clients clients(CasClient casClient, CasRestFormClient casRestFormClient) {

Clients clients = new Clients();

ParameterClient parameterClient = new ParameterClient("token", jwtAuthenticator());

parameterClient.setSupportGetRequest(true);

parameterClient.setName("jwt");

clients.setClients(casClient, casRestFormClient, parameterClient);

return clients;

}

@Bean

protected Config casConfig(Clients clients) {

Config config = new Config();

config.setClients(clients);

return config;

}

@Bean(name = "subjectFactory")

protected SubjectFactory subjectFactory() {

return new Pac4jSubjectFactory();

}

@SuppressWarnings({"rawtypes", "unchecked"})

@Bean

public ServletListenerRegistrationBean<?> singleSignOutHttpSessionListener() {

ServletListenerRegistrationBean bean = new ServletListenerRegistrationBean();

bean.setListener(new SingleSignOutHttpSessionListener());

bean.setEnabled(true);

return bean;

}

@Bean

@Order(Ordered.HIGHEST_PRECEDENCE)

public FilterRegistrationBean singleSignOutFilter() {

FilterRegistrationBean bean = new FilterRegistrationBean();

bean.setName("singleSignOutFilter");

SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();

singleSignOutFilter.setCasServerUrlPrefix(prefixUrl);

singleSignOutFilter.setIgnoreInitConfiguration(true);

bean.setFilter(singleSignOutFilter);

bean.addUrlPatterns("/*");

bean.setEnabled(true);

return bean;

}

@Bean(name = "securityManager")

public DefaultWebSecurityManager securityManager(Realm pac4jRealm, SubjectFactory subjectFactory) {

DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

defaultWebSecurityManager.setRealm(pac4jRealm);

defaultWebSecurityManager.setSubjectFactory(subjectFactory);

return defaultWebSecurityManager;

}

@Bean

public FilterRegistrationBean filterRegistrationBean() {

FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();

filterRegistrationBean.setFilter(new DelegatingFilterProxy("shiroFilter"));

filterRegistrationBean.addInitParameter("targetFilterLifecycle", "true");

filterRegistrationBean.setEnabled(true);

filterRegistrationBean.addUrlPatterns("/*");

return filterRegistrationBean;

}

@Bean(name = "shiroFilter")

protected ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager, Config config) {

ShiroFilterFactoryBean filterFactoryBean = super.shiroFilterFactoryBean();

filterFactoryBean.setSecurityManager(securityManager);

Map<String, Filter> filters = new HashMap<String, Filter>();

SecurityFilter securityFilter = new SecurityFilter();

securityFilter.setClients("cas,rest,jwt");

securityFilter.setConfig(config);

filters.put("casSecurityFilter", securityFilter);

CallbackFilter callbackFilter = new CallbackFilter();

callbackFilter.setConfig(config);

filters.put("callbackFilter", callbackFilter);

filterFactoryBean.setFilters(filters);

return filterFactoryBean;

}

@Bean

public ShiroFilterChainDefinition shiroFilterChainDefinition() {

DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();

definition.addPathDefinition("/callback", "callbackFilter");

definition.addPathDefinition("/you", "anon");

definition.addPathDefinition("/**", "casSecurityFilter");

return definition;

}

@Bean

@DependsOn({"lifecycleBeanPostProcessor"})

public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {

DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();

advisorAutoProxyCreator.setProxyTargetClass(true);

return advisorAutoProxyCreator;

}

@Bean

public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) {

AuthorizationAttributeSourceAdvisor aasa = new AuthorizationAttributeSourceAdvisor();

aasa.setSecurityManager(securityManager);

return aasa;

}

}

一个配置类

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.bofeng.shiro.config;

import org.apache.shiro.authz.AuthorizationException;

import org.apache.shiro.authz.UnauthorizedException;

import org.springframework.web.bind.annotation.ExceptionHandler;

import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;

import java.util.HashMap;

import java.util.Map;

@RestControllerAdvice

public class ShiroExceptionHandler {

@ExceptionHandler(value = {UnauthorizedException.class})

public Map<String, Object> unauthorizedExceptionHandler(HttpServletRequest request, Exception e) {

return noPermissionResult();

}

private Map<String, Object> noPermissionResult() {

Map<String, Object> result = new HashMap<String, Object>() {

private static final long serialVersionUID = 1L;

{

put("errcode", 0);

put("errmsg", "暂无权限");

}

};

return result;

}

}

启动类顺便也贴出来了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.bofeng.shiro;

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authz.annotation.RequiresPermissions;

import org.apache.shiro.subject.PrincipalCollection;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@SpringBootApplication

public class Application {

public static void main(String[] args) {

SpringApplication.run(Application.class, args);

}

@RequiresPermissions(value = "role:edit")

@GetMapping(value = "/roles/{id}")

public String put(){

return "允许修改角色";

}

@RequiresPermissions(value = "user:info")

@GetMapping(value = "/users/{id}")

public PrincipalCollection getUserById() {

return SecurityUtils.getSubject().getPrincipals();

}

@GetMapping(value = "/you")

public String you(){

return "you you 不需要权限";

}

}

最重要的yml文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server:

port: 8083

spring:

http:

encoding:

charset: UTF-8

enabled: true

force: true

mail:

default-encoding: UTF-8

messages:

encoding: UTF-8

casServerUrlPrefix: https:

cas:

prefixUrl: https:

loginUrl: ${cas.prefixUrl}/login

logoutUrl: ${cas.prefixUrl}/logout

serviceUrl: http:

callbackUrl: ${cas.serviceUrl}/callback

jwt:

salt: cas

debug: true

配置什么的你们看自己需求改,host别说不会

到这里Springboot的客户端就集成好了,如果还是有问题的话Q845896876交流

如果这篇博客帮你解决了问题,那么那么请给宝宝一点动力

源码提供给大家参考   请分开tomcat部署   https://download.csdn.net/download/weixin_39819191/10422417

验证码,自定义登录页面>https://blog.csdn.net/u010588262/article/details/80014083

跑源码发现的几个类,

这个是前后端分离AJAX调用时返回的类,但是发现个没效果的问题,

最后让前端在请求头里面加入 X-Requested-With=XMLHttpRequest  就好了,不知道怎么回事,,,

判断是不是ajax的类

问题: ajax请求后无法正常登陆,确认是session不对,跨域问题,

解决:前端判断401,跳转到后台一个特殊接口,接口无权访问会跳到cas登录页,登陆后跳转到接口,接口转发到前端路由

有点绕,,,但是就这么解决问题了,,