日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢(xún)
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷(xiāo)解決方案
SpringSecurity系列之SpringBoot+CAS單點(diǎn)登錄

 [[408875]]

1.準(zhǔn)備工作

準(zhǔn)備工作主要做兩件事。

成都創(chuàng)新互聯(lián)自2013年創(chuàng)立以來(lái),先為阿巴嘎等服務(wù)建站,阿巴嘎等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為阿巴嘎企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。

1.1 服務(wù)記錄

某一個(gè) Client 需要接入 CAS Server 進(jìn)行驗(yàn)證,則該 Client 必須提前在 CAS Server 上配置其信息。

這個(gè)信息既可以動(dòng)態(tài)添加,也可以通過(guò) JSON 來(lái)配置,后面松哥會(huì)教搭建如何動(dòng)態(tài)添加,這里方便起見(jiàn),我們還是通過(guò) JSON 來(lái)進(jìn)行配置。

具體配置方式如下,在 CAS Server 中創(chuàng)建如下目錄:

 
 
 
 
  1. src/main/resources/services 

在該目錄下創(chuàng)建一個(gè)名為 client1-99.json 的文件,client1 表示要接入的 client 的名字,99 表示要接入的 client 的 id,json 文件內(nèi)容如下(這個(gè)配置可以參考官方給出的模版:overlays/org.apereo.cas.cas-server-webapp-tomcat-5.3.14/WEB-INF/classes/services/Apereo-10000002.json):

 
 
 
 
  1.   "@class": "org.apereo.cas.services.RegexRegisteredService", 
  2.   "serviceId": "^(https|http)://.*", 
  3.   "name": "client1", 
  4.   "id": 99, 
  5.   "description": "應(yīng)用1 的定義信息", 
  6.   "evaluationOrder": 1 

這段 JSON 配置含義如下:

  1. @calss 指定注冊(cè)服務(wù)類(lèi),這個(gè)是固定的org.apereo.cas.services.RegexRegisteredService。
  2. serviceId 則通過(guò)正則表達(dá)式用來(lái)匹配具體的請(qǐng)求。
  3. name 是接入的 client 的名稱(chēng)。
  4. id 是接入的 client 的 id。
  5. description 是接入的 client 的描述信息。
  6. evaluationOrder 則指定了執(zhí)行的優(yōu)先級(jí)。

接下來(lái)再在 src/main/resources/application.properties 文件中配置剛剛 json 的信息,如下:

 
 
 
 
  1. cas.serviceRegistry.json.location=classpath:/services 
  2. cas.serviceRegistry.initFromJson=true 

這里有兩行配置:

  1. 指定配置 JSON 文件的位置。
  2. 開(kāi)啟 JSON 識(shí)別。

OK,配置完成后,重啟 CAS Server。

CAS Server 啟動(dòng)成功后,我們?cè)诳刂婆_(tái)看到如下日志,表示 JSON 配置已經(jīng)加載成功了:

1.2 JDK 證書(shū)

第二個(gè)要提前準(zhǔn)備的東西就是 JDK 證書(shū)。

在實(shí)際開(kāi)發(fā)中,這一步可以忽略,但是因?yàn)槲覀儸F(xiàn)在用的自己生成的 SSL 證書(shū),所以我們要將自己生成的證書(shū)導(dǎo)入到 JDK 中,否則在使用 Spring Security 接入 CAS 單點(diǎn)登錄時(shí),會(huì)拋出如下錯(cuò)誤:

將 SSL 證書(shū)導(dǎo)入 JDK 中的命令其實(shí)也很簡(jiǎn)單,兩個(gè)步驟,第一個(gè)導(dǎo)出 .cer 文件,第二步,導(dǎo)入 JDK,命令如下:

 
 
 
 
  1. keytool -export -trustcacerts -alias casserver -file ./cas.cer -keystore ./keystore 
  2. sudo keytool -import -trustcacerts -alias casserver -file ./cas.cer -keystore /Library/Java/JavaVirtualMachines/jdk-10.0.2.jdk/Contents/Home/lib/security/cacerts 

