springboot+cas單點登錄

1.創(chuàng)建工程
? ? ? 創(chuàng)建Maven工程:springboot-security-cas
2.加入依賴
? ? ? 創(chuàng)建工程后,打開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 對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)用訪問地址  
app.server.host.url=http://localhost:8080  
#應(yīng)用登錄地址  
app.login.url=/login  
#應(yīng)用登出地址  
app.logout.url=/logout  

4.創(chuàng)建入口啟動類(MainConfig)
創(chuàng)建入口啟動類MainConfig,完整代碼如下:

package com.lidd.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權(quán)限的才能訪問  
    @RequestMapping("/security")  
    public String security() {  
        return "hello world security";  
    }  
  
    @PreAuthorize("hasAuthority('ADMIN')")//必須要有ADMIN權(quán)限的才能訪問  
    @RequestMapping("/authorize")  
    public String authorize() {  
        return "有權(quán)限訪問";  
    }  
      
    /**這里注意的是,TEST與ADMIN只是權(quán)限編碼,可以自己定義一套規(guī)則,根據(jù)實際情況即可*/  
}  

5.創(chuàng)建Security配置類(SecurityConfig)
創(chuàng)建Security配置類SecurityConfig,完整代碼如下:

package com.lidd.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.lidd.springboot.custom.CustomUserDetailsService;  
import com.lidd.springboot.properties.CasProperties;  
  
@Configuration  
@EnableWebSecurity //啟用web權(quán)限  
@EnableGlobalMethodSecurity(prePostEnabled = true) //啟用方法驗證  
public class SecurityConfig extends WebSecurityConfigurerAdapter {  
    @Autowired  
    private CasProperties casProperties;  
      
    /**定義認(rèn)證用戶信息獲取來源,密碼校驗規(guī)則等*/  
    @Override  
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
        super.configure(auth);  
        auth.authenticationProvider(casAuthenticationProvider());  
        //inMemoryAuthentication 從內(nèi)存中獲取  
        //auth.inMemoryAuthentication().withUser("lidd").password("123456").roles("USER")  
        //.and().withUser("admin").password("123456").roles("ADMIN");  
          
        //jdbcAuthentication從數(shù)據(jù)庫中獲取,但是默認(rèn)是以security提供的表結(jié)構(gòu)  
        //usersByUsernameQuery 指定查詢用戶SQL  
        //authoritiesByUsernameQuery 指定查詢權(quán)限SQL  
        //auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);  
          
        //注入userDetailsService,需要實現(xiàn)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表單登錄  
          
        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)證過濾器*/  
    @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()); //這里只是接口類型,實現(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());  
    }  
      
    /**單點登出過濾器*/  
    @Bean  
    public SingleSignOutFilter singleSignOutFilter() {  
        SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();  
        singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());  
        singleSignOutFilter.setIgnoreInitConfiguration(true);  
        return singleSignOutFilter;  
    }  
      
    /**請求單點退出過濾器*/  
    @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.lidd.springboot.properties;  
  
import org.springframework.beans.factory.annotation.Value;  
import org.springframework.stereotype.Component;  
  
/** 
 * CAS的配置參數(shù) 
 * @author lidd 
 */  
@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.lidd.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;  
  
/** 
 * 用于加載用戶信息 實現(xiàn)UserDetailsService接口,或者實現(xiàn)AuthenticationUserDetailsService接口 
 * @author lidd 
 * 
 */  
public class CustomUserDetailsService /* 
    //實現(xiàn)UserDetailsService接口,實現(xiàn)loadUserByUsername方法 
    implements UserDetailsService { 
    @Override 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
        System.out.println("當(dāng)前的用戶名是:"+username); 
        //這里我為了方便,就直接返回一個用戶信息,實際當(dāng)中這里修改為查詢數(shù)據(jù)庫或者調(diào)用服務(wù)什么的來獲取用戶信息 
        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; 
    }*/  
      
      
    //實現(xiàn)AuthenticationUserDetailsService,實現(xiàn)loadUserDetails方法  
    implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {  
  
    @Override  
    public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {  
        System.out.println("當(dāng)前的用戶名是:"+token.getName());  
        /*這里我為了方便,就直接返回一個用戶信息,實際當(dāng)中這里修改為查詢數(shù)據(jù)庫或者調(diào)用服務(wù)什么的來獲取用戶信息*/  
        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)限信息,實現(xiàn)GrantedAuthority接口,代碼如下:

package com.lidd.springboot.custom;  
  
import org.springframework.security.core.GrantedAuthority;  
  
/** 
 * 權(quán)限信息 
 *  
 * @author lidd 
 * 
 */  
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)前用戶信息,實現(xiàn)UserDetails接口,代碼如下:

package com.lidd.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;  
  
/** 
 * 用戶信息 
 * @、這里我寫了幾個較為常用的字段,id,name,username,password,可以根據(jù)實際的情況自己增加 
 * @author lidd 
 * 
 */  
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 方法  
}  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,545評論 19 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,271評論 6 342
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 34,669評論 18 399
  • 這是離開臨汾最后一次去師大拍的毓秀湖!看到了要搬新校區(qū)的消息,心中卻沒有一絲興奮,以后的師大還是我回憶中的師大嗎?...
    尼古拉斯FY閱讀 516評論 0 6
  • 153 幼兒教師,即小孩子的老師,職業(yè)道德 ,即職業(yè)的道德 是道德在職業(yè)活動中的一種特殊要求和準(zhǔn)則,是道德的組成...
    涅磐新生閱讀 744評論 0 0

友情鏈接更多精彩內(nèi)容