当前位置:   article > 正文

SpringCloud - Spring Cloud 之 Security服务安全机制(二十)_springcloudsecurity

springcloudsecurity

阅读本文前可先参考

​​​​​​SpringCloud - Spring Cloud根/父项目,开发准备(二)_MinggeQingchun的博客-CSDN博客

Spring Security

微服务的Rest服务都是基于http请求的,因此很有可能暴露在公网上,任何人都可能调用访问,如果Rest服务有一些私密信息,就会导致信息的泄露,因此我们需要给微服务增加安全机制。如:Spring Security

Spring Security 是 Spring Resource 社区的一个安全组件, Spring Security 为 JavaEE 企业开发提供了全面的安全防护。

Spring Security 采用“安全层”的概念,使每一层都尽可能安全,连续的安全层可以达到全面的防护

Spring Seeurity 可以在 Controller 层、 Service 层、 DAO 层等以加注解的方式来保护应用程序的安全。

Spring Security 提供了细粒度的权限控制,可以精细到每一个 API 接口、每一个业务的方法,或者每一个操作数据库的 DAO 层的方法。

Spring Security 提供的是应用程序层的安全解决方案,一个系统的安全还需要考虑传输层和系统层的安全,例如采用 Htpps 协议、服务器部署防火墙等。

Spring Security 是一个提供身份验证、授权和针对常见攻击的保护的框架。凭借对保护命令式和反应式应用程序的一流支持,它是保护基于 Spring 的应用程序的事实上的标准

一、服务提供者集成 Security 安全认证

1、创建一个 springboot Module 服务提供者 springcloud-11-service-security-provider

  

2、添加 spring-boot-starter-security等 依赖

  1. <!--spring-boot-starter-security-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-security</artifactId>
  5. </dependency>
  1. <!--继承统一的父项目-->
  2. <parent>
  3. <groupId>com.company</groupId>
  4. <artifactId>springcloud-demo</artifactId>
  5. <version>1.0.0</version>
  6. </parent>
  7. <groupId>com.company</groupId>
  8. <artifactId>springcloud-11-service-security-provider</artifactId>
  9. <version>1.0.0</version>
  10. <name>springcloud-11-service-security-provider</name>
  11. <description>Demo project for Spring Boot</description>
  12. <properties>
  13. <java.version>1.8</java.version>
  14. </properties>
  15. <dependencies>
  16. <!--spring web 起步依赖-->
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-web</artifactId>
  20. </dependency>
  21. <!-- MySQL的jdbc驱动包 -->
  22. <dependency>
  23. <groupId>mysql</groupId>
  24. <artifactId>mysql-connector-java</artifactId>
  25. </dependency>
  26. <!--mybatis起步依赖-->
  27. <dependency>
  28. <groupId>org.mybatis.spring.boot</groupId>
  29. <artifactId>mybatis-spring-boot-starter</artifactId>
  30. <version>2.2.2</version>
  31. </dependency>
  32. <!--依赖统一的springcloud-service-commons项目-->
  33. <dependency>
  34. <groupId>com.company</groupId>
  35. <artifactId>springcloud-2-service-common</artifactId>
  36. <version>1.0.0</version>
  37. </dependency>
  38. <!-- springboot 开发自动热部署 -->
  39. <dependency>
  40. <groupId>org.springframework.boot</groupId>
  41. <artifactId>spring-boot-devtools</artifactId>
  42. <optional>true</optional>
  43. </dependency>
  44. <!--spring-cloud-starter-netflix-eureka-client-->
  45. <dependency>
  46. <groupId>org.springframework.cloud</groupId>
  47. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  48. </dependency>
  49. <!--spring-boot-starter-security-->
  50. <dependency>
  51. <groupId>org.springframework.boot</groupId>
  52. <artifactId>spring-boot-starter-security</artifactId>
  53. </dependency>
  54. </dependencies>
  55. <build>
  56. <!--处理资源目录-->
  57. <resources>
  58. <resource>
  59. <directory>src/main/java</directory>
  60. <includes>
  61. <include>**/*.xml</include>
  62. </includes>
  63. </resource>
  64. <resource>
  65. <directory>src/main/resources</directory>
  66. <includes>
  67. <include>**/*.*</include>
  68. </includes>
  69. </resource>
  70. </resources>
  71. <plugins>
  72. <!--spring boot提供的编译、打包的Maven插件-->
  73. <plugin>
  74. <groupId>org.springframework.boot</groupId>
  75. <artifactId>spring-boot-maven-plugin</artifactId>
  76. </plugin>
  77. </plugins>
  78. </build>

