pandaAnthony:spring boot cas 服務(wù)端和spring security客戶端搭建(三)

這個(gè)系列有3篇文章:

  1. spring boot cas 服務(wù)端和spring security客戶端搭建(一):主要介紹怎么用spring boot cas搭建https的服務(wù)端
  2. spring boot cas 服務(wù)端和spring security客戶端搭建(二):主要介紹怎么用怎么結(jié)合數(shù)據(jù)庫(kù)用cas提供的動(dòng)態(tài)加密方式登錄及相關(guān)配置
  3. spring boot cas 服務(wù)端和spring security客戶端搭建(三):主要介紹怎么結(jié)合spring security客戶端進(jìn)行整合及http方式登錄配置

終于騰出時(shí)間來(lái)寫完這個(gè)系列了鸦泳。
接著上篇spring boot cas 服務(wù)端和spring security客戶端搭建(二)繼續(xù)介紹cas與spring security客戶端的整合淹真。官網(wǎng)的資料只在github上找到了客戶端的代碼https://github.com/apereo/java-cas-client#spring-security-integration耸携,而且還不是spring boot版本的:

image.png

image.png

由于學(xué)習(xí)spring boot不久笨忌,還要花更多時(shí)間研究其他功能冬殃,就沒(méi)花時(shí)間去把這些xml配置轉(zhuǎn)成spring boot的配置了魂角;參考https://blog.csdn.net/cl_andywin/article/details/53998986遂填,搭建了基于spring boot的spring security cas客戶端立叛。

引入相關(guān)的依賴包

在對(duì)應(yīng)工程的pom文件中引入spring-security-cas包(其他相關(guān)spring boot 的包就不在這里描述了负敏,這里的包的版本和spring boot parent版本對(duì)應(yīng))
spring boot版本,項(xiàng)目中用的是2.0.3.RELEASE:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
    <relativePath/>
</parent>

spring boot security和 security cas包

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-cas</artifactId>
</dependency>

配置文件和配置類

CasProperties秘蛇,cas服務(wù)端和客戶端相關(guān)的配置信息(這里用到了lombok.Data來(lái)生成get其做,set方法):

@Data
@Component
public class CasProperties {
    
    @Value("${security.cas.server.host}")
    private String casServerUrl;
 
    @Value("${security.cas.server.login}")
    private String casServerLoginUrl;
 
    @Value("${security.cas.server.logout}")
    private String casServerLogoutUrl;
 
    @Value("${security.cas.service.host}")
    private String appServerUrl;
 
    @Value("${security.cas.service.login}")
    private String appLoginUrl;
 
    @Value("${security.cas.service.logout}")
    private String appLogoutUrl;

}

對(duì)應(yīng)的配置信息(這時(shí)cas服務(wù)用的是http形式的了顶考,因?yàn)榄h(huán)境限制不能用域名的,而且http的省事妖泄,在文章的后面會(huì)介紹怎么使用http)驹沿,配置的具體含義這里就不描述了:

security:
  cas:
    server:
      host: http://xxx.xxx.xxx.xxx:8443/cas
      login: ${security.cas.server.host}/login
      logout: ${security.cas.server.host}/logout?service=${security.cas.service.host}
    service:
      host: http://localhost:8764
      login: /login
      logout: /logout

