Spring Boot 使用Spring security 集成CAS - CSDN博客

标签: | 发表时间:2018-06-15 14:25 | 作者:
出处:https://blog.csdn.net

1.创建工程

      创建Maven工程:springboot-security-cas

2.加入依赖

      创建工程后,打开pom.xml,在pom.xml中加入以下内容:
[html]  view plain  copy
  1. <parent>  
  2.         <groupId>org.springframework.boot</groupId>  
  3.         <artifactId>spring-boot-starter-parent</artifactId>  
  4.         <version>1.4.3.RELEASE</version>  
  5.     </parent>  
  6.     <properties>  
  7.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>  
  8.         <java.version>1.8</java.version>  
  9.     </properties>  
  10.     <dependencies>  
  11.         <dependency>  
  12.             <groupId>org.springframework.boot</groupId>  
  13.             <artifactId>spring-boot-starter</artifactId>  
  14.         </dependency>  
  15.         <dependency>  
  16.             <groupId>org.springframework.boot</groupId>  
  17.             <artifactId>spring-boot-starter-web</artifactId>  
  18.         </dependency>  
  19.         <!-- security starter Poms -->  
  20.         <dependency>  
  21.             <groupId>org.springframework.boot</groupId>  
  22.             <artifactId>spring-boot-starter-security</artifactId>  
  23.         </dependency>  
  24.         <!-- security 对CAS支持 -->  
  25.         <dependency>  
  26.             <groupId>org.springframework.security</groupId>  
  27.             <artifactId>spring-security-cas</artifactId>  
  28.         </dependency>  
  29.         <!-- security taglibs -->  
  30.         <dependency>  
  31.             <groupId>org.springframework.security</groupId>  
  32.             <artifactId>spring-security-taglibs</artifactId>  
  33.         </dependency>  
  34.         <!-- 热加载 -->  
  35.         <dependency>  
  36.             <groupId>org.springframework.boot</groupId>  
  37.             <artifactId>spring-boot-devtools</artifactId>  
  38.             <optional>true</optional>  
  39.         </dependency>  
  40.         <dependency>  
  41.             <groupId>org.springframework.boot</groupId>  
  42.             <artifactId>spring-boot-configuration-processor</artifactId>  
  43.             <optional>true</optional>  
  44.         </dependency>  
  45.     </dependencies>  
  46.     <build>  
  47.         <plugins>  
  48.             <plugin>  
  49.                 <groupId>org.springframework.boot</groupId>  
  50.                 <artifactId>spring-boot-maven-plugin</artifactId>  
  51.             </plugin>  
  52.         </plugins>  
  53.     </build>  

3.创建application.properties

      创建application.properties文件,加入以下内容:
[plain]  view plain  copy
  1. #CAS服务地址  
  2. cas.server.host.url=http://localhost:8081/cas  
  3. #CAS服务登录地址  
  4. cas.server.host.login_url=${cas.server.host.url}/login  
  5. #CAS服务登出地址  
  6. cas.server.host.logout_url=${cas.server.host.url}/logout?service=${app.server.host.url}  
  7. #应用访问地址  
  8. app.server.host.url=http://localhost:8080  
  9. #应用登录地址  
  10. app.login.url=/login  
  11. #应用登出地址  
  12. app.logout.url=/logout  

4.创建入口启动类(MainConfig)

      创建入口启动类MainConfig,完整代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot;  
  2.   
  3. import org.springframework.boot.SpringApplication;  
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;  
  5. import org.springframework.security.access.prepost.PreAuthorize;  
  6. import org.springframework.web.bind.annotation.RequestMapping;  
  7. import org.springframework.web.bind.annotation.RestController;  
  8.   
  9. @RestController  
  10. @SpringBootApplication  
  11. public class MainConfig {  
  12.     public static void main(String[] args) {  
  13.         SpringApplication.run(MainConfig.class, args);  
  14.     }  
  15.   
  16.     @RequestMapping("/")  
  17.     public String index() {  
  18.         return "访问了首页哦";  
  19.     }  
  20.   
  21.     @RequestMapping("/hello")  
  22.     public String hello() {  
  23.         return "不验证哦";  
  24.     }  
  25.   
  26.     @PreAuthorize("hasAuthority('TEST')")//有TEST权限的才能访问  
  27.     @RequestMapping("/security")  
  28.     public String security() {  
  29.         return "hello world security";  
  30.     }  
  31.   
  32.     @PreAuthorize("hasAuthority('ADMIN')")//必须要有ADMIN权限的才能访问  
  33.     @RequestMapping("/authorize")  
  34.     public String authorize() {  
  35.         return "有权限访问";  
  36.     }  
  37.       
  38.     /**这里注意的是,TEST与ADMIN只是权限编码,可以自己定义一套规则,根据实际情况即可*/  
  39. }  

