Как защитить REST API с помощью Spring Boot и Spring Security?

Я знаю, что защита REST API - это широко обсуждаемая тема, но я не могу создать небольшой прототип, соответствующий моим критериям (и мне нужно подтвердить, что эти критерии реалистичны). Существует так много вариантов, как защитить ресурсы и как работать с безопасностью Spring, мне нужно уточнить, реалистичны ли мои потребности.

Мои требования

  • Аутентификатор на основе токена - пользователи предоставят свои учетные данные и получат уникальный и ограниченный по времени токен доступа. Я хотел бы управлять созданием токена, проверкой действительности, истечением срока действия в моей собственной реализации.
  • Некоторые ресурсы REST будут общедоступными - без аутентификации вообще,
  • Некоторые ресурсы будут доступны только пользователям с правами администратора,
  • Другой ресурс будет доступен после авторизации для всех пользователей.
  • Я не хочу использовать обычную проверку подлинности
  • Конфигурация кода Java (не XML)

Текущий статус

Мой REST API работает очень хорошо, но теперь мне нужно его обезопасить. Когда я искал решение, я создал javax.servlet.Filter фильтр:

  @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        String accessToken = request.getHeader(AUTHORIZATION_TOKEN);
        Account account = accountDao.find(accessToken);

        if (account == null) {    
            throw new UnauthorizedException();    
        }

        chain.doFilter(req, res);

    }

Но это решение с javax.servlet.filters не работает так, как мне нужно, потому что есть проблема с обработкой исключений через @ControllerAdvice с Spring servlet dispatcher.

Что мне нужно

Я хотел бы узнать, реалистичны ли эти критерии, и получить помощь, как начать защищать REST API с помощью Spring Security. Я прочитал много руководств (например, Spring Data REST + Spring Security), но все они работают в очень простой конфигурации - пользователи с их учетными данными хранятся в памяти в конфигурации, и мне нужно работать с СУБД и создать собственный аутентификатор.

Подскажите, с чего начать.


person Artegon    schedule 13.09.2015    source источник


Ответы (4)


Аутентификация на основе токенов - пользователи предоставят свои учетные данные и получат уникальный и ограниченный по времени токен доступа. Я хотел бы управлять созданием токена, проверкой действительности, истечением срока действия в моей собственной реализации.

На самом деле, используйте фильтр для аутентификации токена - лучший способ в этом случае

В конце концов, вы можете создать CRUD через Spring Data для управления такими свойствами токена, как истечение срока действия и т. Д.

Вот мой фильтр токенов: http://pastebin.com/13WWpLq2

И реализация токен-сервиса

http://pastebin.com/dUYM555E

Некоторые ресурсы REST будут общедоступными - аутентификация не требуется.

Это не проблема, вы можете управлять своими ресурсами с помощью конфигурации безопасности Spring следующим образом: .antMatchers("/rest/blabla/**").permitAll()

Некоторые ресурсы будут доступны только пользователям с правами администратора,

Взгляните на аннотацию @Secured к классу. Пример:

@Controller
@RequestMapping(value = "/adminservice")
@Secured("ROLE_ADMIN")
public class AdminServiceController {

Другой ресурс будет доступен после авторизации для всех пользователей.

Вернувшись к настройке Spring Security, вы можете настроить свой URL-адрес следующим образом:

    http
            .authorizeRequests()
            .antMatchers("/openforall/**").permitAll()
            .antMatchers("/alsoopen/**").permitAll()
            .anyRequest().authenticated()

Я не хочу использовать обычную проверку подлинности

Да, через фильтр токенов ваши пользователи будут аутентифицированы.

Конфигурация кода Java (не XML)

Вернемся к словам выше, посмотрите на @EnableWebSecurity. Ваш класс будет:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {}

Вам необходимо переопределить метод configure. Код ниже, например, как настроить сопоставители. Это из другого проекта.