WebSecurityConfig配置類,最核心的配置(上面cas相關(guān)地址的配置不一定要那樣實(shí)現(xiàn)蹈胡,可能有更靈活的辦法渊季;下面登出的相關(guān)配置沒(méi)有起到想象的作用,一個(gè)應(yīng)用登出了罚渐,其他應(yīng)用不會(huì)一起登出却汉;后續(xù)找到辦法了會(huì)繼續(xù)補(bǔ)充):

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CasProperties casProperties;

    /**
     * configure(AuthenticationManagerBuilder): 身份驗(yàn)證配置,用于注入自定義身份驗(yàn)證Bean和密碼校驗(yàn)規(guī)則
     * 
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
        auth.authenticationProvider(casAuthenticationProvider());
    }

    /**
     * configure(WebSecurity): Web層面的配置荷并,一般用來(lái)配置無(wú)需安全檢查的路徑
     * 
     * @param web
     * @throws Exception
     */
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/static/**", "/templates/**");
    }

    /**
     * configure(HttpSecurity): Request層面的配置合砂,對(duì)應(yīng)XML Configuration中的<http>元素
     * 
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()// 配置安全策略
                .antMatchers("/login/cas").permitAll()
                .and().authorizeRequests().anyRequest().authenticated()
                .and().logout().permitAll()// 定義logout不需要驗(yàn)證
                .and().formLogin().defaultSuccessUrl("/index"); // 登錄成功之后的跳轉(zhuǎn)

        http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
                .and().addFilter(casAuthenticationFilter())
                .addFilterBefore(casLogoutFilter(), LogoutFilter.class)
                .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);

        http.csrf().disable();

        // 關(guān)閉spring security默認(rèn)的frame訪問(wèn)限制
        http.headers().frameOptions().sameOrigin();
    }

    @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);
        serviceProperties.setSendRenew(false);
        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());
        // 這里只是接口類型,實(shí)現(xiàn)的接口不一樣源织,都可以的翩伪。
        casAuthenticationProvider.setServiceProperties(serviceProperties());
        // casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
        casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
        casAuthenticationProvider.setKey("casAuthenticationProviderKey");
        return casAuthenticationProvider;
    }

    // 用戶自定義的AuthenticationUserDetailsService
    @Bean
    public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {
        return new CustomUserDetailsService();
    }

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

    @Bean
    public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
        return new Cas30ServiceTicketValidator(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;
    }

    public SingleSignOutHttpSessionListener singleSignOutHttpSessionListener() {
        return new SingleSignOutHttpSessionListener();
    }

    @Bean
    public ServletListenerRegistrationBean<EventListener> singleSignOutListenerRegistration() {
        ServletListenerRegistrationBean<EventListener> registrationBean = new ServletListenerRegistrationBean<EventListener>();
        registrationBean.setListener(new SingleSignOutHttpSessionListener());
        registrationBean.setOrder(1);
        return registrationBean;
    }

    @Bean
    public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> singleSignOutHttpSessionListenerBean() {
        ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> listenerRegistrationBean = new ServletListenerRegistrationBean<>();
        listenerRegistrationBean.setEnabled(true);
        listenerRegistrationBean.setListener(singleSignOutHttpSessionListener());
        listenerRegistrationBean.setOrder(3);
        System.out.println("================================singleListener執(zhí)行");
        return listenerRegistrationBean;
    }

}

其中需要自己去實(shí)現(xiàn)CustomUserDetailsService的用戶認(rèn)證邏輯:

@Service
public class CustomUserDetailsService //實(shí)現(xiàn)AuthenticationUserDetailsService,實(shí)現(xiàn)loadUserDetails方法
    implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {           
    @Override
    public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {
        // 結(jié)合具體的邏輯去實(shí)現(xiàn)用戶認(rèn)證谈息,并返回繼承UserDetails的用戶對(duì)象;
        return XXX;
    }

}

其中UserDetails是個(gè)接口:


image.png

到這里缘屹,spring boot下spring security整合cas的客戶端基本就構(gòu)建完成了。

http方式的CAS服務(wù)端

在第一篇文章(http://www.reibang.com/p/0b3375b10860)介紹的cas-overlay-template下的配置文件application.properties中修改:

# 去掉https驗(yàn)證
cas.tgc.secure=false
cas.warn.cookie.secure=false
server.ssl.enabled=false

其中cas.tgc.secure和cas.warn.cookie.secure是新增的侠仇,server.ssl.enabled默認(rèn)的是true:


image.png

默認(rèn)情況下轻姿,CAS是只支持https請(qǐng)求的;還有個(gè)地方需要修改逻炊。因?yàn)槭莝pring boot結(jié)構(gòu)踢代,可以直接覆蓋原有文件,這里就不在額外的加配置了嗅骄,直接在serveices文件夾下修改HTTSPandIMAPS-10000001.json:


image.png

image.png

這個(gè)文件可以在打包后的target下找到:


image.png

在https的邊上多加個(gè)‘|http’就可以了:


image.png

這樣CAS就能支持http方式了胳挎。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市溺森,隨后出現(xiàn)的幾起案子慕爬,更是在濱河造成了極大的恐慌,老刑警劉巖屏积,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件幸逆,死亡現(xiàn)場(chǎng)離奇詭異罐氨,居然都是意外死亡玷氏,警方通過(guò)查閱死者的電腦和手機(jī)筹我,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人独榴,你說(shuō)我怎么就攤上這事僧叉。” “怎么了棺榔?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵瓶堕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我症歇,道長(zhǎng)郎笆,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任忘晤,我火速辦了婚禮宛蚓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘设塔。我一直安慰自己苍息,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布壹置。 她就那樣靜靜地躺著,像睡著了一般表谊。 火紅的嫁衣襯著肌膚如雪钞护。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天爆办,我揣著相機(jī)與錄音难咕,去河邊找鬼。 笑死距辆,一個(gè)胖子當(dāng)著我的面吹牛余佃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播跨算,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼爆土,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了诸蚕?” 一聲冷哼從身側(cè)響起步势,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎背犯,沒(méi)想到半個(gè)月后坏瘩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡漠魏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年倔矾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哪自,死狀恐怖丰包,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情提陶,我是刑警寧澤烫沙,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站隙笆,受9級(jí)特大地震影響锌蓄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撑柔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一瘸爽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧铅忿,春花似錦剪决、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至峻凫,卻和暖如春渗鬼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背荧琼。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工譬胎, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人命锄。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓堰乔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親脐恩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镐侯,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容