如何使用Spring Boot和Spring Security保护REST API?


80

我知道保护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无法按我的需要工作,因为通过@ControllerAdviceSpring处理异常存在问题servlet dispatcher

我需要的

我想知道这些标准是否切合实际并获得任何帮助,以及如何开始使用Spring Security保护REST API。我阅读了许多教程(例如Spring Data REST + Spring Security),但是所有教程都在非常基本的配置中工作-带有凭据的用户存储在配置中的内存中,我需要使用DBMS并创建自己的身份验证器。

请给我一些如何开始的想法。

Answers:


67

基于令牌的身份验证-用户将提供其凭据,并获得唯一且受时间限制的访问令牌。我想在自己的实现中管理令牌的创建,检查有效性和到期时间。

实际上,将过滤器用于令牌验证-这种情况下的最佳方法

最终,您可以通过Spring Data创建CRUD,以管理Token的属性(例如过期)等。

这是我的令牌过滤器: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 configure,您可以像这样配置您的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();
}

你能帮我解决我的问题吗?stackoverflow.com/questions/46065063/…
费利佩A.

2
是否有包含所有要求的示例项目?
AlikElzin-kilaka'3

@Oleksandr:那是一个远景,但是你能告诉我为什么你在RESTAuthenticationTokenProcessingFilter类的updateLastLogin(...)方法中启动了一个线程吗?
Z3d4s

1
@ z3d4s,实际上是一个旧示例(4年),现在,我建议使用OffsetDateTime,其他方法等:)我建议使用新线程来减少用户请求的处理时间,因为在保存过程中可能会花费更多时间进入数据库。
Oleksandr Loushkin '19年

啊,我明白了,那就是个天才的解决方案!谢谢!
Z3d4s

4

Spring安全性对于为REST URL提供身份验证和授权也非常有用。我们无需指定任何自定义实现。

首先,您需要在安全性配置中指定对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>

该代码将通过身份验证和授权来保护REST网址,而无需任何自定义实现。

有关完整的代码,请找到以下链接:

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



-1

要验证REST API,有两种方法

1-使用application.properties文件中设置的默认用户名和密码进行基本身份验证

基本认证

2-使用具有实际用户名和密码的数据库(userDetailsS​​ervice)进行身份验证

进阶验证


视频非常有用。如何对ReST API进行相同的高级身份验证。这里只描述一下Web。是否有任何视频教程可用于REST API中的高级身份验证。
雅各布

如果您看过第二个视频(高级身份验证),那么我也在使用REST客户端(用于REST API)进行相同的身份验证。
jeet singh parmar,
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.