3、application.properties配置文件中添加安全认证账号密码

  1. #安全认证;配置访问账号和密码
  2. spring.security.user.name=admin
  3. spring.security.user.password=123456
  1. server.port=9001
  2. #设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
  3. spring.application.name=springcloud-11-service-security-provider
  4. #设置mysql数据库连接信息
  5. spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
  6. spring.datasource.username=root
  7. spring.datasource.password=admin123456
  8. #每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
  9. eureka.instance.lease-renewal-interval-in-seconds=5
  10. #告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
  11. eureka.instance.lease-expiration-duration-in-seconds=10
  12. #告诉服务端,服务实例以IP作为链接,不是取机器名
  13. eureka.instance.prefer-ip-address=false
  14. #注册服务实例名称
  15. eureka.instance.instance-id=springcloud-11-service-security-provider
  16. #注册中心的链接地址
  17. eureka.client.service-url.defaultZone=http://localhost:8761/eureka
  18. #安全认证;配置访问账号和密码
  19. spring.security.user.name=admin
  20. spring.security.user.password=123456

4、创建 controller,mapper,model等文件基于RESTFUL风格访问

  1. @RestController
  2. public class GoodsController {
  3. @Autowired
  4. private GoodsService goodsService;
  5. @GetMapping(value = "/eureka/security/goodList")
  6. public List<Goods> goodList(){
  7. List<Goods> goodsList = goodsService.getAllGoods();
  8. System.out.println("查询商品列表成功:");
  9. for (Goods good:goodsList) {
  10. System.out.println("查询商品:"+ good);
  11. }
  12. return goodsList;
  13. }
  14. }

5、启动springboot 启动类,输入 http://localhost:9001/eureka/security/goodList

访问,首先会进入安全登录页,输入账号密码即可访问

注:

在这里,遇到一个坑,因为刚开始复制的 Sleuth + Zipkin 模块的项目,因此运行 导致只能访问一次,应该是 Spring CLoud内部版本之间有点冲突,去掉 Sleuth + Zipkin 依赖即可

二、服务消费者集成 Security 安全认证

当远程的服务提供者使用了 密码安全验证,此时服务的消费方如果想直接访问服务提供者就不能访问,需要对服务消费者 进行配置处理

1、RestTemplate 调用

1、创建一个 springboot Module 服务消费者 springcloud-11-service-security-consumer

2、pom.xml文件如下:

  1. <!--继承统一的父项目-->
  2. <parent>
  3. <groupId>com.company</groupId>
  4. <artifactId>springcloud-demo</artifactId>
  5. <version>1.0.0</version>
  6. <!-- <relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
  7. </parent>
  8. <groupId>com.company</groupId>
  9. <artifactId>springcloud-11-service-security-consumer</artifactId>
  10. <version>1.0.0</version>
  11. <name>springcloud-11-service-security-consumer</name>
  12. <description>Demo project for Spring Boot</description>
  13. <properties>
  14. <java.version>1.8</java.version>
  15. </properties>
  16. <dependencies>
  17. <!--spring web 起步依赖-->
  18. <dependency>
  19. <groupId>org.springframework.boot</groupId>
  20. <artifactId>spring-boot-starter-web</artifactId>
  21. </dependency>
  22. <!--依赖统一的springcloud-service-commons项目-->
  23. <dependency>
  24. <groupId>com.company</groupId>
  25. <artifactId>springcloud-2-service-common</artifactId>
  26. <version>1.0.0</version>
  27. </dependency>
  28. <!-- springboot 开发自动热部署 -->
  29. <dependency>
  30. <groupId>org.springframework.boot</groupId>
  31. <artifactId>spring-boot-devtools</artifactId>
  32. <optional>true</optional>
  33. </dependency>
  34. <!--spring-cloud-starter-netflix-eureka-client-->
  35. <dependency>
  36. <groupId>org.springframework.cloud</groupId>
  37. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  38. </dependency>
  39. </dependencies>
  40. <build>
  41. <plugins>
  42. <plugin>
  43. <groupId>org.springframework.boot</groupId>
  44. <artifactId>spring-boot-maven-plugin</artifactId>
  45. </plugin>
  46. </plugins>
  47. </build>

3、application.properties配置文件

  1. server.port=8081
  2. #设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
  3. spring.application.name=springcloud-11-service-security-consumer
  4. #每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
  5. eureka.instance.lease-renewal-interval-in-seconds=30
  6. #告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
  7. eureka.instance.lease-expiration-duration-in-seconds=60
  8. #告诉服务端,服务实例以IP作为链接,不是取机器名
  9. eureka.instance.prefer-ip-address=false
  10. #注册服务实例名称
  11. eureka.instance.instance-id=springcloud-11-service-security-consumer
  12. #注册中心的链接地址
  13. #eureka.client.service-url.defaultZone=http://localhost:8761/eureka
  14. eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka

