Автоматично конфигуриране на пролетното стартиране

1. Въведение

В тази статия ще разгледаме внимателния подход на Spring Boot към сигурността.

Най-просто казано, ще се съсредоточим върху конфигурацията по подразбиране на защитата и как можем да я деактивираме или персонализираме, ако има нужда.

2. Настройка по подразбиране на защитата

За да добавим сигурност към нашето приложение Spring Boot, трябва да добавим зависимостта на стартера за защита :

 org.springframework.boot spring-boot-starter-security 

Това ще включва клас SecurityAutoConfiguration - съдържащ първоначалната / конфигурацията по подразбиране на защитата.

Забележете как не сме посочили версията тук, с предположението, че проектът вече използва Boot като родител.

Просто казано, по подразбиране удостоверяването се активира за приложението. Също така, договарянето на съдържание се използва, за да се определи дали трябва да се използва основно или formLogin.

Има някои предварително дефинирани свойства, като например:

spring.security.user.name spring.security.user.password

Ако не конфигурираме паролата с помощта на предварително дефинираното свойство spring.security.user.password и стартираме приложението, ще забележим, че парола по подразбиране се генерира на случаен принцип и се отпечатва в конзолния дневник:

Using default security password: c8be15de-4488-4490-9dc6-fab3f91435c6

За повече настройки по подразбиране вижте раздела за свойства на защитата на справочната страница на Spring Boot Common Application Properties.

3. Деактивиране на автоматичното конфигуриране

За да отхвърлим автоматичната конфигурация на защитата и да добавим наша собствена конфигурация, трябва да изключим класа SecurityAutoConfiguration .

Това може да стане чрез просто изключване:

@SpringBootApplication(exclude = { SecurityAutoConfiguration.class }) public class SpringBootSecurityApplication { public static void main(String[] args) { SpringApplication.run(SpringBootSecurityApplication.class, args); } } 

Или чрез добавяне на някаква конфигурация във файла application.properties :

spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration

Има и някои конкретни случаи, в които тази настройка не е напълно достатъчна.

Например, почти всяко приложение на Spring Boot се стартира с Actuator в пътя на класа. Това създава проблеми, защото друг клас за автоматично конфигуриране се нуждае от този, който току-що изключихме , така че приложението няма да може да се стартира.

За да разрешим този проблем, трябва да изключим този клас; и, специфично за ситуацията с актуатора, трябва да изключим ManagementWebSecurityAutoConfiguration .

3.1. Деактивиране срещу надминаване на автоматичната конфигурация на сигурността

Има значителна разлика между деактивирането на автоматичното конфигуриране и надминаването му.

Като го деактивирате, това е точно като добавяне на зависимостта Spring Security и цялата настройка от нулата. Това може да бъде полезно в няколко случая:

  1. Интегриране на защитата на приложението с доставчик на персонализирана защита
  2. Мигриране на наследено приложение Spring с вече съществуваща настройка на защитата - към Spring Boot

Но през повечето време няма да имаме нужда да деактивираме напълно автоматичната конфигурация на защитата.

Начинът, по който е конфигуриран Spring Boot, позволява надминаване на автоматично конфигурираната защита чрез добавяне в нашите нови / персонализирани класове за конфигуриране. Това обикновено е по-лесно, тъй като ние просто персонализираме съществуваща настройка за защита, за да отговорим на нашите нужди.

4. Конфигуриране на Spring Boot Security

Ако сме избрали пътя за деактивиране на автоматичната конфигурация на защитата, естествено трябва да предоставим собствена конфигурация.

Както обсъждахме по-рано, това е конфигурацията по подразбиране за защита; можем да го персонализираме, като модифицираме файла със свойства.

Можем например да заменим паролата по подразбиране, като добавим нашата собствена:

spring.security.user.password=password

Ако искаме по-гъвкава конфигурация, например с множество потребители и роли - трябва да използваме пълен клас @Configuration :

@Configuration @EnableWebSecurity public class BasicConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); auth .inMemoryAuthentication() .withUser("user") .password(encoder.encode("password")) .roles("USER") .and() .withUser("admin") .password(encoder.encode("admin")) .roles("USER", "ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest() .authenticated() .and() .httpBasic(); } }

В @EnableWebSecurity анотацията е от решаващо значение, ако искаме да деактивирате конфигурацията на сигурност по подразбиране.

Ако липсва, приложението няма да стартира. Анотацията е незадължителна само ако просто заместваме поведението по подразбиране с помощта на WebSecurityConfigurerAdapter .

Също така обърнете внимание, че трябва да използваме PasswordEncoder, за да зададем паролите, когато използваме Spring Boot 2 . За повече подробности вижте нашето ръководство за кодиращия парола по подразбиране в Spring Security 5.

Сега трябва да проверим дали нашата конфигурация за сигурност се прилага правилно чрез няколко бързи теста на живо:

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = RANDOM_PORT) public class BasicConfigurationIntegrationTest { TestRestTemplate restTemplate; URL base; @LocalServerPort int port; @Before public void setUp() throws MalformedURLException { restTemplate = new TestRestTemplate("user", "password"); base = new URL("//localhost:" + port); } @Test public void whenLoggedUserRequestsHomePage_ThenSuccess() throws IllegalStateException, IOException { ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); assertEquals(HttpStatus.OK, response.getStatusCode()); assertTrue(response.getBody().contains("Baeldung")); } @Test public void whenUserWithWrongCredentials_thenUnauthorizedPage() throws Exception { restTemplate = new TestRestTemplate("user", "wrongpassword"); ResponseEntity response = restTemplate.getForEntity(base.toString(), String.class); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); assertTrue(response.getBody().contains("Unauthorized")); } }

