BASIC authentication is applied between curl and Client and between Client and Config Server. Originally, OAuth 2.0 is probably better, but that's another opportunity.
The sample code is uploaded to GitHub.
At the time of writing, Spring Cloud Finchley has not yet been officially released. Please note that the specifications may change in the future.
For the Config Server itself, see Maki-san's blog. However, please note that this is an article before the official release, so there are some differences from the current one.
You can use Git or SVN as the repository. This time I will use GitHub. Click here for URL-> https://github.com/MasatoshiTada/app-config Please fork and use!
application.properties This setting is used for all applications and all profiles.
application.properties
message=Hello application!
common=common
application-xxx.properties This setting is used by all applications, but only by a specific profile ("xxx" is the profile name).
application-dev.properties
message=Hello application-dev!
common=common-dev
application-qa.properties
message=Hello application-qa!
common=common-qa
client.properties This setting is used for all profiles only in the application whose name is "client".
client.properties
message=Hello client!
server.port=8081
#Used for refreshing settings/Activate the refresh endpoint
management.endpoints.web.exposure.include=refresh
#Set the Spring Security log level to trace to make it easier to see the internal execution.
logging.level.org.springframework.security=trace
The third line,
management.endpoints.web.exposure.include = refresh
, is a new setting from Spring Boot 2.0. In Spring Boot 2.0, only the endpoints described in this setting are enabled (multiple comma separated).
client-xxx.properties This setting is used only for specific profiles only in applications whose name is "client" ("xxx" is the profile name).
client-dev.properties
message=Hello client-dev!
server.port=8082
client-qa.properties
message=Hello client-qa!
server.port=8083
foo.properties This setting is used for all profiles only in applications whose name is "foo".
foo.properties
message=Hello foo!
server.port=9001
foo-xxx.properties This setting is used only for specific profiles only in applications whose name is "foo" ("xxx" is the profile name).
foo-dev.properties
message=Hello foo-dev!
server.port=9002
foo-qa.properties
message=Hello foo-qa!
server.port=9003
If another file has a setting with the same name, it will be prioritized in the following order (the higher one will be prioritized).
(1) Let's make a template with Spring Initializr. Decide "Group" and "Artifact" appropriately, and add "Config Server" and "Security" in "Dependencies".
(2) Add @EnableConfigServer
to the class that has the main () method.
@SpringBootApplication
@EnableConfigServer //Attach this
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
(3) Create a Java Config class for Spring Security. Create one user with any user name and password and enable BASIC authentication.
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// "client"Create a user
//Do not use NoOpPasswordEncoder in production, use BCryptPasswordEncoder instead
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("client").password("password").roles("CLIENT");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//Enable BASIC authentication so that all URLs must be authenticated before they can be accessed
http.httpBasic();
http.authorizeRequests()
.anyRequest().authenticated();
}
}
As mentioned in the comments, NoOpPasswordEncoder does not encode passwords at all and should not be used in production (already deprecated in Spring Security 5). This time I'm using it for learning only.
(4) Describe the settings in application.properties.
#URL of Git repository
spring.cloud.config.server.git.uri=https://github.com/MasatoshiTada/app-config.git
#This Config Server port number
server.port=8888
(1) Let's make a template with Spring Initializr. Decide "Group" and "Artifact" appropriately, and add "Web", "Config Client", "Actuator" and "Security" in "Dependencies".
(2) Create a Java Config class for Spring Security. Create two users with an arbitrary user name and password (separate roles and give them an arbitrary role name).
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// "ACTUATOR"When"USER"Whenいう2つのロールのユーザーを作る
//Don't use NoOpPasswordEncoder in production!
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("actuator").password("password").roles("ACTUATOR").and()
.withUser("user").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//Enable BASIC authentication
http.httpBasic();
//Actuator endpoints can only be accessed by the ACTUATOR role,
//Others can be accessed by any role as long as you are logged in
http.authorizeRequests()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
.anyRequest().authenticated();
//Do not disable CSRF in production!
http.csrf().disable();
}
}
This time we have disabled CSRF to avoid making the sample too complicated. Please do not disable it in the production environment, and obtain a token by some means before accessing with curl.
(3) Describe the settings in bootstrap.properties.
#Application name for this client
spring.application.name=client
#Config Server URL
spring.cloud.config.uri=http://localhost:8888/
#Username and password to access Config Server
#(Created with Java Config of Config Server)
spring.cloud.config.username=client
spring.cloud.config.password=password
bootstrap.properties describes the boot settings and is only used in the Spring Cloud environment.
(4) Create an appropriate controller that returns the value obtained from Config Server. Append @RefreshScope
to the class.
@RefreshScope // "POST /actuator/refresh"Will destroy the instance of this class
@RestController
@RequestMapping("/hello")
public class HelloController {
private final String message;
private final String common;
//Get the value obtained from Config Server with the constructor
public HelloController(@Value("${message}") String message, @Value("${common}") String common) {
this.message = message;
this.common = common;
}
@GetMapping
public Map<String, String> hello() {
HashMap<String, String> map = new HashMap<>();
map.put("message", message);
map.put("common", common);
return map;
}
}
(1) Start only Config Server.
(2) You can get the value of application.properties by accessing / application / default
.
$ curl -X GET -u client:password http://localhost:8888/application/default | jq
{
"name": "application",
"profiles": [
"default"
],
"label": null,
"version": "e87b3c3ff0239394963e3bddf0a2982db5064339",
"state": null,
"propertySources": [
{
"name": "https://github.com/MasatoshiTada/app-config.git/application.properties",
"source": {
"message": "Hello application!",
"common": "common"
}
}
]
}
(2) You can get the values of application.properties and application-dev.properties by accessing / application / dev
.
$ curl -X GET -u client:password http://localhost:8888/application/dev | jq
{
"name": "application",
"profiles": [
"dev"
],
"label": null,
"version": "e87b3c3ff0239394963e3bddf0a2982db5064339",
"state": null,
"propertySources": [
{
"name": "https://github.com/MasatoshiTada/app-config.git/application-dev.properties",
"source": {
"message": "Hello application-dev!",
"common": "common-dev"
}
},
{
"name": "https://github.com/MasatoshiTada/app-config.git/application.properties",
"source": {
"message": "Hello application!",
"common": "common"
}
}
]
}
Although not described, you can get the values of application.properties and application-qa.properties by accessing
/ application / qa
.
(3) You can get the values of application.properties and client.properties by accessing / client / default
.
$ curl -X GET -u client:password http://localhost:8888/client/default | jq
{
"name": "client",
"profiles": [
"default"
],
"label": null,
"version": "e87b3c3ff0239394963e3bddf0a2982db5064339",
"state": null,
"propertySources": [
{
"name": "https://github.com/MasatoshiTada/app-config.git/client.properties",
"source": {
"message": "Hello client!",
"server.port": "8081",
"management.endpoints.web.exposure.include": "refresh",
"logging.level.org.springframework.security": "trace"
}
},
{
"name": "https://github.com/MasatoshiTada/app-config.git/application.properties",
"source": {
"message": "Hello application!",
"common": "common"
}
}
]
}
Although not described, you can get the values of application.properties and foo.properties by accessing
/ foo / default
.
(4) By accessing / client / dev
, you can get the values of application.properties, application-dev.properties, client.properties, client-dev.properties.
$ curl -X GET -u client:password http://localhost:8888/client/dev | jq
{
"name": "client",
"profiles": [
"dev"
],
"label": null,
"version": "e87b3c3ff0239394963e3bddf0a2982db5064339",
"state": null,
"propertySources": [
{
"name": "https://github.com/MasatoshiTada/app-config.git/client-dev.properties",
"source": {
"message": "Hello client-dev!",
"server.port": "8082"
}
},
{
"name": "https://github.com/MasatoshiTada/app-config.git/application-dev.properties",
"source": {
"message": "Hello application-dev!",
"common": "common-dev"
}
},
{
"name": "https://github.com/MasatoshiTada/app-config.git/client.properties",
"source": {
"message": "Hello client!",
"server.port": "8081",
"management.endpoints.web.exposure.include": "refresh",
"logging.level.org.springframework.security": "trace"
}
},
{
"name": "https://github.com/MasatoshiTada/app-config.git/application.properties",
"source": {
"message": "Hello application!",
"common": "common"
}
}
]
}
Not listed, --You can get the values of application.properties, application-qa.properties, client.properties, client-qa.properties by accessing
/ client / qa
. --You can get the values of application.properties, application-dev.properties, foo.properties, and foo-dev.properties by accessing/ foo / dev
. --You can get the values of application.properties, application-qa.properties, foo.properties, and foo-qa.properties by accessing/ foo / qa
.
Keep the Config Server running after the above checks.
(1) Start the client without specifying any profile.
(2) At startup, the client accesses Config Server with the URL tried in the previous chapter based on the application name specified in spring.application.name
and the profile name being executed (in this case, / client. / default
). Also, BASIC authentication is used for this access (user name client
, password password
).
(3) Access localhost: 8081 / hello
with curl.
$ curl -X GET -u user:password http://localhost:8081/hello | jq
{
"common": "common",
"message": "Hello client!"
}
"common" is the value of application.properties. "message" is also defined in application.properties, but the value of client.properties is used from the priority rule. The port number 8081 that is running is also the value of client.properties.
(4) Stop the client once and restart it with the dev profile. The profile is specified by a command line argument with "-" (in addition, it can be specified by environment variables, JVM system properties, etc.)
client $ mvn clean package
client $ java -jar target/client-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev
client $ curl -X GET -u user:password http://localhost:8082/hello | jq
{
"common": "common-dev",
"message": "Hello client-dev!"
}
"common" is the value of application-dev.properties. "message" is the value of client-dev.properties. The port number 8082 that is running is also the value of client-dev.properties.
(1) Stop the currently running client and restart it without specifying a profile.
(2) Use curl to access the / hello
endpoint. The value of message is "Hello client!".
$ curl -X GET -u user:password http://localhost:8081/hello | jq
{
"common": "common",
"message": "Hello client!"
}
(3) On GitHub, rewrite the value of message in client.properties.
message=Hello client!!!!!!!!!!!!!!!!!!!!!!!!!
(4) Access the / hello
endpoint with curl again. The value of message remains "Hello client!" And has not changed. This is because the value changed in GitHub has not been reflected on the client side yet.
$ curl -X GET -u user:password http://localhost:8081/hello | jq
{
"common": "common",
"message": "Hello client!"
}
(5) Access / actuator / refresh
with curl. The client then accesses the Config Server, which gets the value from GitHub and passes it to the client.
$ curl -X POST -u actuator:password http://localhost:8081/actuator/refresh | jq
[
"config.client.version",
"message"
]
Note that the username specified with
-u
is ʻactuator. This is a user created in Java Config on the client and a user in the ʻACTUATOR
role who has permission to access/ actuator / **
.
(6) When refreshed, the instance of the bean with @RefreshScope
added (in this case HelloController
) is destroyed. The instance is recreated the first time the bean is needed after a refresh (in this case, when you access / hello
with curl), and the new settings after the change are used.
$ curl -X GET -u user:password http://localhost:8081/hello | jq
{
"common": "common",
"message": "Hello client!!!!!!!!!!!!!!!!!!!!!!!!!"
}
Recommended Posts