详解SpringBoot使⽤Springsecurity集成CAS 1.创建⼯程
创建Maven⼯程:springboot-security-cas
2.加⼊依赖
创建⼯程后,打开l,在l中加⼊以下内容:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.3.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- security starter Poms -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- security 对CAS⽀持 -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
</dependency>
<!-- security taglibs -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<!-- 热加载 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
3.创建application.properties
创建application.properties⽂件,加⼊以下内容:
#CAS服务地址
cas.server.host.url=localhost:8081/cas
#CAS服务登录地址
cas.server.host.login_url=${cas.server.host.url}/login
#CAS服务登出地址
cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}
#应⽤访问地址
app.server.host.url=localhost:8080
#应⽤登录地址
app.login.url=/login
#应⽤登出地址
app.logout.url=/logout
4.创建⼊⼝启动类(MainConfig)
创建⼊⼝启动类MainConfig,完整代码如下:
package com.chengli.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@SpringBootApplication
public class MainConfig {
public static void main(String[] args) {
SpringApplication.run(MainConfig.class, args);
}
@RequestMapping("/")
public String index() {
return "访问了⾸页哦";
}
@RequestMapping("/hello")
public String hello() {
return "不验证哦";
}
@PreAuthorize("hasAuthority('TEST')")//有TEST权限的才能访问
@RequestMapping("/security")
public String security() {
return "hello world security";
}
@PreAuthorize("hasAuthority('ADMIN')")//必须要有ADMIN权限的才能访问
@RequestMapping("/authorize")
public String authorize() {
return "有权限访问";
}
/**这⾥注意的是,TEST与ADMIN只是权限编码,可以⾃⼰定义⼀套规则,根据实际情况即可*/
}
5.创建Security配置类(SecurityConfig)
创建Security配置类SecurityConfig,完整代码如下:
package com.chengli.springboot.security;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import t.annotation.Bean;
import t.annotation.Configuration;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.fig.annotation.authentication.builders.AuthenticationManagerBuilder; import org.figuration.EnableGlobalMethodSecurity; import org.fig.annotation.web.builders.HttpSecurity;
import org.fig.figuration.EnableWebSecurity;
import org.fig.figuration.WebSecurityConfigurerAdapter; import org.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import com.chengli.springboot.custom.CustomUserDetailsService;
import com.chengli.springboot.properties.CasProperties;
@Configuration
@EnableWebSecurity //启⽤web权限
@EnableGlobalMethodSecurity(prePostEnabled = true) //启⽤⽅法验证
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CasProperties casProperties;
/**定义认证⽤户信息获取来源,密码校验规则等*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
//inMemoryAuthentication 从内存中获取
//auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")
//.and().withUser("admin").password("123456").roles("ADMIN");
//jdbcAuthentication从数据库中获取,但是默认是以security提供的表结构
/
/usersByUsernameQuery 指定查询⽤户SQL
//authoritiesByUsernameQuery 指定查询权限SQL
//auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);    //注⼊userDetailsService,需要实现userDetailsService接⼝
//auth.userDetailsService(userDetailsService);
}
/**定义安全策略*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//配置安全策略
//.antMatchers("/","/hello").permitAll()//定义/请求不需要验证
.anyRequest().authenticated()//其余的所有请求都需要验证
.and()
.logout()
.permitAll()//定义logout不需要验证
.and()
.formLogin();//使⽤form表单登录springcloud和springboot
.and()
.addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
//http.csrf().disable(); //禁⽤CSRF
}
/**认证的⼊⼝*/
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.CasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
/**指定service相关信息*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.AppServerUrl() + AppLoginUrl());
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
/**CAS认证过滤器*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.AppLoginUrl());
return casAuthenticationFilter;
}
/**cas 认证 Provider*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
//casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这⾥只是接⼝类型,实现的接⼝不⼀样,都可以的。
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
return casAuthenticationProvider;
}
/*@Bean
public UserDetailsService customUserDetailsService(){
return new CustomUserDetailsService();
}*/
/**⽤户⾃定义的AuthenticationUserDetailsService*/
@Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){
return new CustomUserDetailsService();
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new CasServerUrl());
}
/**单点登出过滤器*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.CasServerUrl());
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
/**请求单点退出过滤器*/
@Bean
public LogoutFilter casLogoutFilter() {
LogoutFilter logoutFilter = new CasServerLogoutUrl(), new SecurityContextLogoutHandler());
logoutFilter.AppLogoutUrl());
return logoutFilter;
}
}
6.⽤户⾃定义类
(1)定义CasProperties,⽤于将properties⽂件指定的内容注⼊以⽅便使⽤,这⾥不注⼊也是可以的,可以获取Spring 当前的环境,代码如下:
package com.chengli.springboot.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* CAS的配置参数
* @author ChengLi
*/
@Component
public class CasProperties {
@Value("${cas.server.host.url}")
private String casServerUrl;
@Value("${cas.server.host.login_url}")
private String casServerLoginUrl;
@Value("${cas.server.host.logout_url}")
private String casServerLogoutUrl;
@Value("${app.server.host.url}")
private String appServerUrl;
@Value("${app.login.url}")
private String appLoginUrl;
@Value("${app.logout.url}")
private String appLogoutUrl;
.
.....省略 getters setters ⽅法
}
(2)定义CustomUserDetailsService类,代码如下:
package com.chengli.springboot.custom;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.userdetails.AuthenticationUserDetailsService;
import org.userdetails.UserDetails;
import org.userdetails.UsernameNotFoundException;
/**
* ⽤于加载⽤户信息实现UserDetailsService接⼝,或者实现AuthenticationUserDetailsService接⼝
* @author ChengLi
*
*/
public class CustomUserDetailsService /*
//实现UserDetailsService接⼝,实现loadUserByUsername⽅法
implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("当前的⽤户名是:"+username);
//这⾥我为了⽅便,就直接返回⼀个⽤户信息,实际当中这⾥修改为查询数据库或者调⽤服务什么的来获取⽤户信息
UserInfo userInfo = new UserInfo();
userInfo.setUsername("admin");
userInfo.setName("admin");
Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
AuthorityInfo authorityInfo = new AuthorityInfo("TEST");
authorities.add(authorityInfo);
userInfo.setAuthorities(authorities);
return userInfo;
}*/
//实现AuthenticationUserDetailsService,实现loadUserDetails⽅法
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
System.out.println("当前的⽤户名是:"+Name());
/*这⾥我为了⽅便,就直接返回⼀个⽤户信息,实际当中这⾥修改为查询数据库或者调⽤服务什么的来获取⽤户信息*/
UserInfo userInfo = new UserInfo();
userInfo.setUsername("admin");
userInfo.setName("admin");
Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
AuthorityInfo authorityInfo = new AuthorityInfo("TEST");
authorities.add(authorityInfo);
userInfo.setAuthorities(authorities);
return userInfo;
}
}
(3)定义AuthorityInfo类,⽤于加载当前登录⽤户的权限信息,实现GrantedAuthority接⼝,代码如下:package com.chengli.springboot.custom;
import org.GrantedAuthority;
/**
* 权限信息
*
* @author ChengLi
*