Làm thế nào để bảo mật REST API với Spring Boot và Spring Security?


80

Tôi biết rằng bảo mật REST API là chủ đề được bình luận rộng rãi nhưng tôi không thể tạo một nguyên mẫu nhỏ đáp ứng các tiêu chí của mình (và tôi cần xác nhận rằng các tiêu chí này là thực tế). Có rất nhiều lựa chọn về cách bảo mật tài nguyên và cách hoạt động với bảo mật Spring, tôi cần phải làm rõ xem nhu cầu của mình có thực tế không.

Yêu cầu của tôi

  • Trình xác thực dựa trên mã thông báo - người dùng sẽ cung cấp thông tin đăng nhập của nó và nhận mã thông báo truy cập giới hạn thời gian và duy nhất. Tôi muốn quản lý việc tạo mã thông báo, kiểm tra tính hợp lệ, hết hạn trong quá trình triển khai của riêng tôi.
  • Một số tài nguyên REST sẽ được công khai - không cần xác thực gì cả,
  • Một số tài nguyên sẽ chỉ có thể truy cập được đối với người dùng có quyền quản trị viên,
  • Tài nguyên khác sẽ có thể truy cập được sau khi cấp quyền cho tất cả người dùng.
  • Tôi không muốn sử dụng Xác thực cơ bản
  • Cấu hình mã Java (không phải XML)

Tình trạng hiện tại

API REST của tôi hoạt động rất tốt, nhưng bây giờ tôi cần bảo mật nó. Khi tìm kiếm giải pháp, tôi đã tạo một javax.servlet.Filterbộ lọc:

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

    }

Nhưng giải pháp này với javax.servlet.filterskhông hoạt động như tôi cần vì có vấn đề với việc xử lý ngoại lệ thông qua @ControllerAdviceSpring servlet dispatcher.

Tôi cân gi

Tôi muốn biết liệu những tiêu chí này có thực tế không và nhận bất kỳ trợ giúp nào, cách bắt đầu bảo mật API REST với Spring Security. Tôi đã đọc nhiều hướng dẫn (ví dụ: Spring Data REST + Spring Security ) nhưng tất cả đều hoạt động ở cấu hình rất cơ bản - người dùng với thông tin đăng nhập của họ được lưu trữ trong bộ nhớ trong cấu hình và tôi cần làm việc với DBMS và tạo trình xác thực riêng.

Xin vui lòng cho tôi một số ý tưởng làm thế nào để bắt đầu.

Câu trả lời:


67

Xác thực dựa trên mã thông báo - người dùng sẽ cung cấp thông tin đăng nhập của nó và nhận mã thông báo truy cập giới hạn thời gian và duy nhất. Tôi muốn quản lý việc tạo mã thông báo, kiểm tra tính hợp lệ, hết hạn trong quá trình triển khai của riêng tôi.

Trên thực tế, hãy sử dụng Bộ lọc cho mã thông báo Auth - cách tốt nhất trong trường hợp này

Cuối cùng, bạn có thể tạo CRUD thông qua Dữ liệu mùa xuân để quản lý các thuộc tính của Mã thông báo như sắp hết hạn, v.v.

Đây là bộ lọc mã thông báo của tôi: http://pastebin.com/13WWpLq2

Và triển khai dịch vụ mã thông báo

http://pastebin.com/dUYM555E

Một số tài nguyên REST sẽ được công khai - không cần xác thực gì cả

Đó không phải là vấn đề, bạn có thể quản lý tài nguyên của mình thông qua cấu hình bảo mật Spring như sau: .antMatchers("/rest/blabla/**").permitAll()

Một số tài nguyên sẽ chỉ có thể truy cập được đối với người dùng có quyền quản trị viên,

Hãy xem @Securedchú thích cho lớp. Thí dụ:

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

Tài nguyên khác sẽ có thể truy cập được sau khi cấp quyền cho tất cả người dùng.

