Як захистити REST API за допомогою Spring Boot та Spring Security?


80

Я знаю, що захист REST API є широко коментованою темою, але я не можу створити невеликий прототип, який відповідає моїм критеріям (і мені потрібно підтвердити, що ці критерії реалістичні). Є так багато варіантів, як захистити ресурси та як працювати з Spring security, мені потрібно пояснити, чи реалістичні мої потреби.

Мої вимоги

  • Аутентифікатор на основі токенів - користувачі надаватимуть його облікові дані та отримуватимуть унікальний та обмежений у часі маркер доступу. Я хотів би керувати створенням маркера, перевіркою дійсності, закінченням терміну дії у власній реалізації.
  • Деякі ресурси 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не працює, як мені потрібно, оскільки є проблема з обробкою винятків через @ControllerAdviceSpring servlet dispatcher.

Що мені потрібно

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

Будь ласка, дайте мені кілька ідей, як почати.

Відповіді:


67

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

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

Зрештою, ви можете створити CRUD через Spring Data для управління властивостями маркера, яким закінчується термін дії тощо.

Ось мій фільтр маркерів: http://pastebin.com/13WWpLq2

І реалізація Token Service

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 {}

Ви повинні замінити метод налаштування . Код нижче, лише для прикладу, як налаштувати збіги. Це з іншого проекту.

    @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();
}

Ви можете мені допомогти у моєму питанні? stackoverflow.com/questions/46065063/…
Феліпе А.

2
Будь-який приклад проекту, який включає всі вимоги?
AlikElzin-kilaka 03.03.18

@Oleksandr: Це довгий удар, але чи можете ви сказати мені, чому ви запустили ланцюжок у методі updateLastLogin (...) класу RESTAuthenticationTokenProcessingFilter?
Z3d4s

1
@ z3d4s, насправді це старий приклад (4 роки), наразі я запропоную використовувати OffsetDateTime, інші підходи тощо :) новий потік, який я запропонував використовувати для зменшення часу обробки запитів користувачів, оскільки це може зайняти додатковий час під час збереження в базу даних.
Олександр Лоушкін

Аааа, я бачу, це геніальне рішення! Дякую!
Z3d4s,

4

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

По-перше, вам потрібно вказати точку входу-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



-1

Перевірити REST API можна двома способами

1 - Базова автентифікація за допомогою типового імені користувача та пароля, встановлених у файлі application.properties

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

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

Розширена автентифікація


Відео корисно. Як зробити ту саму розширену автентифікацію для ReST API. Тут лише опис про Інтернет. Чи існує якийсь відеоурок для розширеної автентифікації в REST API.
Яків

Якщо ви бачили 2-е відео (розширена автентифікація), то я також виконую ту саму аутентифікацію за допомогою клієнта REST (для REST API).
jeet singh parmar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.