Spring Boot中使用内存进行身份验证保护

x33g5p2x  于2022-09-28 转载在 Spring  
字(6.6k)|赞(0)|评价(0)|浏览(554)

在本教程中,我们将学习如何使用 Spring Boot 为简单的 REST 服务启用内存中基本身份验证。我们将为两个不同的用户配置不同的角色,并添加一个测试类来验证内存中的基本身份验证。

###新建一个Spring Boot项目

首先创建一个基本的 Spring Boot 项目,其中包括以下依赖项:

<?xml version="1.0" encoding="UTF-8"?><project>
   	
   <parent>
       		
      <groupId>org.springframework.boot</groupId>
       		
      <artifactId>spring-boot-starter-parent</artifactId>
       		
      <version>2.1.9.RELEASE</version>
       		
      <relativePath/>
         	
   </parent>
    	
   <groupId>com.example</groupId>
    	
   <artifactId>demo-rest-secured</artifactId>
    	
   <version>0.0.1-SNAPSHOT</version>
    	
   <name>demo</name>
    	
   <description>Demo project for Spring Boot</description>
     	
   <properties>
       		
      <java.version>1.8</java.version>
       	
   </properties>
     	
   <dependencies>
       		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-web</artifactId>
          		
      </dependency>
        		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-test</artifactId>
          			
         <scope>test</scope>
          		
      </dependency>
       		
      <!-- spring security -->
       		
      <dependency>
          			
         <groupId>org.springframework.boot</groupId>
          			
         <artifactId>spring-boot-starter-security</artifactId>
          		
      </dependency>
        		
      <!-- spring security test -->
       		
      <dependency>
          			
         <groupId>org.springframework.security</groupId>
          			
         <artifactId>spring-security-test</artifactId>
          			
         <scope>test</scope>
          		
      </dependency>
        	
   </dependencies>
    
</project>

Spring 安全配置我在扩展WebSecurityConfigurerAdapter 的@Configuration Bean 中定义:

package com.example.testrest;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("user")
        .password("{noop}password")
        .roles("USER")
        .and()
        .withUser("admin")
        .password("{noop}password")
        .roles("USER", "ADMIN");
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.httpBasic()
        .and()
        .authorizeRequests()
        .antMatchers(HttpMethod.GET, "/**")
        .hasRole("USER")
        .antMatchers(HttpMethod.POST, "/")
        .hasRole("ADMIN")
        .and()
        .csrf()
        .disable()
        .formLogin()
        .disable();
  }
}

如您所见,我们添加了两个角色:

  • 属于 USER 角色的用户
  • admin 属于 USER,ADMIN 角色

另外,请注意,在上面的示例中,每个密码都有一个前缀 {x},它指定应该使用什么密码编码器来对提供的密码进行编码。以下是您可以用作密码前缀的不同值:

  • 使用 {bcrypt} 作为 BCryptPasswordEncoder,
  • 使用 {noop} 作为 NoOpPasswordEncoder,
  • 使用 {pbkdf2} 作为 Pbkdf2PasswordEncoder,
  • 将 {scrypt} 用于 SCryptPasswordEncoder,
  • 使用 {sha256} 作为 StandardPasswordEncoder。

因此,为了使用 HTTP POST 方法,您需要“ADMIN”角色,而 HTTP GET 可以由“USER”角色执行。让我们添加一个带有 GET 和 POST 方法的 Controller 类:

package com.example.testrest;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
public class CustomerController {
  @Autowired CustomerRepository repository;

  @RequestMapping(
      method = RequestMethod.GET,
      produces = {"application/json"})
  public List<Customer> findAll() {
    return repository.getData();
  }

  @PostMapping(path = "/", consumes = "application/json", produces = "application/json")
  public ResponseEntity<Customer> addCustomer(@RequestBody Customer customer) throws Exception {
    repository.save(customer);
    return new ResponseEntity<Customer>(customer, HttpStatus.CREATED);
  }
}

Customer 类使用 CustomerRepository 来持久化 Customer 对象。在文章末尾查看此示例的完整代码。

您可以使用基本的 SpringBootApplication 运行该类:

package com.example.testrest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
  public static void main(String[] args) {
    SpringApplication.run(DemoApplication.class, args);
  }
}

为了测试它,我们可以使用 TestRestTemplate 类:

package com.example.testrest;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class DemoApplicationTests {
  private static final ObjectMapper om = new ObjectMapper();
  @Autowired private TestRestTemplate restTemplate;
  @Test public void testCustomerList() throws Exception {
    ResponseEntity < String > response = restTemplate.withBasicAuth("user", "password").getForEntity("/", String.class);
    printJSON(response);
    //Verify user is authorized and content is JSON 	
    assertEquals(MediaType.APPLICATION_JSON_UTF8, response.getHeaders().getContentType());
    assertEquals(HttpStatus.OK, response.getStatusCode());
    Customer c = new Customer(3, "Adam");
    ResponseEntity < String > result = restTemplate.withBasicAuth("user", "password").postForEntity("/", c, String.class);

    //Verify user is unauthorized 		

    Assert.assertEquals(403, result.getStatusCodeValue()); //Verify user is authorized 		

    result = restTemplate.withBasicAuth("admin", "password").postForEntity("/", c, String.class);

    //Verify request succeed 		

    Assert.assertEquals(201, result.getStatusCodeValue());
  }
  private static void printJSON(Object object) {
    String result;
    try {
      result = om.writerWithDefaultPrettyPrinter().writeValueAsString(object);
      System.out.println(result);
    } catch (JsonProcessingException e) {
      e.printStackTrace();
    }
  }
}

在这个测试中,我们执行一组断言。首先,我们使用“用户/密码”凭据执行 HTTP GET。然后,使用相同的凭据,我们尝试执行 HTTP POST。该测试预计会失败。最后,我们使用“admin/password”凭据再次执行 HTTP POST。这有望通过。

运行测试类

您可以使用以下命令运行上述测试:

mvn install

您应该看到测试方法成功完成:

[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.755 s - in com.example.testrest.DemoApplicationTests

恭喜!您刚刚设法针对 REST 服务运行了 Spring 内存中身份验证的第一个基本示例。

完整源代码:https://github.com/fmarchioni/masterspringboot/tree/master/security/rest-inmemory-security

相关文章