Это третий пост из моей серии постов в блоге Spring Boot. В самом первом посте я рассказал о своем опыте создания RESTFul Services с использованием Spring Boot. Затем я расширил образец до
интегрировать с документацией Swagger . В этом посте я собираюсь расширить пример выше с аспектом безопасности.
Что такое безопасность API
API Security — это широкая область с множеством различных определений, значений и решений. Основными ключевыми терминами безопасности API являются Авторизация, Аутентификация, Шифрование, Федерация и Делегирование. Однако я не буду говорить о каждом из них здесь.
Что такое аутентификация
Аутентификация используется для надежного определения личности конечного пользователя и предоставления доступа к ресурсам на основе правильно идентифицированного пользователя.
Что такое базовая аутентификация
Базовая аутентификация — это самый простой способ обеспечить контроль доступа к ресурсам. Здесь, пользовательский агент HTTP предоставляет имя пользователя и пароль при выполнении запроса. Строка, содержащая имя пользователя и пароль, разделенные двоеточием, кодируется Base64 перед отправкой бэкэнду, когда требуется аутентификация.
Как вызвать Basic Auth Protected API
Вариант 1: Отправить заголовок авторизации. Это значение в кодировке base64: имя пользователя: пароль Пример: «Авторизация: Basic Y2hhbmRhbmE6Y2hhbmRhbmE =»
1
|
curl -X GET http: //localhost :8080 /admin/hello/chandana -H 'authorization: Basic Y2hhbmRhbmE6Y2hhbmRhbmE=' |
Вариант 2. Использование URL:
1
|
curl -X GET -u username:password http: //localhost :8080 /admin/hello/chandana |
ОК, мы говорили о базовых вещах. Итак, давайте посмотрим, как защитить REST API с помощью Spring Security. Вы можете загрузить исходный пример кода из моего репозитория GitHub (исходный код Swagger Spring Boot Project)
Чтобы улучшить наш предыдущий пример базовой безопасностью аутентификации, сначала я собираюсь добавить в файл pom зависимости «spring-boot-starter-security» и «spring-boot-starter-tomcat».
01
02
03
04
05
06
07
08
09
10
|
<!-- --> < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-security</ artifactId > </ dependency > < dependency > < groupId >javax.servlet</ groupId > < artifactId >javax.servlet-api</ artifactId > < version >3.1.0</ version > </ dependency > |
Следующим шагом является то, что наш класс конфигурации аннотируется аннотацией @EnableWebSecurity, а класс конфигурации расширяется из WebSecurityConfigurerAdapter. Аннотация EnableWebSecurity включит поддержку веб-безопасности Spring-Security.
1
2
3
4
|
@Configuration @EnableSwagger2 @EnableWebSecurity public class ApplicationConfig extends WebSecurityConfigurerAdapter { |
Метод переопределенной конфигурации (HttpSecurity) используется для определения того, какие URL-пути должны быть защищены, а какие — нет. В моем примере пути «/» и «/ api» не требуют никакой аутентификации, а любые другие пути (например, «admin») должны проходить аутентификацию с базовой аутентификацией.
1
2
3
4
5
6
7
|
@Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests().antMatchers( "/" , "/api/**" ).permitAll() .anyRequest().authenticated(); http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint); } |
В методе configureGlobal (AuthenticationManagerBuilder) я создал пользовательское хранилище в памяти с пользователем «chandana». Там я добавил имя пользователя, пароль и роль пользователя для пользователя в памяти.
1
2
3
4
|
@Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser( "chandana" ).password( "chandana" ).roles( "USER" ); } |
В дополнение к этому, вы можете видеть, что я добавил AutoAired BasicAuthenticationPoint, в мой класс конфигурации. Целью класса BasicAuthenticationEntryPoint является установка заголовка «WWW-Authenticate» для ответа. Таким образом, веб-браузеры будут отображать диалоговое окно для ввода имени пользователя и пароля на основе базового механизма аутентификации (заголовок WWW-Authenticate)
Затем вы можете запустить образец, используя «mvn spring-boot: run». Когда вы обращаетесь к «localhost: 8080 / api / hello / chandana», базовая аутентификация не требуется для вызова API. Однако если вы попытаетесь получить доступ к «localhost: 8080 / admin / hello / chandana», потребуется предоставить базовые учетные данные для доступа к ресурсу.
Класс AppConfig:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
package com.chandana.helloworld.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; 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 springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Contact; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 @EnableWebSecurity public class ApplicationConfig extends WebSecurityConfigurerAdapter { @Autowired private BasicAuthenticationPoint basicAuthenticationPoint; @Bean public Docket api() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(getApiInfo()) .select() .apis(RequestHandlerSelectors.basePackage( "com.chandana.helloworld.controllers" )) .paths(PathSelectors.any()) .build(); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.authorizeRequests().antMatchers( "/" , "/api/**" ).permitAll() .anyRequest().authenticated(); http.httpBasic().authenticationEntryPoint(basicAuthenticationPoint); } private ApiInfo getApiInfo() { Contact contact = new Contact( "Chandana Napagoda" , "http://blog.napagoda.com" , "[email protected]" ); return new ApiInfoBuilder() .title( "Example Api Title" ) .description( "Example Api Definition" ) .version( "1.0.0" ) .license( "Apache 2.0" ) .contact(contact) .build(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser( "chandana" ).password( "chandana" ).roles( "USER" ); } } |
Класс BasicAuthenticationEntryPoint:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.chandana.helloworld.config; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint; import org.springframework.stereotype.Component; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class BasicAuthenticationPoint extends BasicAuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) throws IOException, ServletException { response.addHeader( "WWW-Authenticate" , "Basic realm=" +getRealmName()); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); PrintWriter writer = response.getWriter(); writer.println( "HTTP Status 401 - " + authEx.getMessage()); } @Override public void afterPropertiesSet() throws Exception { setRealmName( "Chandana" ); super .afterPropertiesSet(); } } |
Вы также можете загрузить исходный код Spring Boot Basic Auth Project из моего репозитория GitHub.
См. Оригинальную статью здесь: Безопасный Spring Boot REST API с использованием базовой аутентификации
Мнения, высказанные участниками Java Code Geeks, являются их собственными. |