4、 在RestConfig配置类中添加 HttpHeaders(org.springframework.http.HttpHeaders)

  1. @Configuration
  2. public class RestConfig {
  3. //使用Ribbon实现负载均衡的调用
  4. @LoadBalanced
  5. @Bean
  6. public RestTemplate restTemplate () {
  7. return new RestTemplate();
  8. }
  9. /**
  10. * 进行 Http头信息配置实现安全认证
  11. */
  12. @Bean
  13. public HttpHeaders getHeaders(){
  14. //定义 HTTP 头部信息
  15. HttpHeaders headers = new HttpHeaders();
  16. /*
  17. 认证的账户密码
  18. 服务提供者 application.properties 配置文件中 安全认证配置的访问账号和密码
  19. spring.security.user.name=admin
  20. spring.security.user.password=123456
  21. * */
  22. String auth = "admin:123456";
  23. //加密处理
  24. byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
  25. String authHeader = "Basic " + new String(encodedAuth);
  26. headers.set("Authorization", authHeader);
  27. return headers;
  28. }
  29. }

5、在controller中调用的地方注入该HttpHeaders,且传入这个http头信息

  1. @RestController
  2. public class GoodsController {
  3. private final String GOODS_SERVICE_URL = "http://localhost:9001/service/goodList";
  4. private final String GOODS_SERVICE_EUREKA_URL = "http://springcloud-11-service-security-provider/eureka/security/goodList";
  5. @Autowired
  6. private RestTemplate restTemplate;
  7. //HttpHeaders这个bean注入到controller中
  8. @Autowired
  9. private HttpHeaders httpHeaders;
  10. @GetMapping(value = "/springcloud/security/goodList")
  11. public @ResponseBody Object getGoodList(){
  12. //调用远程的一个controller(Restful风格调用)
  13. ResponseEntity<Object> responseEntity = restTemplate.exchange(GOODS_SERVICE_EUREKA_URL, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),Object.class);
  14. return responseEntity.getBody();
  15. }
  16. }

6、依次启动Eureka,服务提供者,服务消费者 访问

http://localhost:8081/springcloud/security/goodList

注:

eureka中也配置了安全认证 

eureka中application.properties

  1. #指定服务注册中心的位置 eureka.client.service-url.defaultZone=http://localhost:8761/eureka
  2. #eureka.client.service-url.defaultZone=http://localhost:8761/eureka
  3. eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
  4. #安全认证;配置访问config配置中心的访问账号和密码
  5. spring.security.user.name=admin
  6. spring.security.user.password=123456

提供者中

  1. eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
  2. #安全认证;配置访问账号和密码
  3. spring.security.user.name=admin
  4. spring.security.user.password=123456

消费者中

  1. #注册服务实例名称
  2. eureka.instance.instance-id=springcloud-11-service-security-consumer
  3. #注册中心的链接地址
  4. #eureka.client.service-url.defaultZone=http://localhost:8761/eureka
  5. eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka

2、OpenFeign 调用

1、 在 springcloud-2-service-common 公共模块新增一个 FeignConfiguration 配置类

  1. @Configuration
  2. public class FeignConfiguration {
  3. //@RequestLine("GET /eureka/security/goodList")
  4. /**
  5. * 一种契约,采用feign的契约方式,如果不配置该bean,会转成SpringMVC的方式
  6. */
  7. /*@Bean
  8. public Contract feignContract(){
  9. return new Contract.Default();
  10. }*/
  11. @Bean
  12. public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
  13. //传用户名和密码
  14. return new BasicAuthRequestInterceptor("admin","123456");
  15. }
  16. }

2、 新增一个 服务声明接口 ProviderSecurityGoodsRemoteClient 

  1. @Component
  2. @FeignClient(value = "springcloud-11-service-security-provider",
  3. /*fallback = HystrixProviderGoodsRemoteClientFallBack.class,*/
  4. fallbackFactory = HystrixProviderGoodsRemoteClientFallBackFactory.class,
  5. configuration = FeignConfiguration.class)
  6. public interface ProviderSecurityGoodsRemoteClient {
  7. /**
  8. * 声明一个feign的接口,它的实现是服务提供者的controller实现
  9. */
  10. @GetMapping(value = "/eureka/security/goodList")
  11. public List<Goods> goods();
  12. }

