赞
踩
微服务的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 的应用程序的事实上的标准
1、创建一个 springboot Module 服务提供者 springcloud-11-service-security-provider
2、添加 spring-boot-starter-security等 依赖
- <!--spring-boot-starter-security-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
- <!--继承统一的父项目-->
- <parent>
- <groupId>com.company</groupId>
- <artifactId>springcloud-demo</artifactId>
- <version>1.0.0</version>
- </parent>
-
- <groupId>com.company</groupId>
- <artifactId>springcloud-11-service-security-provider</artifactId>
- <version>1.0.0</version>
-
- <name>springcloud-11-service-security-provider</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <!--spring web 起步依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!-- MySQL的jdbc驱动包 -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
-
- <!--mybatis起步依赖-->
- <dependency>
- <groupId>org.mybatis.spring.boot</groupId>
- <artifactId>mybatis-spring-boot-starter</artifactId>
- <version>2.2.2</version>
- </dependency>
-
- <!--依赖统一的springcloud-service-commons项目-->
- <dependency>
- <groupId>com.company</groupId>
- <artifactId>springcloud-2-service-common</artifactId>
- <version>1.0.0</version>
- </dependency>
-
- <!-- springboot 开发自动热部署 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <optional>true</optional>
- </dependency>
-
- <!--spring-cloud-starter-netflix-eureka-client-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
-
- <!--spring-boot-starter-security-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- </dependencies>
-
- <build>
-
- <!--处理资源目录-->
- <resources>
- <resource>
- <directory>src/main/java</directory>
- <includes>
- <include>**/*.xml</include>
- </includes>
- </resource>
-
- <resource>
- <directory>src/main/resources</directory>
- <includes>
- <include>**/*.*</include>
- </includes>
- </resource>
- </resources>
-
- <plugins>
-
- <!--spring boot提供的编译、打包的Maven插件-->
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
3、application.properties配置文件中添加安全认证账号密码
- #安全认证;配置访问账号和密码
- spring.security.user.name=admin
- spring.security.user.password=123456
- server.port=9001
-
- #设置应用名称,对应Eureka控制台下 DS Replicas 的 Application
- spring.application.name=springcloud-11-service-security-provider
-
- #设置mysql数据库连接信息
- spring.datasource.url=jdbc:mysql://localhost:3306/springcloud?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
- spring.datasource.username=root
- spring.datasource.password=admin123456
-
- #每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活”
- eureka.instance.lease-renewal-interval-in-seconds=5
- #告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出
- eureka.instance.lease-expiration-duration-in-seconds=10
- #告诉服务端,服务实例以IP作为链接,不是取机器名
- eureka.instance.prefer-ip-address=false
-
- #注册服务实例名称
- eureka.instance.instance-id=springcloud-11-service-security-provider
- #注册中心的链接地址
- eureka.client.service-url.defaultZone=http://localhost:8761/eureka
-
-
- #安全认证;配置访问账号和密码
- spring.security.user.name=admin
- spring.security.user.password=123456
4、创建 controller,mapper,model等文件基于RESTFUL风格访问
- @RestController
- public class GoodsController {
-
- @Autowired
- private GoodsService goodsService;
-
- @GetMapping(value = "/eureka/security/goodList")
- public List<Goods> goodList(){
- List<Goods> goodsList = goodsService.getAllGoods();
-
- System.out.println("查询商品列表成功:");
- for (Goods good:goodsList) {
- System.out.println("查询商品:"+ good);
- }
- return goodsList;
- }
- }
5、启动springboot 启动类,输入 http://localhost:9001/eureka/security/goodList
访问,首先会进入安全登录页,输入账号密码即可访问
注:
在这里,遇到一个坑,因为刚开始复制的 Sleuth + Zipkin 模块的项目,因此运行 导致只能访问一次,应该是 Spring CLoud内部版本之间有点冲突,去掉 Sleuth + Zipkin 依赖即可
当远程的服务提供者使用了 密码安全验证,此时服务的消费方如果想直接访问服务提供者就不能访问,需要对服务消费者 进行配置处理
1、创建一个 springboot Module 服务消费者 springcloud-11-service-security-consumer
2、pom.xml文件如下:
- <!--继承统一的父项目-->
- <parent>
- <groupId>com.company</groupId>
- <artifactId>springcloud-demo</artifactId>
- <version>1.0.0</version>
- <!-- <relativePath/> <!– lookup parent from repository –>-->
- </parent>
-
- <groupId>com.company</groupId>
- <artifactId>springcloud-11-service-security-consumer</artifactId>
- <version>1.0.0</version>
-
- <name>springcloud-11-service-security-consumer</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <!--spring web 起步依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!--依赖统一的springcloud-service-commons项目-->
- <dependency>
- <groupId>com.company</groupId>
- <artifactId>springcloud-2-service-common</artifactId>
- <version>1.0.0</version>
- </dependency>
-
- <!-- springboot 开发自动热部署 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <optional>true</optional>
- </dependency>
-
- <!--spring-cloud-starter-netflix-eureka-client-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
3、application.properties配置文件
server.port=8081 #设置应用名称,对应Eureka控制台下 DS Replicas 的 Application spring.application.name=springcloud-11-service-security-consumer #每间隔5s,向Eureka服务注册中心发送一次心跳,证明服务是否依然“存活” eureka.instance.lease-renewal-interval-in-seconds=30 #告诉服务端,如果10s之内没有发送心跳,就代表故障,将本服务踢出 eureka.instance.lease-expiration-duration-in-seconds=60 #告诉服务端,服务实例以IP作为链接,不是取机器名 eureka.instance.prefer-ip-address=false #注册服务实例名称 eureka.instance.instance-id=springcloud-11-service-security-consumer #注册中心的链接地址 #eureka.client.service-url.defaultZone=http://localhost:8761/eureka eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
4、 在RestConfig配置类中添加 HttpHeaders(org.springframework.http.HttpHeaders)
- @Configuration
- public class RestConfig {
-
- //使用Ribbon实现负载均衡的调用
- @LoadBalanced
- @Bean
- public RestTemplate restTemplate () {
- return new RestTemplate();
- }
-
- /**
- * 进行 Http头信息配置实现安全认证
- */
- @Bean
- public HttpHeaders getHeaders(){
- //定义 HTTP 头部信息
- HttpHeaders headers = new HttpHeaders();
- /*
- 认证的账户密码
- 服务提供者 application.properties 配置文件中 安全认证配置的访问账号和密码
- spring.security.user.name=admin
- spring.security.user.password=123456
- * */
- String auth = "admin:123456";
-
- //加密处理
- byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
- String authHeader = "Basic " + new String(encodedAuth);
- headers.set("Authorization", authHeader);
- return headers;
- }
- }
5、在controller中调用的地方注入该HttpHeaders,且传入这个http头信息
- @RestController
- public class GoodsController {
- private final String GOODS_SERVICE_URL = "http://localhost:9001/service/goodList";
-
- private final String GOODS_SERVICE_EUREKA_URL = "http://springcloud-11-service-security-provider/eureka/security/goodList";
-
- @Autowired
- private RestTemplate restTemplate;
-
- //HttpHeaders这个bean注入到controller中
- @Autowired
- private HttpHeaders httpHeaders;
-
- @GetMapping(value = "/springcloud/security/goodList")
- public @ResponseBody Object getGoodList(){
- //调用远程的一个controller(Restful风格调用)
- ResponseEntity<Object> responseEntity = restTemplate.exchange(GOODS_SERVICE_EUREKA_URL, HttpMethod.GET, new HttpEntity<Object>(httpHeaders),Object.class);
-
- return responseEntity.getBody();
- }
- }
6、依次启动Eureka,服务提供者,服务消费者 访问
http://localhost:8081/springcloud/security/goodList
注:
eureka中也配置了安全认证
eureka中application.properties
-
- #指定服务注册中心的位置 eureka.client.service-url.defaultZone=http://localhost:8761/eureka
- #eureka.client.service-url.defaultZone=http://localhost:8761/eureka
- eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
-
-
- #安全认证;配置访问config配置中心的访问账号和密码
- spring.security.user.name=admin
- spring.security.user.password=123456
提供者中
- eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
-
-
- #安全认证;配置访问账号和密码
- spring.security.user.name=admin
- spring.security.user.password=123456
消费者中
- #注册服务实例名称
- eureka.instance.instance-id=springcloud-11-service-security-consumer
- #注册中心的链接地址
- #eureka.client.service-url.defaultZone=http://localhost:8761/eureka
- eureka.client.service-url.defaultZone=http://admin:123456@localhost:8761/eureka
1、 在 springcloud-2-service-common 公共模块新增一个 FeignConfiguration 配置类
- @Configuration
- public class FeignConfiguration {
-
- //@RequestLine("GET /eureka/security/goodList")
-
- /**
- * 一种契约,采用feign的契约方式,如果不配置该bean,会转成SpringMVC的方式
- */
- /*@Bean
- public Contract feignContract(){
- return new Contract.Default();
- }*/
-
- @Bean
- public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
- //传用户名和密码
- return new BasicAuthRequestInterceptor("admin","123456");
- }
- }
2、 新增一个 服务声明接口 ProviderSecurityGoodsRemoteClient
- @Component
- @FeignClient(value = "springcloud-11-service-security-provider",
- /*fallback = HystrixProviderGoodsRemoteClientFallBack.class,*/
- fallbackFactory = HystrixProviderGoodsRemoteClientFallBackFactory.class,
- configuration = FeignConfiguration.class)
- public interface ProviderSecurityGoodsRemoteClient {
-
- /**
- * 声明一个feign的接口,它的实现是服务提供者的controller实现
- */
- @GetMapping(value = "/eureka/security/goodList")
- public List<Goods> goods();
- }
3、服务消费者引入依赖
- <dependencies>
- <!--spring web 起步依赖-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!--依赖统一的springcloud-service-commons项目-->
- <dependency>
- <groupId>com.company</groupId>
- <artifactId>springcloud-2-service-common</artifactId>
- <version>1.0.0</version>
- </dependency>
-
- <!-- springboot 开发自动热部署 -->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-devtools</artifactId>
- <optional>true</optional>
- </dependency>
-
- <!--spring-cloud-starter-netflix-eureka-client-->
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
-
- </dependencies>
4、消费者启动类添加注解
- @EnableFeignClients //表示开启 Spring Cloud OpenFeign的支持功能
- @EnableEurekaClient //开启 Eureka client服务
- @SpringBootApplication
- public class Security11ConsumerApplication {
- public static void main(String[] args) {
- SpringApplication.run(Security11ConsumerApplication.class, args);
- }
- }
5、消费者controller调用
- @RestController
- public class GoodsController {
-
- @Autowired
- private ProviderSecurityGoodsRemoteClient providerSecurityGoodsRemoteClient;
-
-
- @GetMapping(value = "/springcloud/security/openfeign/goodList")
- public @ResponseBody Object getGoodListOpenFeign(){
-
- // 调用远程的一个controller, restful的调用,通过openfeign这种声明式的远程调用,providerGoodsRemoteClient就像dubbo里面的接口层一样
- return providerSecurityGoodsRemoteClient.goods();
- }
- }
浏览器输入http://localhost:8081/springcloud/security/openfeign/goodList
注:
在这里,遇到一个坑,因为刚开始复制的 Sleuth + Zipkin 模块的项目,因此运行 导致只能访问一次,应该是 Spring CLoud内部版本之间有点冲突,去掉 Sleuth + Zipkin 依赖即可
在实际项目开发中,服务一般会非常多,绝大多数服务都需要用到安全验证,账户密码基本一样,如果每个服务都单独配置安全认证,繁琐重复劳动不是我们提倡的,因此单独建立一个安全服务验证的项目,其他微服务如果需要安全认证就引入该项目的依赖即可
1、新建一个模块 springcloud-11-service-security-auth
2、添加 spring-boot-starter-security 依赖
- <!--继承统一的父项目-->
- <parent>
- <groupId>com.company</groupId>
- <artifactId>springcloud-demo</artifactId>
- <version>1.0.0</version>
- </parent>
-
- <groupId>com.company</groupId>
- <artifactId>springcloud-11-service-security-auth</artifactId>
- <version>1.0.0</version>
-
- <name>springcloud-11-service-security-auth</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
-
- <!--spring-boot-starter-security-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
3、新增配置类 WebSecurityConfiguration
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
- 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.config.http.SessionCreationPolicy;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-
- @Configuration
- @EnableWebSecurity
- public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
- @Override
- public void configure(AuthenticationManagerBuilder auth) throws Exception{
- auth.inMemoryAuthentication()
- .passwordEncoder(new BCryptPasswordEncoder())
- .withUser("admin")
- .password(new BCryptPasswordEncoder().encode("123456"))
- .roles("USER","ADMIN")
- .and()
- .withUser("root")
- .password(new BCryptPasswordEncoder().encode("123456"))
- .roles("USER","ROOT");
- }
-
- @Override
- public void configure(HttpSecurity httpSecurity) throws Exception{
- httpSecurity.httpBasic().and().authorizeRequests().anyRequest().fullyAuthenticated();
- httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
- //把csrf拦截置为不可用,401问题
- httpSecurity.csrf().disable();
- }
- }
4、在服务提供者模块中引入本模块依赖,启动运行测试即可
- <!--微服务统一安全认证依赖-->
- <dependency>
- <groupId>com.company</groupId>
- <artifactId>springcloud-11-service-security-auth</artifactId>
- </dependency>
这里的UI界面会和之前有些区别
1、之前界面是spring封装的security
2、当前是使用的security自己的jar包
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。