注意,在執(zhí)行 export 導(dǎo)出命令時(shí),需要輸入密鑰口令,這個(gè)口令就是自己一開(kāi)始創(chuàng)建 SSL 證書(shū)時(shí)設(shè)置的。在執(zhí)行 import 導(dǎo)入命令時(shí),也需要輸入口令,這個(gè)口令是 changeit,注意,不是自己一開(kāi)始設(shè)置的。

密鑰庫(kù)的位置在 JDK 目錄下的 /lib/security/cacerts,小伙伴們根據(jù)自己實(shí)際情況來(lái)修改(在 JDK9 之前,位置在 jre/lib/security/cacerts)。

我們?cè)诒镜販y(cè)試一定要導(dǎo)入證書(shū)到 JDK 證書(shū)庫(kù)中,否則后面的測(cè)試會(huì)出現(xiàn)上圖中的錯(cuò)誤,證書(shū)導(dǎo)入 JDK 證書(shū)庫(kù)之后,要確保之后的開(kāi)發(fā)中,使用的是本地的 JDK。

注意,JDK 證書(shū)導(dǎo)入之后,CASServer 需要重啟一下。

1.3 修改 hosts

另外,我們還需要修改電腦 hosts 文件,因?yàn)榍懊骊P(guān)于 CAS Server,關(guān)于 SSL 證書(shū)的配置都涉及到域名,所以后面的訪問(wèn)我們將通過(guò)域名的形式訪問(wèn),hosts 文件中添加如下兩條記錄:

第一個(gè)是 CAS Server 的請(qǐng)求域名,第二個(gè)是 CAS Client 的請(qǐng)求域名。

2.開(kāi)發(fā) Client

在使用 Spring Security 開(kāi)發(fā) CAS Client 之前,有一個(gè)基本問(wèn)題需要先和小伙伴們捋清楚:用戶(hù)登錄是在 CAS Server 上登錄,所以 Spring Security 中雖然依舊存在用戶(hù)的概念,但是對(duì)于用戶(hù)的處理邏輯會(huì)和前面的有所不同。

好了,接下來(lái)我們來(lái)看下具體步驟。

首先我們來(lái)創(chuàng)建一個(gè)普通的 Spring Boot 項(xiàng)目,加入 Web 依賴(lài) 和 Spring Security 依賴(lài),如下:

項(xiàng)目創(chuàng)建成功后,我們?cè)賮?lái)手動(dòng)加入 cas 依賴(lài):

 
 
 
 
  1.  
  2.     org.springframework.security 
  3.     spring-security-cas 
  4.  

 

接下來(lái),在 application.properties 中配置 CAS Server 和 CAS Client 的請(qǐng)求地址信息:

 
 
 
 
  1. cas.server.prefix=https://cas.javaboy.org:8443/cas 
  2. cas.server.login=${cas.server.prefix}/login 
  3. cas.server.logout=${cas.server.prefix}/logout 
  4.  
  5. cas.client.prefix=http://client1.cas.javaboy.org:8080 
  6. cas.client.login=${cas.client.prefix}/login/cas 
  7. cas.client.logoutRelative=/logout/cas 
  8. cas.client.logout=${cas.client.prefix}${cas.client.logoutRelative} 

這些配置都是自定義配置,所以配置的 key 可以自己隨意定義。至于配置的含義都好理解,分別配置了 CAS Server 和 CAS Client 的登錄和注銷(xiāo)地址。

配置好之后,我們需要將這些配置注入到實(shí)體類(lèi)中使用,這里就用到了類(lèi)型安全的屬性綁定。