5.创建Security配置类(SecurityConfig)

      创建Security配置类SecurityConfig,完整代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot.security;  
  2.   
  3. import org.jasig.cas.client.session.SingleSignOutFilter;  
  4. import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;  
  5. import org.springframework.beans.factory.annotation.Autowired;  
  6. import org.springframework.context.annotation.Bean;  
  7. import org.springframework.context.annotation.Configuration;  
  8. import org.springframework.security.cas.ServiceProperties;  
  9. import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;  
  10. import org.springframework.security.cas.authentication.CasAuthenticationProvider;  
  11. import org.springframework.security.cas.web.CasAuthenticationEntryPoint;  
  12. import org.springframework.security.cas.web.CasAuthenticationFilter;  
  13. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;  
  14. import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;  
  15. import org.springframework.security.config.annotation.web.builders.HttpSecurity;  
  16. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;  
  17. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;  
  18. import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;  
  19. import org.springframework.security.web.authentication.logout.LogoutFilter;  
  20. import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;  
  21.   
  22. import com.chengli.springboot.custom.CustomUserDetailsService;  
  23. import com.chengli.springboot.properties.CasProperties;  
  24.   
  25. @Configuration  
  26. @EnableWebSecurity //启用web权限  
  27. @EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法验证  
  28. public class SecurityConfig extends WebSecurityConfigurerAdapter {  
  29.     @Autowired  
  30.     private CasProperties casProperties;  
  31.       
  32.     /**定义认证用户信息获取来源,密码校验规则等*/  
  33.     @Override  
  34.     protected void configure(AuthenticationManagerBuilder auth) throws Exception {  
  35.         super.configure(auth);  
  36.         auth.authenticationProvider(casAuthenticationProvider());  
  37.         //inMemoryAuthentication 从内存中获取  
  38.         //auth.inMemoryAuthentication().withUser("chengli").password("123456").roles("USER")  
  39.         //.and().withUser("admin").password("123456").roles("ADMIN");  
  40.           
  41.         //jdbcAuthentication从数据库中获取,但是默认是以security提供的表结构  
  42.         //usersByUsernameQuery 指定查询用户SQL  
  43.         //authoritiesByUsernameQuery 指定查询权限SQL  
  44.         //auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);  
  45.           
  46.         //注入userDetailsService,需要实现userDetailsService接口  
  47.         //auth.userDetailsService(userDetailsService);  
  48.     }  
  49.       
  50.     /**定义安全策略*/  
  51.     @Override  
  52.     protected void configure(HttpSecurity http) throws Exception {  
  53.         http.authorizeRequests()//配置安全策略  
  54.             //.antMatchers("/","/hello").permitAll()//定义/请求不需要验证  
  55.             .anyRequest().authenticated()//其余的所有请求都需要验证  
  56.             .and()  
  57.         .logout()  
  58.             .permitAll()//定义logout不需要验证  
  59.             .and()  
  60.         .formLogin();//使用form表单登录  
  61.           
  62.         http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())  
  63.             .and()  
  64.             .addFilter(casAuthenticationFilter())  
  65.             .addFilterBefore(casLogoutFilter(), LogoutFilter.class)  
  66.             .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);  
  67.           
  68.         //http.csrf().disable(); //禁用CSRF  
  69.     }  
  70.       
  71.     /**认证的入口*/  
  72.     @Bean  
  73.     public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {  
  74.         CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();  
  75.         casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());  
  76.         casAuthenticationEntryPoint.setServiceProperties(serviceProperties());  
  77.         return casAuthenticationEntryPoint;  
  78.     }  
  79.       
  80.     /**指定service相关信息*/  
  81.     @Bean  
  82.     public ServiceProperties serviceProperties() {  
  83.         ServiceProperties serviceProperties = new ServiceProperties();  
  84.         serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());  
  85.         serviceProperties.setAuthenticateAllArtifacts(true);  
  86.         return serviceProperties;  
  87.     }  
  88.       
  89.     /**CAS认证过滤器*/  
  90.     @Bean  
  91.     public CasAuthenticationFilter casAuthenticationFilter() throws Exception {  
  92.         CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();  
  93.         casAuthenticationFilter.setAuthenticationManager(authenticationManager());  
  94.         casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());  
  95.         return casAuthenticationFilter;  
  96.     }  
  97.       
  98.     /**cas 认证 Provider*/  
  99.     @Bean  
  100.     public CasAuthenticationProvider casAuthenticationProvider() {  
  101.         CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();  
  102.         casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());  
  103.         //casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。  
  104.         casAuthenticationProvider.setServiceProperties(serviceProperties());  
  105.         casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());  
  106.         casAuthenticationProvider.setKey("casAuthenticationProviderKey");  
  107.         return casAuthenticationProvider;  
  108.     }  
  109.       
  110.     /*@Bean 
  111.     public UserDetailsService customUserDetailsService(){ 
  112.         return new CustomUserDetailsService(); 
  113.     }*/  
  114.       
  115.     /**用户自定义的AuthenticationUserDetailsService*/  
  116.     @Bean  
  117.     public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService(){  
  118.         return new CustomUserDetailsService();  
  119.     }  
  120.       
  121.     @Bean  
  122.     public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {  
  123.         return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());  
  124.     }  
  125.       
  126.     /**单点登出过滤器*/  
  127.     @Bean  
  128.     public SingleSignOutFilter singleSignOutFilter() {  
  129.         SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();  
  130.         singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());  
  131.         singleSignOutFilter.setIgnoreInitConfiguration(true);  
  132.         return singleSignOutFilter;  
  133.     }  
  134.       
  135.     /**请求单点退出过滤器*/  
  136.     @Bean  
  137.     public LogoutFilter casLogoutFilter() {  
  138.         LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());  
  139.         logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl());  
  140.         return logoutFilter;  
  141.     }  
  142. }  

