在我们实际生产环境中,都需要考虑到一个安全问题,比如用户登录,又或者是eureka server,它对外暴露的有自己的rest API,如果没有安全认证,也就意味着别人可以通过rest API随意修改数据信息,这是一件非常恐怖的事情,这篇文章咱们详谈eureka server是如何开启认证,以及eureka client是如何配置鉴权信息。
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --></parent><properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Finchley.RELEASE</spring-cloud.version></properties><dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>
1.1、eureka server工程pom:
<!--加上文章头部的公共依赖-->
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
<!--权限依赖,只要pom文件有这个依赖,项目默认就已经开启了权限校验--> <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>
1.2、eureka server工程启动类:
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication@EnableEurekaServerpublic class EurkeaServerApplication { public static void main(String[] args) { SpringApplication.run(EurkeaServerApplication.class, args); }}
1.3、eureka server工程配置文件,路径:eureka-server\src\main\resources\
application-security.yml:
server: port: 8761spring: security: basic: enabled: true user: name: admin password: Xk38CNHigBP5jK75eureka: instance: hostname: localhost client: registerWithEureka: false fetchRegistry: false serviceUrl: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ server: waitTimeInMsWhenSyncEmpty: 0 enableSelfPreservation: false
application.yml:
spring: profiles: active: security
由于spring-boot-starter-security默认开启了CSRF校验,对于client端这类非界面应用来说,有些不合适,但是又没有配置文件的方式可以禁用,需要通过Java配置,进行禁用,如下:
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;/** * 关闭spring-boot-starter-security的CSRF校验 */@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { super.configure(http); http.csrf().disable(); }}
1.4、启动eureka server工程,执行命令:
mvn spring-boot:run
打开命令行终端,执行: curl -i http://localhost:8761/eureka/apps
curl -i http://localhost:8761/eureka/appsHTTP/1.1 401Set-Cookie: JSESSIONID=554BCAF092D8D1ED3936C0CB09E91AF1; Path=/; HttpOnlyWWW-Authenticate: Basic realm="Realm"X-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockCache-Control: no-cache, no-store, max-age=0, must-revalidatePragma: no-cacheExpires: 0X-Frame-Options: DENYContent-Type: application/json;charset=UTF-8Transfer-Encoding: chunkedDate: Fri, 04 Oct 2019 07:31:57 GMT{"timestamp":"2019-10-04T07:31:57.888+0000","status":401,"error":"Unauthorized","message":"Unauthorized","path":"/eureka/apps"}
可以看出,没有传递Authenticate的header,返回401状态码。
下面使用http basic的账号密码传递Authenticate的header:
curl -i --basic -u admin:Xk38CNHigBP5jK75 http://localhost:8761/eureka/appsHTTP/1.1 200Set-Cookie: JSESSIONID=CF1C0DE56415626494EC539A654CC543; Path=/; HttpOnlyX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockCache-Control: no-cache, no-store, max-age=0, must-revalidatePragma: no-cacheExpires: 0X-Frame-Options: DENYContent-Type: application/xmlTransfer-Encoding: chunkedDate: Fri, 04 Oct 2019 07:35:54 GMT<applications> <versions__delta>1</versions__delta> <apps__hashcode></apps__hashcode></applications>
请求成功。
2.1、eureka client工程pom:
<!--加上文章头部的公共依赖-->
<dependencies> <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>
2.2、eureka client工程启动类:
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication@EnableDiscoveryClientpublic class EurekaClientApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); }}
2.3、eureka client工程配置文件,路径:eureka-client\src\main\resources\
由于eureka server工程开启了http basic认证,eureka client工程也需要添加相应的账号信息来传递,这里我们通过配置文件来指定。
application-security.yml:
server: port: 8081spring: application: name: client1eureka: client: security: basic: user: admin password: Xk38CNHigBP5jK75 serviceUrl: defaultZone: http://${eureka.client.security.basic.user}:${eureka.client.security.basic.password}@localhost:8761/eureka/
application.yml:
spring: profiles: active: security
执行:curl -i --basic -u admin:Xk38CNHigBP5jK75 http://localhost:8761/eureka/apps
curl -i --basic -u admin:Xk38CNHigBP5jK75 http://localhost:8761/eureka/appsHTTP/1.1 200Set-Cookie: JSESSIONID=C7CE372067A44606E9D3DEA6B64AEDCD; Path=/; HttpOnlyX-Content-Type-Options: nosniffX-XSS-Protection: 1; mode=blockCache-Control: no-cache, no-store, max-age=0, must-revalidatePragma: no-cacheExpires: 0X-Frame-Options: DENYContent-Type: application/xmlTransfer-Encoding: chunkedDate: Fri, 04 Oct 2019 07:53:40 GMT<applications> <versions__delta>1</versions__delta> <apps__hashcode>UP_1_</apps__hashcode> <application> <name>CLIENT1</name> <instance> <instanceId>192.168.50.161:client1:8081</instanceId> <hostName>192.168.50.161</hostName> <app>CLIENT1</app> <ipAddr>192.168.50.161</ipAddr> <status>UP</status> <overriddenstatus>UNKNOWN</overriddenstatus> <port enabled="true">8081</port> <securePort enabled="false">443</securePort> <countryId>1</countryId> <dataCenterInfo class="com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo"> <name>MyOwn</name> </dataCenterInfo> <leaseInfo> <renewalIntervalInSecs>30</renewalIntervalInSecs> <durationInSecs>90</durationInSecs> <registrationTimestamp>1570175584067</registrationTimestamp> <lastRenewalTimestamp>1570175584067</lastRenewalTimestamp> <evictionTimestamp>0</evictionTimestamp> <serviceUpTimestamp>1570175584067</serviceUpTimestamp> </leaseInfo> <metadata> <management.port>8081</management.port> </metadata> <homePageUrl>http://192.168.50.161:8081/</homePageUrl> <statusPageUrl>http://192.168.50.161:8081/actuator/info</statusPageUrl> <healthCheckUrl>http://192.168.50.161:8081/actuator/health</healthCheckUrl> <vipAddress>client1</vipAddress> <secureVipAddress>client1</secureVipAddress> <isCoordinatingDiscoveryServer>false</isCoordinatingDiscoveryServer> <lastUpdatedTimestamp>1570175584067</lastUpdatedTimestamp> <lastDirtyTimestamp>1570175583914</lastDirtyTimestamp> <actionType>ADDED</actionType> </instance> </application></applications>
可以看到eureka client已经成功注册到server。