這里我創(chuàng)建兩個(gè)類(lèi)分別用來(lái)接收 CAS Server 和 CAS Client 的配置文件:

 
 
 
 
  1. @ConfigurationProperties(prefix = "cas.server") 
  2. public class CASServerProperties { 
  3.     private String prefix; 
  4.     private String login; 
  5.     private String logout; 
  6.     //省略 getter/setter 
  7. @ConfigurationProperties(prefix = "cas.client") 
  8. public class CASClientProperties { 
  9.     private String prefix; 
  10.     private String login; 
  11.     private String logoutRelative; 
  12.     private String logout; 
  13.     //省略 getter/setter 

另外記得在啟動(dòng)類(lèi)上面添加 @ConfigurationPropertiesScan 注解來(lái)掃描這兩個(gè)配置類(lèi):

 
 
 
 
  1. @SpringBootApplication 
  2. @ConfigurationPropertiesScan 
  3. public class Client1Application { 
  4.  
  5.     public static void main(String[] args) { 
  6.         SpringApplication.run(Client1Application.class, args); 
  7.     } 

這里配置完成后,我們一會(huì)將在配置文件中來(lái)使用。

接下來(lái)創(chuàng)建 CAS 的配置文件,略長(zhǎng):

 
 
 
 
  1. @Configuration 
  2. public class CasSecurityConfig { 
  3.     @Autowired 
  4.     CASClientProperties casClientProperties; 
  5.     @Autowired 
  6.     CASServerProperties casServerProperties; 
  7.     @Autowired 
  8.     UserDetailsService userDetailService; 
  9.  
  10.     @Bean 
  11.     ServiceProperties serviceProperties() { 
  12.         ServiceProperties serviceProperties = new ServiceProperties(); 
  13.         serviceProperties.setService(casClientProperties.getLogin()); 
  14.         return serviceProperties; 
  15.     } 
  16.  
  17.     @Bean 
  18.     @Primary 
  19.     AuthenticationEntryPoint authenticationEntryPoint() { 
  20.         CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint(); 
  21.         entryPoint.setLoginUrl(casServerProperties.getLogin()); 
  22.         entryPoint.setServiceProperties(serviceProperties()); 
  23.         return entryPoint; 
  24.     } 
  25.  
  26.     @Bean 
  27.     TicketValidator ticketValidator() { 
  28.         return new Cas20ProxyTicketValidator(casServerProperties.getPrefix()); 
  29.     } 
  30.  
  31.     @Bean 
  32.     CasAuthenticationProvider casAuthenticationProvider() { 
  33.         CasAuthenticationProvider provider = new CasAuthenticationProvider(); 
  34.         provider.setServiceProperties(serviceProperties()); 
  35.         provider.setTicketValidator(ticketValidator()); 
  36.         provider.setUserDetailsService(userDetailService); 
  37.         provider.setKey("javaboy"); 
  38.         return provider; 
  39.     } 
  40.  
  41.     @Bean 
  42.     CasAuthenticationFilter casAuthenticationFilter(AuthenticationProvider authenticationProvider) { 
  43.         CasAuthenticationFilter filter = new CasAuthenticationFilter(); 
  44.         filter.setServiceProperties(serviceProperties()); 
  45.         filter.setAuthenticationManager(new ProviderManager(authenticationProvider)); 
  46.         return filter; 
  47.     } 
  48.  
  49.     @Bean 
  50.     SingleSignOutFilter singleSignOutFilter() { 
  51.         SingleSignOutFilter sign = new SingleSignOutFilter(); 
  52.         sign.setIgnoreInitConfiguration(true); 
  53.         return sign; 
  54.     } 
  55.     @Bean 
  56.     LogoutFilter logoutFilter() { 
  57.         LogoutFilter filter = new LogoutFilter(casServerProperties.getLogout(), new SecurityContextLogoutHandler()); 
  58.         filter.setFilterProcessesUrl(casClientProperties.getLogoutRelative()); 
  59.         return filter; 
  60.     } 

這個(gè)配置文件略長(zhǎng),但是并不難,我來(lái)和大家挨個(gè)解釋?zhuān)?/p>

  1. 首先一進(jìn)來(lái)注入三個(gè)對(duì)象,這三個(gè)中,有兩個(gè)是我們前面寫(xiě)的配置類(lèi)的實(shí)例,另外一個(gè)則是 UserDetailsService,關(guān)于 UserDetailsService,我想我也不必多做解釋?zhuān)蠹覅⒖急鞠盗星懊娴奈恼戮椭?UserDetailsService 的作用,一會(huì)我會(huì)給出 UserDetailsService 的實(shí)現(xiàn)。
  2. 接下來(lái)配置 ServiceProperties,ServiceProperties 中主要配置一下 Client 的登錄地址即可,這個(gè)地址就是在 CAS Server 上登錄成功后,重定向的地址。
  3. CasAuthenticationEntryPoint 則是 CAS 驗(yàn)證的入口,這里首先設(shè)置 CAS Server 的登錄地址,同時(shí)將前面的 ServiceProperties 設(shè)置進(jìn)去,這樣當(dāng)它登錄成功后,就知道往哪里跳轉(zhuǎn)了。
  4. TicketValidator 這是配置 ticket 校驗(yàn)地址,CAS Client 拿到 ticket 要去 CAS Server 上校驗(yàn),默認(rèn)校驗(yàn)地址是:https://cas.javaboy.org:8443/cas/proxyValidate?ticket=xxx
  5. CasAuthenticationProvider 主要用來(lái)處理 CAS 驗(yàn)證邏輯,關(guān)于 AuthenticationProvider 松哥在前面的文章中和大家分享過(guò)(SpringSecurity 自定義認(rèn)證邏輯的兩種方式(高級(jí)玩法)),當(dāng)時(shí)就說(shuō),想要自定義認(rèn)證邏輯,如短信登錄等,都可以通過(guò)擴(kuò)展 AuthenticationProvider 來(lái)實(shí)現(xiàn),這里的 CAS 登錄當(dāng)然也不例外,這里雖然設(shè)置了一個(gè) userDetailService,但是目的不是為了從數(shù)據(jù)庫(kù)中查詢(xún)數(shù)據(jù)做校驗(yàn),因?yàn)榈卿浭窃?CAS Server 中進(jìn)行的,這個(gè)的作用,我在后面會(huì)做介紹。
  6. CasAuthenticationFilter 則是 CAS 認(rèn)證的過(guò)濾器,過(guò)濾器將請(qǐng)求攔截下來(lái)之后,交由 CasAuthenticationProvider 來(lái)做具體處理。
  7. SingleSignOutFilter 表示接受 CAS Server 發(fā)出的注銷(xiāo)請(qǐng)求,所有的注銷(xiāo)請(qǐng)求都將從 CAS Client 轉(zhuǎn)發(fā)到 CAS Server,CAS Server 處理完后,會(huì)通知所有的 CAS Client 注銷(xiāo)登錄。
  8. LogoutFilter 則是配置將注銷(xiāo)請(qǐng)求轉(zhuǎn)發(fā)到 CAS Server。

接下來(lái)我再來(lái)給大家看下我定義的 UserDetailsService:

 
 
 
 
  1. @Component 
  2. @Primary 
  3. public class UserDetailsServiceImpl implements UserDetailsService{ 
  4.  
  5.     @Override 
  6.     public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException { 
  7.         return new User(s, "123", true, true, true, true, 
  8.                 AuthorityUtils.createAuthorityList("ROLE_user")); 
  9.     } 

既然是單點(diǎn)登錄,也就是用戶(hù)是在 CAS Server 上登錄的,這里的 UserDetailsService 意義在哪里呢?

用戶(hù)雖然在 CAS Server 上登錄,但是,登錄成功之后,CAS Client 還是要獲取用戶(hù)的基本信息、角色等,以便做進(jìn)一步的權(quán)限控制,所以,這里的 loadUserByUsername 方法中的參數(shù),實(shí)際上就是你從 CAS Server 上登錄成功后獲取到的用戶(hù)名,拿著這個(gè)用戶(hù)名,去數(shù)據(jù)庫(kù)中查詢(xún)用戶(hù)的相關(guān)信心并返回,方便 CAS Client 在后續(xù)的鑒權(quán)中做進(jìn)一步的使用,這里我為了方便,就沒(méi)有去數(shù)據(jù)庫(kù)中查詢(xún)了,而是直接創(chuàng)建了一個(gè) User 對(duì)象返回。

接下來(lái),我們?cè)賮?lái)看看 Spring Security 的配置:

 
 
 
 
  1. @Configuration 
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  3.     @Autowired 
  4.     AuthenticationEntryPoint authenticationEntryPoint; 
  5.     @Autowired 
  6.     AuthenticationProvider authenticationProvider; 
  7.     @Autowired 
  8.     SingleSignOutFilter singleSignOutFilter; 
  9.     @Autowired 
  10.     LogoutFilter logoutFilter; 
  11.     @Autowired 
  12.     CasAuthenticationFilter casAuthenticationFilter; 
  13.  
  14.     @Override 
  15.     protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
  16.         auth.authenticationProvider(authenticationProvider); 
  17.     } 
  18.  
  19.     @Override 
  20.     protected void configure(HttpSecurity http) throws Exception { 
  21.         http.authorizeRequests().antMatchers("/user/**") 
  22.                 .hasRole("user") 
  23.                 .antMatchers("/login/cas").permitAll() 
  24.                 .anyRequest().authenticated() 
  25.                 .and() 
  26.                 .exceptionHandling() 
  27.                 .authenticationEntryPoint(authenticationEntryPoint) 
  28.                 .and() 
  29.                 .addFilter(casAuthenticationFilter) 
  30.                 .addFilterBefore(singleSignOutFilter, CasAuthenticationFilter.class) 
  31.                 .addFilterBefore(logoutFilter, LogoutFilter.class); 
  32.     } 