3、服务消费者引入依赖

  1. <dependencies>
  2. <!--spring web 起步依赖-->
  3. <dependency>
  4. <groupId>org.springframework.boot</groupId>
  5. <artifactId>spring-boot-starter-web</artifactId>
  6. </dependency>
  7. <!--依赖统一的springcloud-service-commons项目-->
  8. <dependency>
  9. <groupId>com.company</groupId>
  10. <artifactId>springcloud-2-service-common</artifactId>
  11. <version>1.0.0</version>
  12. </dependency>
  13. <!-- springboot 开发自动热部署 -->
  14. <dependency>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-devtools</artifactId>
  17. <optional>true</optional>
  18. </dependency>
  19. <!--spring-cloud-starter-netflix-eureka-client-->
  20. <dependency>
  21. <groupId>org.springframework.cloud</groupId>
  22. <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
  23. </dependency>
  24. </dependencies>

4、消费者启动类添加注解

  1. @EnableFeignClients //表示开启 Spring Cloud OpenFeign的支持功能
  2. @EnableEurekaClient //开启 Eureka client服务
  3. @SpringBootApplication
  4. public class Security11ConsumerApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(Security11ConsumerApplication.class, args);
  7. }
  8. }

5、消费者controller调用

  1. @RestController
  2. public class GoodsController {
  3. @Autowired
  4. private ProviderSecurityGoodsRemoteClient providerSecurityGoodsRemoteClient;
  5. @GetMapping(value = "/springcloud/security/openfeign/goodList")
  6. public @ResponseBody Object getGoodListOpenFeign(){
  7. // 调用远程的一个controller, restful的调用,通过openfeign这种声明式的远程调用,providerGoodsRemoteClient就像dubbo里面的接口层一样
  8. return providerSecurityGoodsRemoteClient.goods();
  9. }
  10. }

浏览器输入http://localhost:8081/springcloud/security/openfeign/goodList

注:

在这里,遇到一个坑,因为刚开始复制的 Sleuth + Zipkin 模块的项目,因此运行 导致只能访问一次,应该是 Spring CLoud内部版本之间有点冲突,去掉 Sleuth + Zipkin 依赖即可

三、安全服务模块/项目

在实际项目开发中,服务一般会非常多,绝大多数服务都需要用到安全验证,账户密码基本一样,如果每个服务都单独配置安全认证,繁琐重复劳动不是我们提倡的,因此单独建立一个安全服务验证的项目,其他微服务如果需要安全认证就引入该项目的依赖即可

1、新建一个模块 springcloud-11-service-security-auth

2、添加 spring-boot-starter-security 依赖

  1. <!--继承统一的父项目-->
  2. <parent>
  3. <groupId>com.company</groupId>
  4. <artifactId>springcloud-demo</artifactId>
  5. <version>1.0.0</version>
  6. </parent>
  7. <groupId>com.company</groupId>
  8. <artifactId>springcloud-11-service-security-auth</artifactId>
  9. <version>1.0.0</version>
  10. <name>springcloud-11-service-security-auth</name>
  11. <description>Demo project for Spring Boot</description>
  12. <properties>
  13. <java.version>1.8</java.version>
  14. </properties>
  15. <dependencies>
  16. <!--spring-boot-starter-security-->
  17. <dependency>
  18. <groupId>org.springframework.boot</groupId>
  19. <artifactId>spring-boot-starter-security</artifactId>
  20. </dependency>
  21. </dependencies>
  22. <build>
  23. <plugins>
  24. <plugin>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-maven-plugin</artifactId>
  27. </plugin>
  28. </plugins>
  29. </build>

3、新增配置类 WebSecurityConfiguration

  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  3. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  4. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  6. import org.springframework.security.config.http.SessionCreationPolicy;
  7. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  8. @Configuration
  9. @EnableWebSecurity
  10. public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  11. @Override
  12. public void configure(AuthenticationManagerBuilder auth) throws Exception{
  13. auth.inMemoryAuthentication()
  14. .passwordEncoder(new BCryptPasswordEncoder())
  15. .withUser("admin")
  16. .password(new BCryptPasswordEncoder().encode("123456"))
  17. .roles("USER","ADMIN")
  18. .and()
  19. .withUser("root")
  20. .password(new BCryptPasswordEncoder().encode("123456"))
  21. .roles("USER","ROOT");
  22. }
  23. @Override
  24. public void configure(HttpSecurity httpSecurity) throws Exception{
  25. httpSecurity.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated();
  26. httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  27. //把csrf拦截置为不可用,401问题
  28. httpSecurity.csrf().disable();
  29. }
  30. }

4、在服务提供者模块中引入本模块依赖,启动运行测试即可

  1. <!--微服务统一安全认证依赖-->
  2. <dependency>
  3. <groupId>com.company</groupId>
  4. <artifactId>springcloud-11-service-security-auth</artifactId>
  5. </dependency>

 这里的UI界面会和之前有些区别

1、之前界面是spring封装的security

2、当前是使用的security自己的jar包

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/185321
推荐阅读
相关标签
  

闽ICP备14008679号