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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32548372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:44:21  来源:igfitidea点击:

How to secure REST API with Spring Boot and Spring Security?

javaspringrestspring-security

提问by Artegon

I know that securing REST API is widely commented topic but I'm not able to create a small prototype that meets my criteria (and I need to confirm that these criteria are realistic). There are so many options how to secure resources and how work with Spring security, I need to clarify if my needs are realistic.

我知道保护 REST API 是广泛评论的主题,但我无法创建满足我的标准的小型原型(我需要确认这些标准是现实的)。如何保护资源以及如何使用 Spring 安全性有很多选择,我需要澄清我的需求是否切合实际。

My requirements

我的要求

  • Token based authenticator - users will provide its credentials and get unique and time limited access token. I would like to manage token creation, checking validity, expiration in my own implementation.
  • Some REST resources will be public - no need to authenticate at all,
  • Some resources will be accessible only for users with administrator rights,
  • Other resource will be accessible after authorization for all users.
  • I don't want to use Basic authentication
  • Java code configuration (not XML)
  • 基于令牌的身份验证器 - 用户将提供其凭据并获得唯一且有时间限制的访问令牌。我想在我自己的实现中管理令牌创建、检查有效性、到期时间。
  • 一些 REST 资源将是公开的 - 根本不需要进行身份验证,
  • 某些资源只有具有管理员权限的用户才能访问,
  • 其他资源在所有用户授权后即可访问。
  • 我不想使用基本身份验证
  • Java 代码配置(非 XML)

Current status

当前状态

My REST API works very well, but now I need to secure it. When I was looking for a solution I created a javax.servlet.Filterfilter:

我的 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);

    }

But this solution with javax.servlet.filtersdoesn't work as I need because there is an issue with exception handling via @ControllerAdvicewith Spring servlet dispatcher.

但是这个解决方案javax.servlet.filters并没有像我需要的那样工作,因为通过@ControllerAdviceSpring进行异常处理存在问题servlet dispatcher

What I need

我需要的

I would like to know if these criteria are realistic and get any help, how to start securing REST API with Spring Security. I read many tutorials (e.g. Spring Data REST + Spring Security) but all work in very basic configuration - users with their credentials are stored in memoryin configuration and I need to work with DBMS and create own authenticator.

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

Please give me some ideas how to start.

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

采纳答案by Oleksandr Loushkin

Token based authentication - users will provide its credentials and get unique and time limited access token. I would like to manage token creation, checking validity, expiration in my own implementation.

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

Actually, use Filter for token Auth - best way in this case

实际上,使用过滤器进行令牌身份验证 - 在这种情况下最好的方法

Eventually, you can create CRUD via Spring Data for managing Token's properties like to expire, etc.

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

Here is my token filter: http://pastebin.com/13WWpLq2

这是我的令牌过滤器:http: //pastebin.com/13WWpLq2

And Token Service Implementation

和令牌服务实现

http://pastebin.com/dUYM555E

http://pastebin.com/dUYM555E

Some REST resources will be public - no need to authenticate at all

一些 REST 资源将是公开的 - 根本不需要进行身份验证

It's not a problem, you can manage your resources via Spring security config like this: .antMatchers("/rest/blabla/**").permitAll()

这不是问题,您可以通过 Spring 安全配置管理您的资源,如下所示: .antMatchers("/rest/blabla/**").permitAll()

Some resources will be accessible only for users with administrator rights,

某些资源只有具有管理员权限的用户才能访问,

Take a look at @Securedannotation to class. Example:

看一下@Secured类的注释。例子:

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

The other resource will be accessible after authorization for all users.

其他资源在所有用户授权后都可以访问。

Back to Spring Security configure, you can configure your url like this:

回到 Spring Security 配置,您可以像这样配置您的 url:

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

I don't want to use Basic authentication

我不想使用基本身份验证

Yep, via token filter, your users will be authenticated.

是的,通过令牌过滤器,您的用户将通过身份验证。

Java code configuration (not XML)

Java 代码配置(非 XML)

Back to the words above, look at @EnableWebSecurity. Your class will be:

回到上面的话,看看@EnableWebSecurity。你的班级将是:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {}

You have to override the configuremethod. Code below, just for example, how to configure matchers. It's from another project.

您必须覆盖配置方法。下面的代码,仅举例说明如何配置匹配器。它来自另一个项目。

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

回答by serkan ersoy

I searched this long time too.I am working on a similar project.I found out Spring has a module to implement session via redis. It looks easy and useful. I will add to my project too. Can be helpful:

我也搜索了很长时间。我正在做一个类似的项目。我发现Spring有一个模块可以通过redis实现会话。它看起来简单而有用。我也会添加到我的项目中。可能有帮助:

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

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

回答by Nalla Srinivas

Spring security also very useful for providing authentication and authorization to the REST URLs. We no need to specify any custom implementations.

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

First, you need to specify the entry-point-ref to restAuthenticationEntryPoint in your security configuration as below.

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

Implementation for the restAuthenticationEntryPoint might be as below.

restAuthenticationEntryPoint 的实现可能如下所示。

 @Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

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

After this you need to specify RequestHeaderAuthenticationFilter. It contains the RequestHeader key. This is basically used for identifying the user`s authentication. Generally RequestHeader carries this information while making the REST calls. For example consider below code

在此之后,您需要指定 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>

Here,

这里,

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

"Authorization" is the the key presented the incoming request. It holds the required user`s authentication information. Also you need to configure the PreAuthenticatedAuthenticationProvider to fulfill our requirement.

“授权”是传入请求的密钥。它保存所需用户的身份验证信息。您还需要配置 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>

This code will work for securing the REST urls by means of Authentication and authorization without any custom implementations.

此代码将通过身份验证和授权保护 REST url,无需任何自定义实现。

For Complete code please find the below link:

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

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

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

回答by jeet singh parmar

To validate REST API there are 2 ways

要验证 REST API,有两种方法

1 - Basic authentication using default username and password set up in application.properties file

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

Basic Authentication

基本认证

2 - Authenticate using database (userDetailsService) with the actual username and password

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

Advanced Authentication

高级认证