Java 11 HttpClient - 缺少表单参数:grant_type
Java 11 HttpClient - Missing form parameter: grant_type
我正在尝试通过 Java11 的 HttpClient 从 Keycloack 服务器获取访问令牌。但我一直收到错误消息:
{
"error":"invalid_request",
"error_description":"Missing form parameter: grant_type"
}
对了,有postman,我可以拿到token。我在代码中所做的是:
Map<String, String> values = new HashMap<>() {{
put("username", username);
put ("password", password);
put("grant_type", "password");
}};
ObjectMapper objectMapper = new ObjectMapper();
String requestBody = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(values);
HttpRequest request=HttpRequest.newBuilder()
.uri(URI.create(tokenEndpoint))
.setHeader("client_id", clientId)
.setHeader("client_secret", clientSecret)
.setHeader("content-type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpClient.newHttpClient()
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
/*
//Tried also
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
*/
我做错了什么或遗漏了什么?
无效。
这是我们登录的方式:
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("client_id", keycloakProperties.getResource());
requestParams.add("username", username);
requestParams.add("password", password);
requestParams.add("grant_type", "password");
requestParams.add("client_secret", String.valueOf(keycloakProperties.getCredentials().get("secret")));
requestParams.add("scope", "openid");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
String url = keycloakProperties.getAuthServerUrl() + "/realms/" + keycloakProperties.getRealm() + "/protocol/openid-connect/token";
AccessTokenResponse keycloakAccessToken = getAccessTokenResponse(request, url);
// sometimes SSL handshake was failing, so catching error and trying again :)
private AccessTokenResponse getAccessTokenResponse(HttpEntity<MultiValueMap<String, String>> request, String url) {
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (ResourceAccessException e) {
log.error("KeyCloak getAccessTokenResponse: " + e.getMessage());
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (Exception ex) {
throw ex;
}
} catch (Exception e) {
throw e;
}
}
从行 .setHeader("content-type", "application/x-www-form-urlencoded")
开始,请求需要表单数据,
但您在请求 body 中发送 json(通过 ObjectMapper.writeValueAsString()
)。
如果您尝试发送表单数据,那么这应该是正确的编码:
String requestBody = "username=" + username + "password=" + password + "grant_type=password"
如果 API 需要 JSON,则将内容类型 header 更改为 application/json
:
HttpRequest request=HttpRequest.newBuilder()
...
.setHeader("content-type", "application/json")
...
我最近遇到了这个问题,a 使用 Map 传递参数,使用 Map 我得到 'missing grant_type error',当我将参数的类型更改为 MultiValueMap 时,它起作用了。
我正在尝试通过 Java11 的 HttpClient 从 Keycloack 服务器获取访问令牌。但我一直收到错误消息:
{
"error":"invalid_request",
"error_description":"Missing form parameter: grant_type"
}
对了,有postman,我可以拿到token。我在代码中所做的是:
Map<String, String> values = new HashMap<>() {{
put("username", username);
put ("password", password);
put("grant_type", "password");
}};
ObjectMapper objectMapper = new ObjectMapper();
String requestBody = objectMapper.writerWithDefaultPrettyPrinter()
.writeValueAsString(values);
HttpRequest request=HttpRequest.newBuilder()
.uri(URI.create(tokenEndpoint))
.setHeader("client_id", clientId)
.setHeader("client_secret", clientSecret)
.setHeader("content-type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpClient.newHttpClient()
.sendAsync(request, HttpResponse.BodyHandlers.ofString())
.thenApply(HttpResponse::body)
.thenAccept(System.out::println);
/*
//Tried also
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
*/
我做错了什么或遗漏了什么?
这是我们登录的方式:
MultiValueMap<String, String> requestParams = new LinkedMultiValueMap<>();
requestParams.add("client_id", keycloakProperties.getResource());
requestParams.add("username", username);
requestParams.add("password", password);
requestParams.add("grant_type", "password");
requestParams.add("client_secret", String.valueOf(keycloakProperties.getCredentials().get("secret")));
requestParams.add("scope", "openid");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(requestParams, headers);
String url = keycloakProperties.getAuthServerUrl() + "/realms/" + keycloakProperties.getRealm() + "/protocol/openid-connect/token";
AccessTokenResponse keycloakAccessToken = getAccessTokenResponse(request, url);
// sometimes SSL handshake was failing, so catching error and trying again :)
private AccessTokenResponse getAccessTokenResponse(HttpEntity<MultiValueMap<String, String>> request, String url) {
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (ResourceAccessException e) {
log.error("KeyCloak getAccessTokenResponse: " + e.getMessage());
try {
ResponseEntity<AccessTokenResponse> response = restTemplate.postForEntity(url, request, AccessTokenResponse.class);
return response.getBody();
} catch (Exception ex) {
throw ex;
}
} catch (Exception e) {
throw e;
}
}
从行 .setHeader("content-type", "application/x-www-form-urlencoded")
开始,请求需要表单数据,
但您在请求 body 中发送 json(通过 ObjectMapper.writeValueAsString()
)。
如果您尝试发送表单数据,那么这应该是正确的编码:
String requestBody = "username=" + username + "password=" + password + "grant_type=password"
如果 API 需要 JSON,则将内容类型 header 更改为 application/json
:
HttpRequest request=HttpRequest.newBuilder()
...
.setHeader("content-type", "application/json")
...
我最近遇到了这个问题,a 使用 Map 传递参数,使用 Map 我得到 'missing grant_type error',当我将参数的类型更改为 MultiValueMap 时,它起作用了。