詳解Spring Boot 使用Spring security 集成CAS
1.創(chuàng)建工程
創(chuàng)建Maven工程:springboot-security-cas
2.加入依賴
創(chuàng)建工程后,打開(kāi)pom.xml,在pom.xml中加入以下內(nèi)容:
<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 對(duì)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.創(chuàng)建application.properties
創(chuàng)建application.properties文件,加入以下內(nèi)容:
#CAS服務(wù)地址
cas.server.host.url=http://localhost:8081/cas
#CAS服務(wù)登錄地址
cas.server.host.login_url=${cas.server.host.url}/login
#CAS服務(wù)登出地址
cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}
#應(yīng)用訪問(wèn)地址
app.server.host.url=http://localhost:8080
#應(yīng)用登錄地址
app.login.url=/login
#應(yīng)用登出地址
app.logout.url=/logout
4.創(chuàng)建入口啟動(dòng)類(MainConfig)
創(chuàng)建入口啟動(dòng)類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 "訪問(wèn)了首頁(yè)哦";
}
@RequestMapping("/hello")
public String hello() {
return "不驗(yàn)證哦";
}
@PreAuthorize("hasAuthority('TEST')")//有TEST權(quán)限的才能訪問(wèn)
@RequestMapping("/security")
public String security() {
return "hello world security";
}
@PreAuthorize("hasAuthority('ADMIN')")//必須要有ADMIN權(quán)限的才能訪問(wèn)
@RequestMapping("/authorize")
public String authorize() {
return "有權(quán)限訪問(wèn)";
}
/**這里注意的是,TEST與ADMIN只是權(quán)限編碼,可以自己定義一套規(guī)則,根據(jù)實(shí)際情況即可*/
}
5.創(chuàng)建Security配置類(SecurityConfig)
創(chuàng)建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 org.springframework.context.annotation.Bean;
import org.springframework.context.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.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.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權(quán)限
@EnableGlobalMethodSecurity(prePostEnabled = true) //啟用方法驗(yàn)證
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CasProperties casProperties;
/**定義認(rèn)證用戶信息獲取來(lái)源,密碼校驗(yàn)規(guī)則等*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(casAuthenticationProvider());
//inMemoryAuthentication 從內(nèi)存中獲取
//auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")
//.and().withUser("admin").password("123456").roles("ADMIN");
//jdbcAuthentication從數(shù)據(jù)庫(kù)中獲取,但是默認(rèn)是以security提供的表結(jié)構(gòu)
//usersByUsernameQuery 指定查詢用戶SQL
//authoritiesByUsernameQuery 指定查詢權(quán)限SQL
//auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);
//注入userDetailsService,需要實(shí)現(xiàn)userDetailsService接口
//auth.userDetailsService(userDetailsService);
}
/**定義安全策略*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()//配置安全策略
//.antMatchers("/","/hello").permitAll()//定義/請(qǐng)求不需要驗(yàn)證
.anyRequest().authenticated()//其余的所有請(qǐng)求都需要驗(yàn)證
.and()
.logout()
.permitAll()//定義logout不需要驗(yàn)證
.and()
.formLogin();//使用form表單登錄
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
//http.csrf().disable(); //禁用CSRF
}
/**認(rèn)證的入口*/
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
/**指定service相關(guān)信息*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
/**CAS認(rèn)證過(guò)濾器*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
return casAuthenticationFilter;
}
/**cas 認(rèn)證 Provider*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
//casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //這里只是接口類型,實(shí)現(xiàn)的接口不一樣,都可以的。
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 Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
}
/**單點(diǎn)登出過(guò)濾器*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
/**請(qǐng)求單點(diǎn)退出過(guò)濾器*/
@Bean
public LogoutFilter casLogoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());
return logoutFilter;
}
}
6.用戶自定義類
(1)定義CasProperties,用于將properties文件指定的內(nèi)容注入以方便使用,這里不注入也是可以的,可以獲取Spring 當(dāng)前的環(huán)境,代碼如下:
package com.chengli.springboot.properties;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* CAS的配置參數(shù)
* @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.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
/**
* 用于加載用戶信息 實(shí)現(xiàn)UserDetailsService接口,或者實(shí)現(xiàn)AuthenticationUserDetailsService接口
* @author ChengLi
*
*/
public class CustomUserDetailsService /*
//實(shí)現(xiàn)UserDetailsService接口,實(shí)現(xiàn)loadUserByUsername方法
implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("當(dāng)前的用戶名是:"+username);
//這里我為了方便,就直接返回一個(gè)用戶信息,實(shí)際當(dāng)中這里修改為查詢數(shù)據(jù)庫(kù)或者調(diào)用服務(wù)什么的來(lái)獲取用戶信息
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;
}*/
//實(shí)現(xiàn)AuthenticationUserDetailsService,實(shí)現(xiàn)loadUserDetails方法
implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {
@Override
public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
System.out.println("當(dāng)前的用戶名是:"+token.getName());
/*這里我為了方便,就直接返回一個(gè)用戶信息,實(shí)際當(dāng)中這里修改為查詢數(shù)據(jù)庫(kù)或者調(diào)用服務(wù)什么的來(lái)獲取用戶信息*/
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類,用于加載當(dāng)前登錄用戶的權(quán)限信息,實(shí)現(xiàn)GrantedAuthority接口,代碼如下:
package com.chengli.springboot.custom;
import org.springframework.security.core.GrantedAuthority;
/**
* 權(quán)限信息
*
* @author ChengLi
*
*/
public class AuthorityInfo implements GrantedAuthority {
private static final long serialVersionUID = -175781100474818800L;
/**
* 權(quán)限CODE
*/
private String authority;
public AuthorityInfo(String authority) {
this.authority = authority;
}
@Override
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
}
(4)定義UserInfo類,用于加載當(dāng)前用戶信息,實(shí)現(xiàn)UserDetails接口,代碼如下:
package com.chengli.springboot.custom;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
/**
* 用戶信息
* @、這里我寫了幾個(gè)較為常用的字段,id,name,username,password,可以根據(jù)實(shí)際的情況自己增加
* @author ChengLi
*
*/
public class UserInfo implements UserDetails {
private static final long serialVersionUID = -1041327031937199938L;
/**
* 用戶ID
*/
private Long id;
/**
* 用戶名稱
*/
private String name;
/**
* 登錄名稱
*/
private String username;
/**
* 登錄密碼
*/
private String password;
private boolean isAccountNonExpired = true;
private boolean isAccountNonLocked = true;
private boolean isCredentialsNonExpired = true;
private boolean isEnabled = true;
private Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();
....省略getters setters 方法
}
到這里基本就已經(jīng)完成了,運(yùn)行CAS Server ,將以上的application.properties文件中的地址修改為實(shí)際的地址即可運(yùn)行。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java數(shù)組的遍歷與求和知識(shí)點(diǎn)
本篇文章給大家總計(jì)了Java數(shù)組的遍歷與求和的知識(shí)點(diǎn)以及需要注意的地方,需要的朋友參考學(xué)習(xí)下。2018-02-02
log4j升級(jí)log4j2遇到的問(wèn)題及解決方式
這篇文章主要介紹了log4j升級(jí)log4j2遇到的問(wèn)題及解決方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12
Java Web項(xiàng)目中實(shí)現(xiàn)文件下載功能的實(shí)例教程
這篇文章主要介紹了Java Web項(xiàng)目中實(shí)現(xiàn)文件下載功能的實(shí)例教程,分別講解了通過(guò)超鏈接實(shí)現(xiàn)下載以及通過(guò)Servlet程序?qū)崿F(xiàn)下載的方式,需要的朋友可以參考下2016-05-05
spring security數(shù)據(jù)庫(kù)表結(jié)構(gòu)實(shí)例代碼
這篇文章主要介紹了spring security數(shù)據(jù)庫(kù)表結(jié)構(gòu)實(shí)例代碼,需要的朋友可以參考下2017-09-09
如何解決IDEA中JSP頁(yè)面部分出現(xiàn)綠色背景色問(wèn)題
這篇文章主要介紹了如何解決IDEA中JSP頁(yè)面部分出現(xiàn)綠色背景色問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12
Java中數(shù)組和List的互相轉(zhuǎn)換問(wèn)題小結(jié)
這篇文章主要介紹了Java中數(shù)組和List的互相轉(zhuǎn)換問(wèn)題小結(jié),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2024-03-03
Java實(shí)戰(zhàn)花店商城系統(tǒng)的實(shí)現(xiàn)流程
只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+Springboot+Maven+mybatis+Vue+Mysql實(shí)現(xiàn)一個(gè)花店商城系統(tǒng),大家可以在過(guò)程中查缺補(bǔ)漏,提升水平2022-01-01
Java并發(fā)之原子性 有序性 可見(jiàn)性及Happen Before原則
一提到happens-before原則,就讓人有點(diǎn)“丈二和尚摸不著頭腦”。這個(gè)涵蓋了整個(gè)JMM中可見(jiàn)性原則的規(guī)則,究竟如何理解,把我個(gè)人一些理解記錄下來(lái)。下面可以和小編一起學(xué)習(xí)Java 并發(fā)四個(gè)原則2021-09-09
基于Comparator對(duì)象集合實(shí)現(xiàn)多個(gè)條件按照優(yōu)先級(jí)的比較
這篇文章主要介紹了基于Comparator對(duì)象集合實(shí)現(xiàn)多個(gè)條件按照優(yōu)先級(jí)的比較,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07