這里的配置就簡(jiǎn)單很多了:

  1. 首先配置 authenticationProvider,這個(gè) authenticationProvider 實(shí)際上就是一開(kāi)始配置的 CasAuthenticationProvider。
  2. 接下來(lái)配置 /user/** 格式的路徑需要有 user 角色才能訪問(wèn),登錄路徑 /login/cas 可以直接訪問(wèn),剩余接口都是登錄成功之后才能訪問(wèn)。
  3. 最后把 authenticationEntryPoint 配置進(jìn)來(lái),再把自定義的過(guò)濾器加進(jìn)來(lái),這些都比較容易我就不多說(shuō)了。

最后,再提供兩個(gè)測(cè)試接口:

 
 
 
 
  1. @RestController 
  2. public class HelloController { 
  3.     @GetMapping("/hello") 
  4.     public String hello() { 
  5.         return "hello"; 
  6.     } 
  7.     @GetMapping("/user/hello") 
  8.     public String user() { 
  9.         return "user"; 
  10.     } 

OK ,如此之后,我們的 CAS Client 現(xiàn)在就開(kāi)發(fā)完成了,接下來(lái)啟動(dòng) CAS Client,啟動(dòng)成功后,瀏覽器輸入 http://client1.cas.javaboy.org:8080/user/hello 訪問(wèn) hello 接口,此時(shí)會(huì)自動(dòng)跳轉(zhuǎn)到 CAS Server 上登錄,登錄成功之后,經(jīng)過(guò)兩個(gè)重定向,會(huì)重新回到 hello 接口。

3.小結(jié)

OK,這就是松哥和大家介紹的 Spring Security + CAS 單點(diǎn)登錄,當(dāng)然,這個(gè)案例中還有很多需要完善的地方,松哥會(huì)在后面的文章中繼續(xù)和大家分享完善的方案。

好了 ,本文就說(shuō)到這里,本文相關(guān)案例我已經(jīng)上傳到 GitHub ,大家可以自行下載:https://github.com/lenve/spring-security-samples

本文轉(zhuǎn)載自微信公眾號(hào)「江南一點(diǎn)雨」,可以通過(guò)以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系江南一點(diǎn)雨公眾號(hào)。


本文名稱(chēng):SpringSecurity系列之SpringBoot+CAS單點(diǎn)登錄
鏈接分享:http://www.5511xx.com/article/ccdscpo.html