[TOC]

Java应用对接CAS服务端

首先你得在 CAS_SERVER 中添加一个应用,你需要你提供你的 services 值,这通常是 cas_server认证成功后请求你的地址(回调地址)。

一、spring security对接

1、引入 spring-security , spring-security-cas 包

1
2
3
4
5
6
7
8
9
10
11
		
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<!--cas的客户端 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>

2、编写 CasProperties配置文件类。

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
/**
* Cas配置文件
* @author xia17
* @date 2020/4/13 11:46
*/
@Data
@ConfigurationProperties(prefix = "cas")
@Configuration
public class CasProperties {

/**
* cas授权URL
*/
private String serverHost;

/** 登录 **/
private String serverLogin;

/** 登出 **/
private String serverLogout;

/** cas加密盐 */
private String salt;

/** appHost */
private String serviceHost;

/** app登录地址 */
private String serviceLogin;

/** app登出 */
private String serviceLogout;

/** 获取登录界面URL */
public String getCasLoginPageUrl() {
return this.serverLogin + "?service=" + this.getServiceHost() + this.getServiceLogin();
}
}

3、新建CAS_SERVER返回的用户信息实体类

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
/**
* cas登录过来的用户
* @author xia17
* @date 2020/8/31 16:12
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class CasUser implements UserDetails {


private String username;

private String pwd;

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.stream(new String[]{"ss"})
.map(SimpleGrantedAuthority::new)
.collect(Collectors.toSet());
}

@Override
public String getPassword() {
return this.pwd;
}

@Override
public String getUsername() {
return this.username;
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}
}

4、编写 CasAssertionUserDetailsService 实现从casServer返回的用户信息转换为本项目的用户信息类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 实现从casServer返回的用户信息转换为本项目的用户信息类
* @author xia17
* @date 2021/6/30 14:25
*/
public class CasAssertionUserDetailsService extends AbstractCasAssertionUserDetailsService {


@Override
protected UserDetails loadUserDetails(Assertion assertion) {
String username = assertion.getPrincipal().getName();
// 下面可获取到其他属性
Map<String, Object> attributes = assertion.getPrincipal().getAttributes();
return new CasUser(username,"123456");
}

}

5、编写 CasAuthenticationSuccessHandler , cas认证成功后进行的操作。

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
/**
* CAS 认证生成JWT Token ,并重定向到前端
* @author xia17
* @date 2020/7/16
*/
@Component
@RequiredArgsConstructor
@Slf4j
public class CasAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

private final TokenProvider tokenProvider;
private final TokenCode tokenCode;
private final GlobalProperties globalProperties;


/**
* CAS认证成功后执行的操作
* @param request 请求
* @param response 响应
* @param authentication 认证信息
* @throws IOException /
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
// 获取用户名(学工号)
log.info("OA[CAS]登录:::{}",authentication.getName());
// 创建Token
String token = tokenProvider.createToken(authentication);
String tokenCode = this.tokenCode.saveTokenAndGenerateCode(token);
response.sendRedirect(getHtmlCodeUrl(request) + tokenCode);
}

/**
* 获取前端接收code的地址
* @param request 请求信息
* @return /
*/
public String getHtmlCodeUrl(HttpServletRequest request){
// 是否是移动端访问
boolean isMobile = UserAgentUtil.parse(request.getHeader("User-Agent")).isMobile();
if (isMobile){
return globalProperties.getPhoneHtmlHref();
}else {
return globalProperties.getPcHtmlHref();
}
}

}

6、注入cas相关的bean

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
/**指定service相关信息*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casProperties.getServiceHost() + casProperties.getServiceLogin());
serviceProperties.setAuthenticateAllArtifacts(false);
serviceProperties.setSendRenew(false);
return serviceProperties;
}

/**认证的入口*/
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getServerLogin());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}


/**CAS认证过滤器*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl(casProperties.getServiceLogin());
// CAS登录成功的处理方法
casAuthenticationFilter.setAuthenticationSuccessHandler(casAuthenticationSuccessHandler);
return casAuthenticationFilter;
}

/**cas 认证 Provider*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setAuthenticationUserDetailsService(new CasAssertionUserDetailsService());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
return casAuthenticationProvider;
}


@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getServerHost());
}

/**单点登出过滤器*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
// singleSignOutFilter.setCasServerUrlPrefix(casProperties.getServerHost());
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}

/**请求单点退出过滤器*/
@Bean
public LogoutFilter casLogoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(casProperties.getServerLogout(), new SecurityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl(casProperties.getServiceLogout());
return logoutFilter;
}

7、在security的配置文件加入 cas 相关的三个过滤器

1
2
3
4
5
httpSecurity
// 添加cas认证
.addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class)

注意:好需要将认证相关的路由放开权限验证(不登录即可访问)

8、填写 application中的cas配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
cas:
# cas服务端地址
server-host: http://192.168.1.30:8080/cas
# cas服务端登录地址
server-login: ${cas.server-host}/login
# cas 服务端退出地址
server-logout: ${cas.server-host}/logout
# 客户端地址
service-host: http://192.168.1.30:8010
# 客户端回调路由
service-login: /cas/login
# 客户端退出登录路由
service-logout: /cas/logout