6.用户自定义类

      (1)定义CasProperties,用于将properties文件指定的内容注入以方便使用,这里不注入也是可以的,可以获取Spring 当前的环境,代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot.properties;  
  2.   
  3. import org.springframework.beans.factory.annotation.Value;  
  4. import org.springframework.stereotype.Component;  
  5.   
  6. /** 
  7.  * CAS的配置参数 
  8.  * @author ChengLi 
  9.  */  
  10. @Component  
  11. public class CasProperties {  
  12.     @Value("${cas.server.host.url}")  
  13.     private String casServerUrl;  
  14.   
  15.     @Value("${cas.server.host.login_url}")  
  16.     private String casServerLoginUrl;  
  17.   
  18.     @Value("${cas.server.host.logout_url}")  
  19.     private String casServerLogoutUrl;  
  20.   
  21.     @Value("${app.server.host.url}")  
  22.     private String appServerUrl;  
  23.   
  24.     @Value("${app.login.url}")  
  25.     private String appLoginUrl;  
  26.   
  27.     @Value("${app.logout.url}")  
  28.     private String appLogoutUrl;  
  29. ......省略 getters setters 方法  
  30. }  

      (2)定义CustomUserDetailsService类,代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot.custom;  
  2.   
  3. import java.util.HashSet;  
  4. import java.util.Set;  
  5.   
  6. import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;  
  7. import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;  
  8. import org.springframework.security.core.userdetails.UserDetails;  
  9. import org.springframework.security.core.userdetails.UsernameNotFoundException;  
  10.   
  11. /** 
  12.  * 用于加载用户信息 实现UserDetailsService接口,或者实现AuthenticationUserDetailsService接口 
  13.  * @author ChengLi 
  14.  * 
  15.  */  
  16. public class CustomUserDetailsService /* 
  17.     //实现UserDetailsService接口,实现loadUserByUsername方法 
  18.     implements UserDetailsService { 
  19.     @Override 
  20.     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
  21.         System.out.println("当前的用户名是:"+username); 
  22.         //这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息 
  23.         UserInfo userInfo = new UserInfo(); 
  24.         userInfo.setUsername("admin"); 
  25.         userInfo.setName("admin"); 
  26.         Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>(); 
  27.         AuthorityInfo authorityInfo = new AuthorityInfo("TEST"); 
  28.         authorities.add(authorityInfo); 
  29.         userInfo.setAuthorities(authorities); 
  30.         return userInfo; 
  31.     }*/  
  32.       
  33.       
  34.     //实现AuthenticationUserDetailsService,实现loadUserDetails方法  
  35.     implements AuthenticationUserDetailsService<CasAssertionAuthenticationToken> {  
  36.   
  37.     @Override  
  38.     public UserDetails loadUserDetails(CasAssertionAuthenticationToken token) throws UsernameNotFoundException {  
  39.         System.out.println("当前的用户名是:"+token.getName());  
  40.         /*这里我为了方便,就直接返回一个用户信息,实际当中这里修改为查询数据库或者调用服务什么的来获取用户信息*/  
  41.         UserInfo userInfo = new UserInfo();  
  42.         userInfo.setUsername("admin");  
  43.         userInfo.setName("admin");  
  44.         Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();  
  45.         AuthorityInfo authorityInfo = new AuthorityInfo("TEST");  
  46.         authorities.add(authorityInfo);  
  47.         userInfo.setAuthorities(authorities);  
  48.         return userInfo;  
  49.     }  
  50.   
  51. }  

      (3)定义AuthorityInfo类,用于加载当前登录用户的权限信息,实现GrantedAuthority接口,代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot.custom;  
  2.   
  3. import org.springframework.security.core.GrantedAuthority;  
  4.   
  5. /** 
  6.  * 权限信息 
  7.  *  
  8.  * @author ChengLi 
  9.  * 
  10.  */  
  11. public class AuthorityInfo implements GrantedAuthority {  
  12.     private static final long serialVersionUID = -175781100474818800L;  
  13.   
  14.     /** 
  15.      * 权限CODE 
  16.      */  
  17.     private String authority;  
  18.   
  19.     public AuthorityInfo(String authority) {  
  20.         this.authority = authority;  
  21.     }  
  22.   
  23.     @Override  
  24.     public String getAuthority() {  
  25.         return authority;  
  26.     }  
  27.   
  28.     public void setAuthority(String authority) {  
  29.         this.authority = authority;  
  30.     }  
  31.   
  32. }  

      (4)定义UserInfo类,用于加载当前用户信息,实现UserDetails接口,代码如下:
