Я использую Spring-Boot 2.0.2 RestTemplate
для создания следующего сценария:
Я - Потребитель отдыха (клиент), которому:
- сначала нужновойдите в систему Spring-Security-Check
- , затем сделайте второй вызов для получения данных.
Сначала я подумал сделать вызов авторизации и вручную прочитать файл cookie JSESSIONID.из SET-COOKIE и установите его на второй вызов в заголовке.Вот моя первая попытка:
RestClient:
@Service
public class RestClient {
private static final String ENDPOINT_DATA = "/data";
private static final String ENDPOINT_SECURITY_CHECK = "/j_spring_security_check";
private static final String HTTP_HEADER_KEY_SET_COOKIE = "Set-Cookie";
private static final String HTTP_HEADER_KEY_COOKIE = "Cookie";
private static final String PROPERTY_SPRING_SECURITY_USER = "j_username";
private static final String PROPERTY_SPRING_SECURITY_PASS = "j_password";
private final RestTemplate restTemplate;
private final RestConfig restConfig;
@Autowired
public RestClient(RestTemplateBuilder restTemplateBuilder, final RestConfig restConfig) {
notNull(restTemplateBuilder, "restTemplateBuilder must not be null!");
this.restTemplate = restTemplateBuilder
.additionalCustomizers(new NoRedirectionHandlingRestTemplateCostumizer())
.build();
notNull(restConfig, "openIdConfig must not be null!");
this.restConfig = restConfig;
}
public String getData() {
final String jSessionCockie = jSpringSecurityLogin();
return getAuthorizeCode(jSessionCockie);
}
private String jSpringSecurityLogin() {
// read config
final String fullLoginUri = restConfig.getUrl() + ENDPOINT_SECURITY_CHECK;
final String user = restConfig.getUser();
final String password = restConfig.getPassword();
// Build entity that is send
final HttpHeaders headers = new HttpHeaders();
final String body = PROPERTY_SPRING_SECURITY_USER + "=" + user + "&" + PROPERTY_SPRING_SECURITY_PASS + "=" + password;
final HttpEntity<String> toSend = new HttpEntity<>(body, headers);
final String jSessionIdCockie;
final ResponseEntity<String> response = restTemplate.postForEntity(fullLoginUri, toSend, String.class);
// Get String "JSESSIONID=XXXX". If there are other Cookies, propably will fail.
if (HttpStatus.FOUND.equals(response.getStatusCode()) && response.getHeaders().containsKey(HTTP_HEADER_KEY_SET_COOKIE)) {
jSessionIdCockie = response.getHeaders().get(HTTP_HEADER_KEY_SET_COOKIE).get(0);
} else {
throw new Error();
}
return jSessionIdCockie;
}
private String getAuthorizeCode(final String jSessionCockie) {
// read config
final String fullDataUri = restConfig.getUrl() + ENDPOINT_DATA;
// Build entity that is send
final HttpHeaders headers = new HttpHeaders();
headers.add(HTTP_HEADER_KEY_COOKIE, jSessionCockie);
final HttpEntity<Void> toSend = new HttpEntity<>(headers);
final ResponseEntity<String> response = restTemplate.exchange(fullDataUri, HttpMethod.GET, toSend, String.class);
if (HttpStatus.OK.equals(response.getStatusCode()) && response.hasBody()) {
return response.getBody();
} else {
return "";
}
}
}
Чтобы завершить, здесь используется Costumizer в конструкторе:
class NoRedirectionHandlingRestTemplateCostumizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
final HttpClient httpClient = HttpClientBuilder.create()
.disableRedirectHandling()
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
}
Теперь, когда я сделаю несколькоФункциональные тесты с помощью Wiremock Я вижу следующие данные в истории запроса на получение Wiremock для вызова данных:
{
...
"headers":
{
"Cookie": [
"JSESSIONID=axcvueiornxniuwherwuieoiun,asdpfoiu",
"JSESSIONID=axcvueiornxniuwherwuieoiun,asdpfoiu"
],
...
},
"cookies":
{
"JSESSIONID": [
"axcvueiornxniuwherwuieoiun,asdpfoiu",
"axcvueiornxniuwherwuieoiun,asdpfoiu"
]
}
...
}
Ожидание - JSESSIONID устанавливается 2 раза.Крутой REST обрабатывает это для меня!
Вторая попытка: я могу удалить передачу Cookie.И это работает.
Но при первой и второй попытках возникают проблемы: после первого вызова RestClient.getData()
все последующие вызовы конечной точки входа в систему также имеют установленный JSESSIONID.Я не знаю, как Рест-продюсер может справиться с этим (время ожидания сеанса и т. Д.).
Теперь моя проблема / вопрос:
Я хотел бы заставить RestTemplate
забыть / стереть все куки-файлы перед тем, как выполнить вход в систему (описание причины ранее).Есть ли возможность?Я не нашел ничего работающего.
Мой обходной путь сейчас состоит в том, чтобы отключить управление Cookie RestTemplate
и делать все вручную, как при первой попытке.Отключение CookieManagment может быть выполнено через RestTemplateCustomizer
:
class NoRedirectionHandlingRestTemplateCostumizer implements RestTemplateCustomizer {
@Override
public void customize(RestTemplate restTemplate) {
final HttpClient httpClient = HttpClientBuilder.create()
.disableRedirectHandling()
.disableCookieManagement()
.build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));
}
}