环境:
jdk:1.8
cas server:5.3.14 + tomcat 8.5
cas client:3.5.1
客户端1:springmvc 传统web项目(使用web.xml)
客户端2:springboot
为了方便,没配置https.如果需要参考上面博客
一.CAS 服务端搭建
1.下载源码包:cas overlay github地址:https://github.com/apereo/cas-overlay-template/tree/5.3
2.部署:
在根目录下执行mvn clean package,下载依赖需要一段时间,如果有的包下载失败就要修改pom.xml比如xmlsectool的jar包要先从maven中央仓库手动下载,然后加进去,我的放到了图中的maven目录下
以下是我修改的pom.xml,对xmlselectool依赖路径进行了更改,增加了json注册服务,jdbc验证等依赖包
1
2
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd ">
5
6
7 4.0.0
8 org.apereo.cas
9 cas-overlay
10 war
11 1.0
12
13
14
15
16 com.rimerosolutions.maven.plugins
17 wrapper-maven-plugin
18 0.0.5
19
20 true
21 MD5
22
23
24
25 org.springframework.boot
26 spring-boot-maven-plugin
27 ${springboot.version}
28
29 ${mainClassName}
30 true
31 ${isExecutable}
32 WAR
33
34
35
36
37 repackage
38
39
40
41
42
43 org.apache.maven.plugins
44 maven-war-plugin
45 2.6
46
47 cas
48 false
49 false
50
51 false
52 ${manifestFileToUse}
53
54
55
56 org.apereo.cas
57 cas-server-webapp${app.server}
58
59
60
61
62
63 org.apache.maven.plugins
64 maven-compiler-plugin
65 3.3
66
67
68 cas
69
70
71
72 5.3.14
73 1.5.18.RELEASE
74 1.3.2
75 3.4.6
76
77 -tomcat
78
79 org.springframework.boot.loader.WarLauncher
80 false
81 ${project.build.directory}/war/work/org.apereo.cas/cas-server-webapp${app.server}/META-INF/MANIFEST.MF
82
83 1.8
84 1.8
85 UTF-8
86
87
88
89
90 net.shibboleth.tool
91 xmlsectool
92 2.0.0
93 system
94 ${pom.basedir}/maven/xmlsectool-2.0.0.jar
95
96
97
98 org.apereo.cas
99 cas-server-support-jdbc
100 ${cas.version}
101
102
103 jul-to-slf4j
104 org.slf4j
105
106
107
108
109
110
111 org.apereo.cas
112 cas-server-core-cookie
113 ${cas.version}
114
115
116
117 org.apereo.cas
118 cas-server-support-jdbc-drivers
119 ${cas.version}
120 runtime
121
122
123
124 org.apereo.cas
125 cas-server-core-configuration
126 ${cas.version}
127
128
129
130
131 org.apereo.cas
132 cas-server-core-authentication-api
133 ${cas.version}
134
135
136
137
138 org.apereo.cas
139 cas-server-core-configuration-api
140 ${cas.version}
141
142
143
144
145 org.apereo.cas
146 cas-server-support-json-service-registry
147 ${cas.version}
148
149
150
151
152 org.apereo.cas
153 cas-server-core-authentication-attributes
154 ${cas.version}
155
156
157
158 com.alibaba
159 fastjson
160 1.2.56
161
162
163
164
165
166 org.projectlombok
167 lombok
168 1.18.10
169 provided
170
171
172
173 org.apereo.cas
174 cas-server-core-webflow
175 ${cas.version}
176
177
178
179
180
181
182
183
184
185
186 true
187
188 default
189
190
191 org.apereo.cas
192 cas-server-webapp${app.server}
193 ${cas.version}
194 war
195 runtime
196
197
200
201
202
203
204
205 false
206
207 exec
208
209 org.apereo.cas.web.CasWebApplication
210 true
211
212
213
214
215
216 com.soebes.maven.plugins
217 echo-maven-plugin
218 0.3.0
219
220
221 prepare-package
222
223 echo
224
225
226
227
228
229 Executable profile to make the generated CAS web application executable.
230
231
232
233
234
235
236
237
238
239 false
240
241 bootiful
242
243 -tomcat
244 false
245
246
247
248 org.apereo.cas
249 cas-server-webapp${app.server}
250 ${cas.version}
251 war
252 runtime
253
254
255
256
257
258
259 false
260
261 pgp
262
263
264
265 com.github.s4u.plugins
266 pgpverify-maven-plugin
267 1.1.0
268
269
270
271 check
272
273
274
275
276 hkp://pool.sks-keyservers.net
277 ${settings.localRepository}/pgpkeys-cache
278 test
279 true
280 false
281
282
283
284
285
286
287
View Code
导入idea,导入的时候可以看到实际导入的是
新建src/main/java和resources,鼠标放到项目上,然后F4,把java目录标记为sources,resources标记为resources
从overlays目录下的WEB-INF拷贝services,META-INF文件夹已经application.properties到我们新建的resources目录下
先说下services文件夹,该文件夹下的json文件定义了哪些应用要接入cas,命名格式为 app-id.json如
重点讲下两个属性:1.serviceId定义哪些服务可以接入,可以写统配符,也可以用项目名2.attributeReleaseStrategy定义返回哪些属性,比如登录后返回的用户信息,其他的参考
application.properties,端口号,项目名,开启json服务识别
1 ##2 # CAS Server Context Configuration3 #4 server.context-path=/cas5 #server.port=8443
6 server.port=8090
7 server.ssl.enabled=false
8 #server.ssl.key-store=file:/etc/cas/thekeystore9 #server.ssl.key-store-password=changeit10 #server.ssl.key-password=changeit11
12 cas.tgc.secure=false
13
14 spring.devtools.restart.enabled=true
15
16
17 server.max-http-header-size=2097152
18 server.use-forward-headers=true
19 server.connection-timeout=20000
20 server.error.include-stacktrace=ALWAYS21
22 server.compression.enabled=true
23 server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain24
25 server.tomcat.max-http-post-size=2097152
26 server.tomcat.basedir=build/tomcat27 server.tomcat.accesslog.enabled=true
28 server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)29 server.tomcat.accesslog.suffix=.log30 server.tomcat.min-spare-threads=10
31 server.tomcat.max-threads=200
32 server.tomcat.port-header=X-Forwarded-Port33 server.tomcat.protocol-header=X-Forwarded-Proto34 server.tomcat.protocol-header-https-value=https35 server.tomcat.remote-ip-header=X-FORWARDED-FOR36 server.tomcat.uri-encoding=UTF-8
37
38 spring.http.encoding.charset=UTF-8
39 spring.http.encoding.enabled=true
40 spring.http.encoding.force=true
41
42 ##43 # CAS Cloud Bus Configuration44 #45 spring.cloud.bus.enabled=false
46
47 # Indicates that systemPropertiesOverride can be used.48 # Set to false to prevent users from changing the default accidentally. Default true.49 spring.cloud.config.allow-override=true
50
51 # External properties should override system properties.52 spring.cloud.config.override-system-properties=false
53
54 # When allowOverride is true, external properties should take lowest priority, and not override any55 # existing property sources (including local config files).56 spring.cloud.config.override-none=false
57
58 # spring.cloud.bus.refresh.enabled=true
59 # spring.cloud.bus.env.enabled=true
60 # spring.cloud.bus.destination=CasCloudBus61 # spring.cloud.bus.ack.enabled=true
62
63 endpoints.enabled=false
64 endpoints.sensitive=true
65
66 endpoints.restart.enabled=false
67 endpoints.shutdown.enabled=false
68
69 # Control the security of the management/actuator endpoints70 # The 'enabled' flag below here controls the rendering of details forthe health endpoint amongst other things.71 management.security.enabled=true
72 management.security.roles=ACTUATOR,ADMIN73 management.security.sessions=if_required74 management.context-path=/status75 management.add-application-context-header=false
76
77 # Define a CAS-specific "WARN"status code and its order78 management.health.status.order=WARN, DOWN, OUT_OF_SERVICE, UNKNOWN, UP79
80 # Control the security of the management/actuator endpoints81 # With basic authentication, assuming Spring Security and/or relevant modules are on the classpath.82 security.basic.authorize-mode=role83 security.basic.path=/cas/status/**
84 security.basic.enabled=true85 security.user.name=casuser86 security.user.password=12387
88 ##89 # CAS Web Application Session Configuration90 #91 server.session.timeout=300092 server.session.cookie.http-only=false93 server.session.tracking-modes=COOKIE94
95 ##96 # CAS Thymeleaf View Configuration97 #98 spring.thymeleaf.encoding=UTF-899 spring.thymeleaf.cache=true100 spring.thymeleaf.mode=HTML101 spring.thymeleaf.template-resolver-order=100102 ##103 # CAS Log4j Configuration104 #105 # logging.config=file:/etc/cas/log4j2.xml106 server.context-parameters.isLog4jAutoInitializationDisabled=true107
108 ##109 # CAS AspectJ Configuration110 #111 spring.aop.auto=true112 spring.aop.proxy-target-class=true113
114 ##115 # CAS Authentication Credentials116 #117 #cas.authn.accept.users=wangyuancheng::Baizhu7958118
119
120
121 ##122 # Service Registry(服务注册)123 #124 # 开启识别Json文件,默认false125 cas.serviceRegistry.initFromJson=true126
127 #自动扫描服务配置,默认开启128 #cas.serviceRegistry.watcherEnabled=true129
130 #120秒扫描一遍131 cas.serviceRegistry.schedule.repeatInterval=120000132
133 #延迟15秒开启134 # cas.serviceRegistry.schedule.startDelay=15000135
136 ##137 # Json配置138 cas.serviceRegistry.json.location=classpath:/services139
140
141 cas.ticket.tgt.maxTimeToLiveInSeconds=28800142 cas.ticket.tgt.timeToKillInSeconds=7200143 cas.ticket.tgt.rememberMe.enabled=true144 # 使用次数145 cas.ticket.st.numberOfUses=1146 # 过期时间100秒147 cas.ticket.st.timeToKillInSeconds=100148
149 cas.httpClient.allowLocalLogoutUrls=true150
151
152 cas.slo.disabled=false153 cas.logout.followServiceRedirects=true154 cas.logout.removeDescendantTickets=true155 cas.slo.asynchronous=true
默认情况下cas会提供一个jdbc的验证方式,把sql写在application.properties,但这种方式无法提供返回的用户信息,因此需要定义验证处理器及配置信息
1 packagecn.bz.bzsso.authentication;2
3 importcn.bz.bzsso.entity.User;4 importcn.bz.bzsso.handler.MyAuthenticationHandler;5 importcn.bz.bzsso.mapper.UserMapper;6 importorg.apereo.cas.authentication.AuthenticationEventExecutionPlan;7 importorg.apereo.cas.authentication.AuthenticationEventExecutionPlanConfigurer;8 importorg.apereo.cas.authentication.AuthenticationHandler;9 importorg.apereo.cas.authentication.principal.DefaultPrincipalFactory;10 importorg.apereo.cas.configuration.CasConfigurationProperties;11 importorg.apereo.cas.services.ServicesManager;12 importorg.springframework.beans.factory.annotation.Autowired;13 importorg.springframework.beans.factory.annotation.Qualifier;14 importorg.springframework.boot.context.properties.EnableConfigurationProperties;15 importorg.springframework.context.annotation.Bean;16 importorg.springframework.context.annotation.Configuration;17
18 /**
19 *@authortele20 * @Description21 * @create 2019-12-0422 */
23 @Configuration("myAuthenticationConfiguration")24 @EnableConfigurationProperties(CasConfigurationProperties.class)25 public class MyAuthenticationConfiguration implementsAuthenticationEventExecutionPlanConfigurer {26
27 @Autowired28 privateCasConfigurationProperties casProperties;29
30 @Autowired31 @Qualifier("servicesManager")32 privateServicesManager servicesManager;33
34
35 /**
36 * 将自定义验证器注册为Bean37 *@return
38 */
39 @Bean40 publicAuthenticationHandler myAuthenticationHandler() {41 MyAuthenticationHandler handler = new MyAuthenticationHandler(MyAuthenticationHandler.class.getSimpleName(), servicesManager, new DefaultPrincipalFactory(), 1);42 returnhandler;43 }44
45 /**
46 * 注册验证器47 *@paramplan48 */
49 @Override50 public voidconfigureAuthenticationExecutionPlan(AuthenticationEventExecutionPlan plan) {51 plan.registerAuthenticationHandler(myAuthenticationHandler());52 }53 }
View Code
1 packagecn.bz.bzsso.handler;2
3 importcn.bz.bzsso.entity.LoginCode;4 importcn.bz.bzsso.entity.LoginStatus;5 importcn.bz.bzsso.entity.User;6 importcom.alibaba.fastjson.JSON;7 importcom.alibaba.fastjson.serializer.SerializerFeature;8 importorg.apereo.cas.authentication.AuthenticationHandlerExecutionResult;9 importorg.apereo.cas.authentication.PreventedException;10 importorg.apereo.cas.authentication.UsernamePasswordCredential;11 importorg.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;12 importorg.apereo.cas.authentication.principal.PrincipalFactory;13 importorg.apereo.cas.services.ServicesManager;14 importorg.springframework.jdbc.core.BeanPropertyRowMapper;15 importorg.springframework.jdbc.core.JdbcTemplate;16 importorg.springframework.jdbc.datasource.DriverManagerDataSource;17 importjava.security.GeneralSecurityException;18 importjava.util.ArrayList;19 importjava.util.HashMap;20 importjava.util.Map;21
22 /**
23 *@authortele24 * @Description25 * @create 2019-12-0426 */
27 public class MyAuthenticationHandler extendsAbstractUsernamePasswordAuthenticationHandler {28
29
30 publicMyAuthenticationHandler(String name, ServicesManager servicesManager, PrincipalFactory principalFactory, Integer order) {31 super(name, servicesManager, principalFactory, order);32 }33
34 @Override35 protected AuthenticationHandlerExecutionResult authenticateUsernamePasswordInternal(UsernamePasswordCredential credential, String originalPassword) throwsGeneralSecurityException, PreventedException {36 String username =credential.getUsername();37 String password =credential.getPassword();38
39
40 DriverManagerDataSource dataSource = newDriverManagerDataSource();41 dataSource.setDriverClassName("com.mysql.jdbc.Driver");42 dataSource.setUrl("xx");43 dataSource.setUsername("xx");44 dataSource.setPassword("xx");45
46 //创建JDBC模板
47 JdbcTemplate jdbcTemplate = newJdbcTemplate();48 jdbcTemplate.setDataSource(dataSource);49
50 String sql = "select id,username,nickname,password from tb_user where username = ?";51
52 User user = (User) jdbcTemplate.queryForObject(sql, new Object[]{username}, new BeanPropertyRowMapper(User.class));53
54 LoginStatus loginStatus = newLoginStatus();55 loginStatus.setId(user.getId());56 loginStatus.setUsername(user.getUserName());57 loginStatus.setNickname(user.getNickName());58
59 if(user.getPassword().equals(password)) {60 loginStatus.setCode(LoginCode.LOGIN_SUCCESS);61 loginStatus.setMessage(LoginCode.MSG_LOGIN_SUCCESS);62 }else{63 loginStatus.setCode(LoginCode.ERROR_OF_USER_PWD);64 loginStatus.setMessage(LoginCode.MSG_ERROR_OF_USER_PWD);65 }66
67 Map resultMap = new HashMap<>(4);68
69 resultMap.put("loginStatus", JSON.toJSONString(loginStatus,SerializerFeature.WriteNullStringAsEmpty));70
71 return createHandlerResult(credential, this.principalFactory.createPrincipal(credential.getUsername(),resultMap), new ArrayList<>(0));72
73 }74 }
View Code
修改MATA-INF下的spring.factoriesorg.springframework.boot.autoconfigure.EnableAutoConfiguration=xx.MyAuthenticationConfiguration
ok,服务端配置到此结束,你可以自定义返回的信息,状态码等
二.客户端接入
既然接入了cas,那么所有的客户端都应该关闭登录与退出接口,扒了下官网,看到一句话大概意思是cas不是一个session管理器,每个应用应当对自己的session负责,cas只会在退出时给接入的应用发通知,然后移除内部维护的tgt对象
,换句话说,每个应用内部应当调用session.invalidate()来销毁各自的session
1.传统web项目接入.这种指的是带有web.xml的web
加入cas-client 版本3.5.1依赖
1
2
3 org.jasig.cas.client
4 cas-client-core
5 ${cas-client.version}
6
7
8
9 org.jasig.cas.client
10 cas-client-integration-tomcat-common
11 ${cas-client.version}
12
在web.xml中加入如下配置,本机环境不建议使用localhost,使用127.0.0.1(5.1版本使用localhost会有退出失效无法通信的问题,浏览器存储cookie时127.0.0.1和localhost是两个不同的文件夹)
servername指的是客户端地址
1
2 org.jasig.cas.client.session.SingleSignOutHttpSessionListener
3
4
5
6
7
8 CAS Single Sign Out Filter
9 org.jasig.cas.client.session.SingleSignOutFilter
10
11 casServerUrlPrefix
12 http://127.0.0.1:8090/cas/
13
14
15
16 CAS Single Sign Out Filter
17 /*18 19
20
21
22 23 24 CAS Authentication Filter25 org.jasig.cas.client.authentication.AuthenticationFilter26 27 casServerLoginUrl28 http://127.0.0.1:8090/cas/login29 30 31 serverName32 33 http://127.0.0.1:808034 35 36 37 CAS Authentication Filter38 /*39 40
41
42 43 44 CAS Validation Filter45 org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter46 47 casServerUrlPrefix48 http://127.0.0.1:8090/cas/49 50 51 serverName52 http://127.0.0.1:808053 54 55 redirectAfterValidation56 true57 58 59 useSession60 true61 62 63 authn_method64 mfa-duo65 66 67 68 CAS Validation Filter69 /*70 71
72 73 74 CASAssertion Thread LocalFilter75 org.jasig.cas.client.util.AssertionThreadLocalFilter76 77 78 CASAssertion Thread LocalFilter79 /*80 81
82
83 84 85 CAS HttpServletRequest Wrapper Filter86 org.jasig.cas.client.util.HttpServletRequestWrapperFilter87 88
89 90 CAS HttpServletRequest Wrapper Filter91 /*92
客户端获得cas返回的登录信息的api,或者使用AssertionHolder.getAssertion().getPrincipal().getAttributes("xx");,严谨一点可以先判空,避免NPE
1 @RequestMapping("/login")2 @ResponseBody3 publicString login() {4 AttributePrincipal userPrincipal =(AttributePrincipal)request.getUserPrincipal();5 return userPrincipal.getAttributes().get("loginStatus").toString();6 }
下面讲下退出
@RequestMapping(value = "logout")public String logout(HttpSession session) throwsInterruptedException {
session.invalidate();return "redirect:" +CASConstant.LOGOUT_URL;
}
我在做的时候发现退出请求总是无法触发,后来发现是项目中有拦截器,于是加了一个excluedUrl,然后在对应的拦截器init的时候filterConfig.getInitParameter("excludedUrl");接下来dofilter时判断如果含有该路径重定向即可,但这样实际相当于重定向两次
还有一个问题是上面redirect的地址如果需要spring静态注入,(当然写死可以),在applicationContext.xml中引入对应的url.properties,然后需要注入的常量类提供set方法即可,需要注意的是spring的注入是基于对象的.所以该set方法不能有static
2.springboot 项目接入cas.springboot内置tomcat,不再需要加入tomcat
pom.xml
1
2 1.8
3 3.5.1
4
5
6
7
8
9
10 org.jasig.cas.client
11 cas-client-core
12 ${cas.client.version}
13
14
15
16
17 org.springframework.boot
18 spring-boot-devtools
19 true
20
21
22
23 org.springframework.boot
24 spring-boot-configuration-processor
25
26
27
28
29 org.springframework.boot
30 spring-boot-starter-web
31
32
33
34 org.springframework.boot
35 spring-boot-autoconfigure
36 2.2.0.RELEASE
37
38
39
40 org.mybatis.spring.boot
41 mybatis-spring-boot-starter
42 2.1.1
43
44
45
46 mysql
47 mysql-connector-java
48 runtime
49
50
51
52 com.alibaba
53 druid
54 1.1.10
55
56
57
58 org.projectlombok
59 lombok
60 true
61
62
63 org.springframework.boot
64 spring-boot-starter-test
65 test
66
67
68 org.junit.vintage
69 junit-vintage-engine
70
71
72
73
View Code
在你的application.properties加入如下配置,依然建议使用127.0.0.1
1 # 监听退出的接口,即所有接口都会进行监听2 spring.cas.sign-out-filters=/*
3 # 需要拦截的认证的接口4 spring.cas.auth-filters=/*5 spring.cas.validate-filters=/*6 spring.cas.request-wrapper-filters=/*7 spring.cas.assertion-filters=/*8 # 表示忽略拦截的接口,也就是不用进行拦截9 spring.cas.ignore-filters=/test10 spring.cas.cas-server-login-url=http://127.0.0.1:8090/cas/login11 spring.cas.cas-server-url-prefix=http://127.0.0.1:8090/cas/12 spring.cas.redirect-after-validation=true13 spring.cas.use-session=true14 spring.cas.redirectAfterValidation=true15 # 客户端地址16 spring.cas.server-name=http://127.0.0.1:8081
下面要注入之前在web.xml中配置的各种拦截器
代码与参考的博客类似,做了些修改,@ConfigurationProperties依赖spring-boot-configuration-processor
1 @Configuration2 public classCasCustomConfig {3 @Autowired4 SpringCasAutoconfig autoconfig;5
6 private static boolean casEnabled = true;7
8 publicCasCustomConfig() {9 }10
11 @Bean12 publicSpringCasAutoconfig getSpringCasAutoconfig() {13 return newSpringCasAutoconfig();14 }15
16 @Bean17 public ServletListenerRegistrationBeansingleSignOutHttpSessionListener() {18 ServletListenerRegistrationBean listener = new ServletListenerRegistrationBean();19 listener.setEnabled(casEnabled);20 listener.setListener(newSingleSignOutHttpSessionListener());21 listener.setOrder(1);22 returnlistener;23 }24
25
26
27 /**
28 * 该过滤器用于实现单点登出功能,单点退出配置,一定要放在其他filter之前29 *@return
30 */
31 @Bean32 publicFilterRegistrationBean singleSignOutFilter() {33 FilterRegistrationBean filterRegistration = newFilterRegistrationBean();34 filterRegistration.setFilter(newSingleSignOutFilter());35 filterRegistration.setEnabled(casEnabled);36 if (autoconfig.getSignOutFilters().size() > 0) {37 filterRegistration.setUrlPatterns(autoconfig.getSignOutFilters());38 } else{39 filterRegistration.addUrlPatterns("/*");40 }41 filterRegistration.addInitParameter("casServerUrlPrefix", autoconfig.getCasServerUrlPrefix());42 filterRegistration.addInitParameter("serverName",autoconfig.getServerName());43 filterRegistration.setOrder(1);44 returnfilterRegistration;45 }46
47
48 /**
49 * 该过滤器负责用户的认证工作50 *51 *@return
52 */
53 @Bean54 publicFilterRegistrationBean authenticationFilter() {55 FilterRegistrationBean filterRegistration = newFilterRegistrationBean();56 filterRegistration.setFilter(newAuthenticationFilter());57 filterRegistration.setEnabled(casEnabled);58 if (autoconfig.getAuthFilters().size() > 0) {59 filterRegistration.setUrlPatterns(autoconfig.getAuthFilters());60 } else{61 filterRegistration.addUrlPatterns("/*");62 }63 if (autoconfig.getIgnoreFilters() != null) {64 filterRegistration.addInitParameter("ignorePattern", autoconfig.getIgnoreFilters());65 }66 filterRegistration.addInitParameter("casServerLoginUrl", autoconfig.getCasServerLoginUrl());67 filterRegistration.addInitParameter("serverName", autoconfig.getServerName());68 //filterRegistration.addInitParameter("useSession", autoconfig.isUseSession() ? "true" : "false");69 //filterRegistration.addInitParameter("redirectAfterValidation", autoconfig.isRedirectAfterValidation() ? "true" : "false");
70 filterRegistration.setOrder(2);71 returnfilterRegistration;72 }73
74 /**
75 * 该过滤器负责对Ticket的校验工作,使用CAS 3.0协议76 *77 *@return
78 */
79 @Bean80 publicFilterRegistrationBean cas30ProxyReceivingTicketValidationFilter() {81 FilterRegistrationBean filterRegistration = newFilterRegistrationBean();82 filterRegistration.setFilter(newCas30ProxyReceivingTicketValidationFilter());83 filterRegistration.setEnabled(casEnabled);84 if (autoconfig.getValidateFilters().size() > 0) {85 filterRegistration.setUrlPatterns(autoconfig.getValidateFilters());86 } else{87 filterRegistration.addUrlPatterns("/*");88 }89 filterRegistration.addInitParameter("casServerUrlPrefix", autoconfig.getCasServerUrlPrefix());90 filterRegistration.addInitParameter("serverName", autoconfig.getServerName());91 filterRegistration.addInitParameter("useSession", autoconfig.isUseSession() ? "true" : "false");92 filterRegistration.addInitParameter("redirectAfterValidation", autoconfig.isRedirectAfterValidation() ? "true" : "false");93 filterRegistration.addInitParameter("authn_method", "mfa-duo");94 filterRegistration.setOrder(3);95 returnfilterRegistration;96 }97
98
99 /**
100 * 该过滤器使得可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。101 * 比如AssertionHolder.getAssertion().getPrincipal().getName()。102 * 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息103 *104 *@return
105 */
106 @Bean107 publicFilterRegistrationBean assertionThreadLocalFilter() {108 FilterRegistrationBean filterRegistration = newFilterRegistrationBean();109 filterRegistration.setFilter(newAssertionThreadLocalFilter());110 filterRegistration.setEnabled(true);111 if (autoconfig.getAssertionFilters().size() > 0) {112 filterRegistration.setUrlPatterns(autoconfig.getAssertionFilters());113 } else{114 filterRegistration.addUrlPatterns("/*");115 }116 filterRegistration.setOrder(4);117 returnfilterRegistration;118 }119
120
121 @Bean122 publicFilterRegistrationBean httpServletRequestWrapperFilter() {123 FilterRegistrationBean filterRegistration = newFilterRegistrationBean();124 filterRegistration.setFilter(newHttpServletRequestWrapperFilter());125 filterRegistration.setEnabled(true);126 if (autoconfig.getRequestWrapperFilters().size() > 0) {127 filterRegistration.setUrlPatterns(autoconfig.getRequestWrapperFilters());128 } else{129 filterRegistration.addUrlPatterns("/*");130 }131 filterRegistration.setOrder(5);132 returnfilterRegistration;133 }134 }
View Code
1 @ConfigurationProperties(prefix = "spring.cas")2 public classSpringCasAutoconfig {3
4 static final String separator = ",";5
6 privateString validateFilters;7 privateString signOutFilters;8 privateString authFilters;9 privateString assertionFilters;10 privateString requestWrapperFilters;11 private String ignoreFilters; //需要放行的url,多个可以使用|分隔,遵循正则
12
13 privateString casServerUrlPrefix;14 privateString casServerLoginUrl;15 privateString serverName;16 private boolean useSession = true;17 private boolean redirectAfterValidation = true;18
19 publicString getIgnoreFilters() {20 returnignoreFilters;21 }22
23 public voidsetIgnoreFilters(String ignoreFilters) {24 this.ignoreFilters =ignoreFilters;25 }26
27 public ListgetValidateFilters() {28 returnArrays.asList(validateFilters.split(separator));29 }30
31 public voidsetValidateFilters(String validateFilters) {32 this.validateFilters =validateFilters;33 }34
35 public ListgetSignOutFilters() {36 returnArrays.asList(signOutFilters.split(separator));37 }38
39 public voidsetSignOutFilters(String signOutFilters) {40 this.signOutFilters =signOutFilters;41 }42
43 public ListgetAuthFilters() {44 returnArrays.asList(authFilters.split(separator));45 }46
47 public voidsetAuthFilters(String authFilters) {48 this.authFilters =authFilters;49 }50
51 public ListgetAssertionFilters() {52 returnArrays.asList(assertionFilters.split(separator));53 }54
55 public voidsetAssertionFilters(String assertionFilters) {56 this.assertionFilters =assertionFilters;57 }58
59 public ListgetRequestWrapperFilters() {60 returnArrays.asList(requestWrapperFilters.split(separator));61 }62
63 public voidsetRequestWrapperFilters(String requestWrapperFilters) {64 this.requestWrapperFilters =requestWrapperFilters;65 }66
67 publicString getCasServerUrlPrefix() {68 returncasServerUrlPrefix;69 }70
71 public voidsetCasServerUrlPrefix(String casServerUrlPrefix) {72 this.casServerUrlPrefix =casServerUrlPrefix;73 }74
75 publicString getCasServerLoginUrl() {76 returncasServerLoginUrl;77 }78
79 public voidsetCasServerLoginUrl(String casServerLoginUrl) {80 this.casServerLoginUrl =casServerLoginUrl;81 }82
83 publicString getServerName() {84 returnserverName;85 }86
87 public voidsetServerName(String serverName) {88 this.serverName =serverName;89 }90
91 public booleanisRedirectAfterValidation() {92 returnredirectAfterValidation;93 }94
95 public void setRedirectAfterValidation(booleanredirectAfterValidation) {96 this.redirectAfterValidation =redirectAfterValidation;97 }98
99 public booleanisUseSession() {100 returnuseSession;101 }102
103 public void setUseSession(booleanuseSession) {104 this.useSession =useSession;105 }106 }
View Code
接下来时登录和登出,不要直接丢个@RestController就完事了,这个主解会让redirect失效,当成字符串转成json返回了,最好的方式是使用@Controller,需要转json的加上@ResponseBody
1 @Controller2 public classLoginController {3
4 @Autowired5 privateUserMapper userMapper;6
7 @Autowired8 privateHttpServletRequest request;9
10 @RequestMapping("/login")11 @ResponseBody12 publicString login() {13 AttributePrincipal userPrincipal =(AttributePrincipal)request.getUserPrincipal();14 return userPrincipal.getAttributes().get("loginStatus").toString();15 }16
17 @RequestMapping("/logout")18 publicString logout(HttpSession session) {19 session.removeAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);20 session.invalidate();21 return "redirect:http://127.0.0.1:8090/cas/logout?service=http://127.0.0.1:8081/spring_boot/login/";22 }23
24 private voidprintln(Object object) {25 System.out.println(object);26 }27 }
三.验证
三.关于源码
源码看了下客户端的拦截器与处理器,大概流程如下,在浏览器输入http://127.0.0.1:8081/spring_boot/login/会被重定向到http://127.0.0.1:8090/cas/login?service=http://127.0.0.1:8081/spring_boot/login/,也就是cas的登录页,点击登录之后,cas server进行验证,之后会进入客户端的拦截器SingleSignOutFilter,拦截器判断请求类型,如果是tokenrequest(带token的请求),保存session和st,如果是登出请求,将st,session从map中移除,在destroySession中session.invalidate(),但是其他接入的客户端并没有销毁session,退出时,cas只会给接入的客户端发通知,当然从哪个客户端发起的退出该客户端的session会被destroy,但其他客户端要在登出接口中session.invalidate(),