    @Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/assets/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .formLogin()
                .usernameParameter("j_username")
                .passwordParameter("j_password")
                .loginPage("/login")
                .defaultSuccessUrl("/", true)
                .successHandler(customAuthenticationSuccessHandler)
                .permitAll()
            .and()
                .logout()
                .logoutUrl("/logout")
                .invalidateHttpSession(true)
                .logoutSuccessUrl("/")
                .deleteCookies("JSESSIONID")
                .logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
            .and()
                .csrf();
}
person Oleksandr Loushkin    schedule 13.09.2015
comment
не могли бы вы помочь мне в моем вопросе? stackoverflow.com/questions/46065063/ - person Felipe A.; 06.09.2017
comment
Любой пример проекта, который включает в себя все требования? - person AlikElzin-kilaka; 03.03.2018
comment
@Oleksandr: Это долгий путь, но можете ли вы мне сказать, почему вы начали поток в методе updateLastLogin (...) класса RESTAuthenticationTokenProcessingFilter? - person Z3d4s; 30.04.2019
comment
@ z3d4s, на самом деле это старый пример (4 года), пока я предлагаю использовать OffsetDateTime, другие подходы и т. д. :) новый поток, который я предлагал использовать, чтобы уменьшить время обработки запросов пользователей, потому что это может занять дополнительное время во время сохранения в базу данных. - person Oleksandr Loushkin; 02.05.2019
comment
Аааааааааааааааа, это гениальное решение! Спасибо! - person Z3d4s; 02.05.2019

Безопасность Spring также очень полезна для обеспечения аутентификации и авторизации URL-адресов REST. Нам не нужно указывать какие-либо специальные реализации.

Во-первых, вам нужно указать точку входа-ref для restAuthenticationEntryPoint в вашей конфигурации безопасности, как показано ниже.

 <security:http pattern="/api/**" entry-point-ref="restAuthenticationEntryPoint" use-expressions="true" auto-config="true" create-session="stateless" >

    <security:intercept-url pattern="/api/userList" access="hasRole('ROLE_USER')"/>
    <security:intercept-url pattern="/api/managerList" access="hasRole('ROLE_ADMIN')"/>
    <security:custom-filter ref="preAuthFilter" position="PRE_AUTH_FILTER"/>
</security:http>

Реализация restAuthenticationEntryPoint может быть такой, как показано ниже.

 @Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

   public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException ) throws IOException {
      response.sendError( HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized" );
   }
}

После этого вам нужно указать RequestHeaderAuthenticationFilter. Он содержит ключ RequestHeader. Это в основном используется для идентификации аутентификации пользователя. Обычно RequestHeader передает эту информацию при выполнении вызовов REST. Например, рассмотрите ниже код

   <bean id="preAuthFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
    <property name="principalRequestHeader" value="Authorization"/>
    <property name="authenticationManager" ref="authenticationManager" />
  </bean>

Здесь,

<property name="principalRequestHeader" value="Authorization"/>

«Авторизация» - это ключ, представленный входящему запросу. Он содержит необходимую информацию для аутентификации пользователя. Также вам необходимо настроить PreAuthenticatedAuthenticationProvider, чтобы выполнить наше требование.

   <bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
  <bean id="userDetailsServiceWrapper"
      class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
    <property name="userDetailsService" ref="authenticationService"/>
  </bean>
</property>
</bean>

Этот код будет работать для защиты URL-адресов REST с помощью аутентификации и авторизации без каких-либо пользовательских реализаций.

Для получения полного кода перейдите по ссылке ниже:

https://github.com/srinivas1918/spring-rest-security

person Nalla Srinivas    schedule 21.12.2016

Я тоже долго искал, работаю над похожим проектом и обнаружил, что в Spring есть модуль для реализации сеанса через redis. Выглядит просто и полезно. Я тоже добавлю в свой проект. Может быть полезно:

http://docs.spring.io/spring-session/docs/1.2.1.BUILD-SNAPSHOT/reference/html5/guides/rest.html.

person serkan ersoy    schedule 24.05.2016

Чтобы проверить REST API, есть 2 способа

1 - Обычная проверка подлинности с использованием имени пользователя и пароля по умолчанию, заданных в файле application.properties.

Базовая аутентификация

2 - Аутентификация с использованием базы данных (userDetailsService) с фактическим именем пользователя и паролем

Расширенная аутентификация

person jeet singh parmar    schedule 17.04.2017
comment
Полезно видео. Как сделать такую ​​же расширенную аутентификацию для ReST API. Здесь только описание Web. Есть ли видеоурок по расширенной аутентификации в REST API. - person Jacob; 02.04.2018
comment
Если вы видели 2-е видео (Расширенная аутентификация), значит, я выполняю ту же аутентификацию, используя REST-клиент (для REST API). - person jeet singh parmar; 02.05.2018