【问题标题】:How to add basic auth to Autowired testRestTemplate in SpringBootTest; Spring Boot 1.4如何在 SpringBootTest 中向 Autowired testRestTemplate 添加基本身份验证;春季启动 1.4
【发布时间】:2023-03-03 08:04:24
【问题描述】:

我在 Spring Boot 1.4 之前的 OAuth 集成测试如下(更新只是为了不使用已弃用的功能):

@RunWith(SpringRunner.class)
@SpringBootTest(classes = { ApplicationConfiguration.class }, webEnvironment = WebEnvironment.RANDOM_PORT)
public class OAuth2IntegrationTest {

    @Value("${local.server.port}")
    private int port;

    private static final String CLIENT_NAME = "client";
    private static final String CLIENT_PASSWORD = "123456";

    @Test
    public void testOAuthAccessTokenIsReturned() {
        MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
        request.set("username", "user");
        request.set("password", password);
        request.set("grant_type", "password");
        @SuppressWarnings("unchecked")
        Map<String, Object> token = new TestRestTemplate(CLIENT_NAME, CLIENT_PASSWORD)
            .postForObject("http://localhost:" + port + "/oauth/token", request, Map.class);
        assertNotNull("Wrong response: " + token, token.get("access_token"));
    }
}

我现在想使用此处所述的 Autowired TestRestTemplate http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-working-with-random-ports

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
    ApplicationConfiguration.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class OAuth2IntegrationTest {

    private static final String CLIENT_NAME = "client";
    private static final String CLIENT_PASSWORD = "123456";

    @Autowired
    private TestRestTemplate testRestTemplate;

    @Test
    public void testOAuthAccessTokenIsReturned() {
        MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
        request.set("username", "user");
        request.set("password", password);
        request.set("grant_type", "password");
        @SuppressWarnings("unchecked")

        Map<String, Object> token1 = this.testRestTemplate. //how to add basic auth here
        assertNotNull("Wrong response: " + token, token.get("access_token"));
    }
}

我认为这是添加身份验证的最接近的方法:

Spring 4.0.0 basic authentication with RestTemplate

我想使用 Autowired testRestTemplate 来避免在我的测试中解析主机和端口。有没有办法做到这一点?

【问题讨论】:

  • public TestRestTemplate withBasicAuth(String username, String password) 这看起来只在spring boot 1.4.1中可用,这是解决方案吗

标签: spring-mvc spring-security spring-boot spring-test-mvc


【解决方案1】:

这在 Spring Boot 1.4.1 中得到了修复,它有一个额外的方法

testRestTemplate.withBasicAuth(USERNAME,PASSWORD)

@Autowired
private TestRestTemplate testRestTemplate;

@Test
public void testOAuthAccessTokenIsReturned() {
    MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
    request.set("username", USERNAME);
    request.set("password", password);
    request.set("grant_type", "password");
    @SuppressWarnings("unchecked")
    Map<String, Object> token = this.testRestTemplate.withBasicAuth(CLIENT_NAME, CLIENT_PASSWORD)
            .postForObject(SyntheticsConstants.OAUTH_ENDPOINT, request, Map.class);
    assertNotNull("Wrong response: " + token, token.get("access_token"));
}

【讨论】:

  • 有没有办法在更中心的地方做到这一点?这样,我将不得不在每个需要基本身份验证的测试用例中重复密码。 TestRestTemplate 可以用来始终以某种方式使用基本身份验证吗?如何将 testRestTemplate 作为@Bean 注入?
【解决方案2】:

有一个更好的解决方案,因此您无需每次都重新输入 withBasicAuth 部分

@Autowired
private TestRestTemplate testRestTemplate;

@BeforeClass
public void setup() {
    BasicAuthorizationInterceptor bai = new BasicAuthorizationInterceptor(CLIENT_NAME, CLIENT_PASSWORD);
    testRestTemplate.getRestTemplate().getInterceptors().add(bai);
}

@Test
public void testOAuthAccessTokenIsReturned() {
    MultiValueMap<String, String> request = new LinkedMultiValueMap<String, String>();
    request.set("username", USERNAME);
    request.set("password", password);
    request.set("grant_type", "password");
    @SuppressWarnings("unchecked")
    Map<String, Object> token = this.testRestTemplate.postForObject(SyntheticsConstants.OAUTH_ENDPOINT, request, Map.class);
    assertNotNull("Wrong response: " + token, token.get("access_token"));
}

【讨论】:

  • 这不起作用,因为设置方法需要是静态的
  • 你可以试试@BeforeEach,不需要是静态的
【解决方案3】:

虽然the accepted answer 是正确的,但就我而言,我必须在每个测试方法和类中复制testRestTemplate.withBasicAuth(...)

所以,我尝试在src/test/java/my.microservice.package 中定义这样的配置:

@Configuration
@Profile("test")
public class MyMicroserviceConfigurationForTest {

    @Bean
    public TestRestTemplate testRestTemplate(TestRestTemplate testRestTemplate, SecurityProperties securityProperties) {
        return testRestTemplate.withBasicAuth(securityProperties.getUser().getName(), securityProperties.getUser().getPassword());
    }

}

似乎具有覆盖默认 TestRestTemplate 定义的效果,允许在我的测试类中的任何位置注入凭据感知 TestRestTemplate

我不完全确定这是否真的是一个有效的解决方案,但你可以试一试......

【讨论】:

    【解决方案4】:

    如果您仍在应用程序中使用基本身份验证,我认为有更好的解决方案,并在 application.properties 文件中设置“user.name”和“user.password”属性:

    public class YourEndpointClassTest {
        private static final Logger logger = LoggerFactory.getLogger(YourEndpointClassTest.class);  
    
        private static final String BASE_URL = "/your/base/url";
    
        @TestConfiguration
        static class TestRestTemplateAuthenticationConfiguration {
    
            @Value("${spring.security.user.name}")
            private String userName;
    
            @Value("${spring.security.user.password}")
            private String password;
    
            @Bean
            public RestTemplateBuilder restTemplateBuilder() {
                return new RestTemplateBuilder().basicAuthentication(userName, password);
            }
        }
    
    
        @Autowired
        private TestRestTemplate restTemplate;
    
    //here add your tests...
    

    【讨论】:

    • 没有直接为我工作,但有一个单独的 @Configuration 注释类,它实现了所示的 restTemplateBuilder() 方法。
    【解决方案5】:

    在单个测试用例中,您可以这样做:

    @Test
    public void test() {
        ResponseEntity<String> entity = testRestTemplate
                .withBasicAuth("username", "password")
                .postForEntity(xxxx,String.class);
        Assert.assertNotNull(entity.getBody());
    }
    

    并为每个测试用例在您的测试类中添加此方法:

    @Before
    public void before() {
        // because .withBasicAuth() creates a new TestRestTemplate with the same 
        // configuration as the autowired one.
         testRestTemplate = testRestTemplate.withBasicAuth("username", "password");
    }
    

    【讨论】:

      猜你喜欢
      • 2022-07-22
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-20
      • 2020-05-26
      • 1970-01-01
      • 2015-01-10
      相关资源
      最近更新 更多