[java]  view plain  copy
  1. package com.chengli.springboot.custom;  
  2.   
  3. import java.util.Collection;  
  4. import java.util.HashSet;  
  5. import java.util.Set;  
  6.   
  7. import org.springframework.security.core.GrantedAuthority;  
  8. import org.springframework.security.core.userdetails.UserDetails;  
  9.   
  10. /** 
  11.  * 用户信息 
  12.  * @、这里我写了几个较为常用的字段,id,name,username,password,可以根据实际的情况自己增加 
  13.  * @author ChengLi 
  14.  * 
  15.  */  
  16. public class UserInfo implements UserDetails {  
  17.     private static final long serialVersionUID = -1041327031937199938L;  
  18.   
  19.     /** 
  20.      * 用户ID 
  21.      */  
  22.     private Long id;  
  23.   
  24.     /** 
  25.      * 用户名称 
  26.      */  
  27.     private String name;  
  28.   
  29.     /** 
  30.      * 登录名称 
  31.      */  
  32.     private String username;  
  33.   
  34.     /** 
  35.      * 登录密码 
  36.      */  
  37.     private String password;  
  38.   
  39.     private boolean isAccountNonExpired = true;  
  40.   
  41.     private boolean isAccountNonLocked = true;  
  42.   
  43.     private boolean isCredentialsNonExpired = true;  
  44.   
  45.     private boolean isEnabled = true;  
  46.   
  47.     private Set<AuthorityInfo> authorities = new HashSet<AuthorityInfo>();  
  48. ....省略getters setters 方法  
  49. }  