Quay lại cấu hình Spring Security, bạn có thể cấu hình url của mình như sau:

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

Tôi không muốn sử dụng Xác thực cơ bản

Đúng vậy, thông qua bộ lọc mã thông báo, người dùng của bạn sẽ được xác thực.

Cấu hình mã Java (không phải XML)

Quay lại những từ trên, hãy nhìn vào @EnableWebSecurity. Lớp học của bạn sẽ là:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {}

Bạn phải ghi đè phương thức cấu hình . Mã bên dưới, chỉ là ví dụ, cách định cấu hình trình kết hợp. Nó từ một dự án khác.

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

bạn có thể giúp tôi câu hỏi của tôi được không? stackoverflow.com/questions/46065063/…
Felipe A.

2
Bất kỳ dự án ví dụ nào bao gồm tất cả các yêu cầu?
AlikElzin-kilaka

@Oleksandr: Đó là một bước dài, nhưng bạn có thể cho tôi biết tại sao bạn lại bắt đầu một chuỗi trong phương thức updateLastLogin (...) của lớp RESTAuthenticationTokenProcessingFilter không?
Z3d4s

1
@ z3d4s, thực ra đó là một ví dụ cũ (4 năm), bây giờ tôi sẽ đề xuất sử dụng OffsetDateTime, một cách tiếp cận khác, v.v. :) luồng mới mà tôi đề xuất sử dụng để giảm thời gian xử lý yêu cầu của người dùng, vì nó có thể mất thêm thời gian trong quá trình lưu vào cơ sở dữ liệu.
Oleksandr Loushkin

Ahhh tôi hiểu rồi, đó là một giải pháp thiên tài! Cảm ơn!
Z3d4s

4

Bảo mật mùa xuân cũng rất hữu ích để cung cấp xác thực và ủy quyền cho các URL REST. Chúng tôi không cần chỉ định bất kỳ triển khai tùy chỉnh nào.

Trước tiên, bạn cần chỉ định entry-point-ref cho restAuthenticationEntryPoint trong cấu hình bảo mật của mình như bên dưới.

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

Việc triển khai cho restAuthenticationEntryPoint có thể như dưới đây.

 @Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

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

Sau đó, bạn cần chỉ định RequestHeaderAuthenticationFilter. Nó chứa khóa RequestHeader. Điều này về cơ bản được sử dụng để xác định xác thực của người dùng. Nói chung RequestHeader mang thông tin này trong khi thực hiện các cuộc gọi REST. Ví dụ, hãy xem xét mã dưới đây

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

Đây,

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

"Ủy quyền" là chìa khóa trình bày yêu cầu đến. Nó chứa thông tin xác thực của người dùng được yêu cầu. Ngoài ra, bạn cần phải cấu hình PreAuthenticatedAuthenticationProvider để đáp ứng yêu cầu của chúng tôi.

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

Mã này sẽ hoạt động để bảo mật các url REST bằng phương pháp Xác thực và ủy quyền mà không cần bất kỳ triển khai tùy chỉnh nào.

Để có mã Hoàn thành, vui lòng tìm liên kết dưới đây:

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



-1

Để xác thực REST API, có 2 cách

1 - Xác thực cơ bản bằng tên người dùng và mật khẩu mặc định được thiết lập trong tệp application.properties

Xác thực cơ bản

2 - Xác thực bằng cơ sở dữ liệu (userDetailsService) với tên người dùng và mật khẩu thực tế

Xác thực nâng cao


Video rất hữu ích. Cách thực hiện xác thực nâng cao tương tự cho ReST API. Ở đây chỉ mô tả về Web. Có video hướng dẫn nào về xác thực nâng cao trong API REST không.
Jacob

Nếu bạn đã xem video thứ 2 (Xác thực nâng cao), thì ở đó tôi cũng đang thực hiện xác thực tương tự bằng ứng dụng khách REST (đối với API REST).
jeet singh parmar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.