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

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

本教程将教您如何使用 JDBC 数据源H2 数据库来保护您的 Spring Boot 应用程序。 我们将创建一个带有两个方法端点的示例 REST 控制器,每个端点都可用于不同的角色。

让我们从包含以下方法的 REST 控制器开始:

@RestController
public class CustomerController {
  @Autowired CustomerRepository repository;

  @RequestMapping(
      path = "/",
      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);
  }
}

这里是 SpringSecurityConfig,它扩展了 WebSecurityConfigurerAdapter。在 configAuthentication 中,我们指定我们将使用 jdbcAuthentication。数据库上的密码将使用 BCryptPasswordEncoder 存储。您可以在本教程中学习如何使用 BCryptPasswordEncoder 加密密码:使用 BCryptPasswordEncoder 加密您的密码

configure 方法中,我们声明了每个方法允许的角色:

@Configuration @EnableAutoConfiguration public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
  @Autowired DataSource dataSource;
  @Autowired public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication().passwordEncoder(new BCryptPasswordEncoder()).dataSource(dataSource);
  }
  @Override protected void configure(HttpSecurity http) throws Exception {
    //HTTP Basic authentication 
    http.httpBasic().and().authorizeRequests().antMatchers(HttpMethod.GET, "/").hasRole("USER").antMatchers(HttpMethod.POST, "/").hasRole("ADMIN").and().csrf().disable().formLogin().disable();
  }
}

如您所见,我们没有指定任何存储用户名、密码和角色的表/关系。事实上,我们将使用默认的表和字段名称,它们是

因此,我们将在资源文件夹中添加两个 sql 脚本。 Schema.sql 用于创建上述表,data.sql 用于插入一些用户:

这是schema.sql:

create table USERS(       username varchar(128) not null primary key,       password varchar(512) not null,       enabled boolean not null);  create table AUTHORITIES (       username varchar(128) not null,       authority varchar(128) not null);  create unique index idx_auth_username on authorities (username,authority);

data.sql:

insert into users (username, password, enabled) values ('adam', '$2a$10$Ptvs9mLVFuEOXC4ckHi1weHGLQ7bGwigKQR5Uk9/aONvmKYPnRl8m', true); insert into authorities (username, authority) values ('adam', 'ROLE_USER');  insert into users (username, password, enabled) values ('jeff', '$2a$10$SRzxfUhAPr3wDJwcIJ/b3ePcJlmaJWOZMafN0dDmAw0ispxdXFi6K', true); insert into authorities (username, authority) values ('jeff', 'ROLE_ADMIN');

以上用户的密码为“password1”和“password2”。它们已使用 BCryptPasswordEncoder 加密。

由于我们将在此示例中使用 H2 数据库,因此在 application.properties 文件中,我们将配置 Datasource 如下:

spring.datasource.url = jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE spring.datasource.username = sa spring.datasource.password = spring.datasource.driverClassName=org.h2.Driver spring.datasource.initialization-mode=always

最后,pom.xml 文件中需要这些依赖项

<?xml version="1.0" encoding="UTF-8"?><project>
       
   <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>
                
      <dependency>
                      
         <groupId>org.springframework.boot</groupId>
                      
         <artifactId>spring-boot-starter-jdbc</artifactId>
                  
      </dependency>
                
      <dependency>
                      
         <groupId>org.springframework.boot</groupId>
                      
         <artifactId>spring-boot-starter-security</artifactId>
                  
      </dependency>
                
      <dependency>
                      
         <groupId>org.springframework.security</groupId>
                      
         <artifactId>spring-security-test</artifactId>
                      
         <scope>test</scope>
                  
      </dependency>
               
      <dependency>
                      
         <groupId>com.h2database</groupId>
                      
         <artifactId>h2</artifactId>
                      
         <scope>runtime</scope>
                  
      </dependency>
           
   </dependencies>
    
</project>

编写测试类

让我们使用 TestRestTemplate 为上述端点编写一个测试:

@RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT) public class DemoApplicationTests {
  private static final ObjectMapper om = new ObjectMapper();

  //@WithMockUser is not working with TestRestTemplate     

  @Autowired private TestRestTemplate restTemplate;
  @Test public void testCustomerList() throws Exception {
    ResponseEntity < String > response = restTemplate.withBasicAuth("adam", "password1").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("adam", "password1").postForEntity("/", c, String.class);
    //Verify user is unauthorized         

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

    result = restTemplate.withBasicAuth("jeff", "password2").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();
    }
  }
}

在这个测试中,我们将检查:

  • 用户“adam”被授权使用 GET Endpoint
  • 用户“adam”无权使用 POST Endpoint
  • 用户“jeff”被授权使用 POST Endpoint

您可以使用以下命令运行它:

mvn clean install

您刚刚学习了如何使用带有 H2 数据库的 JDBC 来保护您的 Spring Boot 应用程序。 如果您想切换到另一个数据库,只需针对其方言调整 sql 脚本并在 pom.xml 和application.properties 中的数据源配置。

本教程的源代码可在此处获得:https://github.com/fmarchioni/masterspringboot/tree/master/security/rest-jdbc-security

相关文章