Идеята е, че зад Spring Boot Security стои всъщност Spring Security, така че всяка конфигурация на защитата, която може да се направи с тази, или всяка интеграция, която поддържа, може също да бъде внедрена в Spring Boot.

5. Автоматично конфигуриране на пролетното стартиране на OAuth2 (използвайки стария стек)

Spring Boot има специална поддръжка за автоматично конфигуриране за OAuth2.

Spring Security OAuth support that came with Spring Boot 1.x was removed in later boot versions in lieu of first class OAuth support that comes bundled with Spring Security 5. We'll see how to use that in the next section.

For the legacy stack (using Spring Security OAuth), first we'll need to add a Maven dependency to start setting up our application:

 org.springframework.security.oauth spring-security-oauth2 

This dependency includes a set of classes that are capable of triggering the auto-configuration mechanism defined in OAuth2AutoConfiguration class.

Now, we have multiple choices to continue, depending on the scope of our application.

5.1. OAuth2 Authorization Server Auto-Configuration

If we want our application to be an OAuth2 provider, we can use @EnableAuthorizationServer.

On startup, we'll notice in the logs that the auto-configuration classes will generate a client id and a client-secret for our authorization server and of course a random password for basic authentication.

Using default security password: a81cb256-f243-40c0-a585-81ce1b952a98 security.oauth2.client.client-id = 39d2835b-1f87-4a77-9798-e2975f36972e security.oauth2.client.client-secret = f1463f8b-0791-46fe-9269-521b86c55b71

These credentials can be used to obtain an access token:

curl -X POST -u 39d2835b-1f87-4a77-9798-e2975f36972e:f1463f8b-0791-46fe-9269-521b86c55b71 \ -d grant_type=client_credentials -d username=user -d password=a81cb256-f243-40c0-a585-81ce1b952a98 \ -d scope=write //localhost:8080/oauth/token

Our another article provides further details on the subject.

5.2. Other Spring Boot OAuth2 Auto-Configuration Settings

There are some other use cases covered by Spring Boot OAuth2 like:

  1. Resource Server – @EnableResourceServer
  2. Client Application – @EnableOAuth2Sso or @EnableOAuth2Client

If we need our application to be one of the types above we just have to add some configuration to application properties, as detailed by the links referenced above.

All OAuth2 specific properties can be found at Spring Boot Common Application Properties.

6. Spring Boot OAuth2 Auto-Configuration (using new stack)

To use the new stack, we need to add dependencies based on what we want to configure – an authorization server, a resource server or a client application.

Let's look at them one by one.

6.1. OAuth2 Authorization Server Support

As we saw in the previous section, the Spring Security OAuth stack offered the possibility of setting up an Authorization Server as a Spring Application. But the project has been deprecated and Spring does not support its own authorization server as of now. Instead, it's recommended to use existing well-established providers such as Okta, Keycloak, and Forgerock.

However, Spring Boot does make it easy for us to configure such providers. For an example Keycloak configuration, we can refer to either A Quick Guide to Using Keycloak with Spring Boot or Keycloak Embedded in a Spring Boot Application.

6.2. OAuth2 Resource Server Support

To include support for a resource server, we need to add this dependency:

 org.springframework.boot spring-boot-starter-oauth2-resource-server 

For the latest version information, head over to Maven Central.

Additionally, in our security configuration, we need to include the oauth2ResourceServer() DSL:

@Configuration public class JWTSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http ... .oauth2ResourceServer(oauth2 -> oauth2.jwt()); ... } }

Our OAuth 2.0 Resource Server With Spring Security 5 gives an in-depth view of this topic.

6.3. OAuth2 Client Support

Similar to how we configured a resource server, a client application also needs its own dependencies and DSLs.

Here's the specific dependency for OAuth2 client support:

 org.springframework.boot spring-boot-starter-oauth2-client  

The latest version can be found at Maven Central.

Spring Security 5 also provides first-class login support via its oath2Login() DSL.

For details on SSO support in the new stack, please refer to our Simple Single Sign-On with Spring Security OAuth2.

7. Spring Boot 2 Security vs Spring Boot 1 Security

Compared to Spring Boot 1, Spring Boot 2 has greatly simplified the auto-configuration.

In Spring Boot 2, if we want our own security configuration, we can simply add a custom WebSecurityConfigurerAdapter. This will disable the default auto-configuration and enable our custom security configuration.

Spring Boot 2 uses most of Spring Security’s defaults. Because of this, some of the endpoints that were unsecured by default in Spring Boot 1 are now secured by default.

These endpoints include static resources such as /css/**, /js/**, /images/**, /webjars/**, /**/favicon.ico, and the error endpoint. If we need to allow unauthenticated access to these endpoints, we can explicitly configure that.

To simplify the security-related configuration, Spring Boot 2 has removed the following Spring Boot 1 properties:

security.basic.authorize-mode security.basic.enabled security.basic.path security.basic.realm security.enable-csrf security.headers.cache security.headers.content-security-policy security.headers.content-security-policy-mode security.headers.content-type security.headers.frame security.headers.hsts security.headers.xss security.ignored security.require-ssl security.sessions

8. Conclusion

In this article, we focused on the default security configuration provided by Spring Boot. We saw how the security auto-configuration mechanism can be disabled or overridden and how a new security configuration can be applied.

Изходният код за OAuth2 може да бъде намерен в нашето хранилище на OAuth2 GitHub, за наследство и нов стек. Останалата част от кода може да бъде намерена в уроците GitHub.