Spring BootはSpring securityを使ってCASを集積します。


1.プロジェクトの作成
Maven作成プロジェクト:springbook-security-cas
2.依存関係を追加
プロジェクトを作成した後、pom.xmlを開いて、pom.xmlに以下の内容を追加します。

<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.appication.propertiesを作成する
appication.propertiesファイルを作成し、以下の内容を追加します。

#CAS     
cas.server.host.url=http://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=http://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 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   
@EnableGlobalMethodSecurity(prePostEnabled = true) //       
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
  @Autowired 
  private CasProperties casProperties; 
   
  /**            ,       */ 
  @Override 
  protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
    super.configure(auth); 
    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     
     
    http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint()) 
      .and() 
      .addFilter(casAuthenticationFilter()) 
      .addFilterBefore(casLogoutFilter(), LogoutFilter.class) 
      .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class); 
     
    //http.csrf().disable(); //  CSRF 
  } 
   
  /**     */ 
  @Bean 
  public CasAuthenticationEntryPoint casAuthenticationEntryPoint() { 
    CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint(); 
    casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl()); 
    casAuthenticationEntryPoint.setServiceProperties(serviceProperties()); 
    return casAuthenticationEntryPoint; 
  } 
   
  /**  service    */ 
  @Bean 
  public ServiceProperties serviceProperties() { 
    ServiceProperties serviceProperties = new ServiceProperties(); 
    serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl()); 
    serviceProperties.setAuthenticateAllArtifacts(true); 
    return serviceProperties; 
  } 
   
  /**CAS     */ 
  @Bean 
  public CasAuthenticationFilter casAuthenticationFilter() throws Exception { 
    CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter(); 
    casAuthenticationFilter.setAuthenticationManager(authenticationManager()); 
    casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl()); 
    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 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)Cas Propertiesを定義し、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)CustoomUserDetails Service類を定義し、コードは以下の通りである。

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; 
 
/** 
 *            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("       :"+token.getName()); 
    /*       ,           ,                              */ 
    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)AuthortyInfoクラスを定義し、現在ログインしているユーザの権限情報をロードするために、Granted Authortyインターフェースを実現します。コードは以下の通りです。

package com.chengli.springboot.custom; 
 
import org.springframework.security.core.GrantedAuthority; 
 
/** 
 *      
 * 
 * @author ChengLi 
 * 
 */ 
public class AuthorityInfo implements GrantedAuthority { 
  private static final long serialVersionUID = -175781100474818800L; 
 
  /** 
   *   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クラスを定義し、現在のユーザ情報をロードするために、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; 
 
/** 
 *      
 * @、              ,id,name,username,password,              
 * @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    
} 

ここでは基本的に完了しました。CAS Serverを実行して、上記のaplication.propertiesファイルのアドレスを実際のアドレスに修正して実行します。
以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。