到这里基本就已经完成了,运行CAS Server ,将以上的application.properties文件中的地址修改为实际的地址即可运行。

参考:
https://github.com/xuanbo/spring-boot-cas-client

相关 [spring boot spring] 推荐:

spring boot与spring batch、postgres及elasticsearch整合

- - 互联网 - ITeye博客
当系统有大量数据需要从数据库导入elasticsearch时,使用sping batch可以提高导入的效率. 这篇文章使用spring batch将数据从postgres导入elasticsearch. 本文使用spring data jest连接ES(也可以使用spring data elasticsearch连接ES),ES版本为5.5.3.

Spring boot传统部署

- - 企业架构 - ITeye博客
使用spring boot很方便,一个jar包就可以启动了,因为它里面内嵌了tomcat等服务器. 但是spring boot也提供了部署到独立服务器的方法. 如果你看文档的话,从jar转换为war包很简单,pom.xml的配置修改略去不讲. 只看source的修改,很简单,只要一个配置类,继承自SpringBootServletInitializer, 并覆盖configure方法.

值得使用的Spring Boot

- - ImportNew
2013年12月12日,Spring发布了4.0版本. 这个本来只是作为Java平台上的控制反转容器的库,经过将近10年的发展已经成为了一个巨无霸产品. 不过其依靠良好的分层设计,每个功能模块都能保持较好的独立性,是Java平台不可多得的好用的开源应用程序框架. Spring的4.0版本可以说是一个重大的更新,其全面支持Java8,并且对Groovy语言也有良好的支持.

Spring Boot配置多个DataSource

- - 廖雪峰的官方网站
使用Spring Boot时,默认情况下,配置 DataSource非常容易. Spring Boot会自动为我们配置好一个 DataSource. 如果在 application.yml中指定了 spring.datasource的相关配置,Spring Boot就会使用该配置创建一个 DataSource.

Spring boot executable jar/war 原理

- - ImportNew
spring boot里其实不仅可以直接以 Java -jar demo.jar的方式启动,还可以把jar/war变为一个可以执行的脚本来启动,比如./demo.jar. 把这个executable jar/war 链接到/etc/init.d下面,还可以变为Linux下的一个service. 只要在spring boot maven plugin里配置:.

Spring Boot Starter是什么?

- - 技术,永无止境
在工作中我们经常能看到各种各样的springboot starter,如spring-cloud-netflix、spring-cloud-alibaba等等. 这些starter究竟有什么作用呢. 在了解这些starter之前,我们需要先大概知道Spring MVC与Spring Boot的关系.

SPRING BOOT OAUTH2 + KEYCLOAK - service to service call

- - BlogJava-首页技术区
employee-service调用department-service,如果要按OAUTH2.0流程,只需要提供client-id和client-secrect即可. 在KEYCLOAK中引入service-account,即配置该employee-service时,取消standard-flow,同时激活service-account.

Spring Boot使用redis做数据缓存

- - ITeye博客
SysUser.class)); //请注意这里. 3 redis服务器配置. /** *此处的dao操作使用的是spring data jpa,使用@Cacheable可以在任意方法上,*比如@Service或者@Controller的方法上 */ public interface SysUserRepo1 extends CustomRepository {.

spring boot应用启动原理分析

- - ImportNew
在spring boot里,很吸引人的一个特性是可以直接把应用打包成为一个jar/war,然后这个jar/war是可以直接启动的,不需要另外配置一个Web Server. 如果之前没有使用过spring boot可以通过下面的demo来感受下. 下面以这个工程为例,演示如何启动Spring boot项目:.

Apache Shiro和Spring boot的结合使用

- - 企业架构 - ITeye博客
实际上在Spring boot里用Spring Security最合适,毕竟是自家东西,最重要的一点是Spring Security里自带有csrf filter,防止csrf攻击,shiro里就没有. 但是Spring Security有点太复杂,custmize起来比较费力,不如shiro来的简单.