我尝试为 Akeneo PIM 编写 Java Jersey 客户端。
当尝试获取访问 token 时,出现 422 响应状态:
{"code":422,"message":"Parameter \"grant_type\", \"username\" or \"password\" is missing, empty or invalid"}
我认为 Body 中对象的编码存在问题。
当我删除 ClientConfig 时,我遇到了另一个问题:
com.sun.jersey.api.client.ClientHandlerException:com.sun.jersey.api.client.ClientHandlerException:Java 类型、类 com.omb.akeneo.akeneoclient.json.UserAuthenticationInfoJson 和 MIME 的消息正文编写器找不到媒体类型 application/json
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.omb.akeneo</groupId>
<artifactId>akeneo-client</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>akeneo-client</name>
<description></description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Jersy dependencies -->
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-bundle</artifactId>
<version>1.19.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.10.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.10.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider -->
**<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.10.1</version>
</dependency>**
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
<!-- Apache Commons lib -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<classifier>exec</classifier>
</configuration>
</plugin>
</plugins>
</build>
</project>
帖子正文对象
包 com.omb.akeneo.akeneoclient.json;
导入com.fasterxml.jackson.annotation.JsonCreator; 导入 com.fasterxml.jackson.annotation.JsonProperty;
公共(public)类 UserAuthenticationInfoJson {
private String username;
private String password;
private String grantType;
public UserAuthenticationInfoJson() {
}
@JsonCreator
public UserAuthenticationInfoJson(
@JsonProperty("username") String username,
@JsonProperty("password")String password,
@JsonProperty("grant_type") String grantType) {
super();
this.username = username;
this.password = password;
this.grantType = grantType;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getGrantType() {
return grantType;
}
public void setGrantType(String grantType) {
this.grantType = grantType;
}
}
响应对象
package com.omb.akeneo.akeneoclient.json;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.annotation.*;
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonPropertyOrder({
"access_token",
"expires_in",
"token_type",
"scope",
"refresh_token"
})
public class UserTokenJson {
@JsonProperty("access_token")
private String accessToken;
@JsonProperty("expires_in")
private Integer expiresIn;
@JsonProperty("token_type")
private String tokenType;
@JsonProperty("scope")
private Object scope;
@JsonProperty("refresh_token")
private String refreshToken;
@JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
@JsonProperty("access_token")
public String getAccessToken() {
return accessToken;
}
@JsonProperty("access_token")
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
@JsonProperty("expires_in")
public Integer getExpiresIn() {
return expiresIn;
}
@JsonProperty("expires_in")
public void setExpiresIn(Integer expiresIn) {
this.expiresIn = expiresIn;
}
@JsonProperty("token_type")
public String getTokenType() {
return tokenType;
}
@JsonProperty("token_type")
public void setTokenType(String tokenType) {
this.tokenType = tokenType;
}
@JsonProperty("scope")
public Object getScope() {
return scope;
}
@JsonProperty("scope")
public void setScope(Object scope) {
this.scope = scope;
}
@JsonProperty("refresh_token")
public String getRefreshToken() {
return refreshToken;
}
@JsonProperty("refresh_token")
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
@JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
@JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
我的客户:
package com.omb.akeneo.akeneoclient.client;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
import com.sun.jersey.api.client.filter.LoggingFilter;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
import java.security.InvalidParameterException;
/**
* Jersy client to acces Akeneo web api
*/
public class MyAkeneoClient {
/**
* credentials to acces at Akeneo api
*/
private Credentials credential;
/**
* Endpoint of Akeneo api
*/
private String endpoint;
/**
* Jersy client
*/
private Client client;
/**
* Initialise a new Akeneo client
* @param username
* @param password
* @param endpoint
*/
public KAkeneoClient(String clientId, String secret, String username, String password, String endpoint) {
// Check input params
checkParams(clientId, secret, username, password, endpoint);
this.credential = new Credentials(clientId, secret, username, password);
this.endpoint = endpoint;
**ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getClasses().add(JacksonJsonProvider.class);
this.client = Client.create(clientConfig);**
this.client.addFilter(new LoggingFilter(System.out));
}
private void checkParams(String clientId, String secret, String username, String password, String endpoint) throws InvalidParameterException {
if(StringUtils.isBlank(username)) {
throw new InvalidParameterException("The username parameter is not valid");
}
if(StringUtils.isBlank(username)) {
throw new InvalidParameterException("The username parameter is not valid");
}
if(StringUtils.isBlank(password)) {
throw new InvalidParameterException("The password parameter is not valid");
}
if(StringUtils.isBlank(endpoint)) {
throw new InvalidParameterException("The endpoint parameter is not valid");
}
}
public Client getClient() {
return client;
}
public String getEndpoint() {
return endpoint;
}
}
Jersey 客户端:
package com.omb.akeneo.akeneoclient.utils;
import com.omb.akeneo.akeneoclient.Constants;
import com.omb.akeneo.akeneoclient.client.MyAkeneoClient ;
import com.omb.akeneo.akeneoclient.json.UserAuthenticationInfoJson;
import com.omb.akeneo.akeneoclient.json.UserTokenJson;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import org.apache.commons.codec.binary.Base64;
import javax.ws.rs.core.MediaType;
public class AuthUtil {
/**
*
* @param clientId
* @param secret
* @param endpoint
* @param authenticationInfoJson
* @return
*/
public static String getAccesToken(final String clientId, final String secret, final String endpoint, final UserAuthenticationInfoJson authenticationInfoJson) {
MyAkeneoClient akeneoClient = new MyAkeneoClient (clientId, secret, authenticationInfoJson.getUsername(), authenticationInfoJson.getPassword(), endpoint);
StringBuilder url = new StringBuilder(akeneoClient.getEndpoint()).append(Constants.GET_ACCES_TOKEN_ENDPOINT);
WebResource webResource = akeneoClient.getClient().resource(url.toString());
StringBuilder autorization = new StringBuilder("Basic ").append(AuthUtil.getBase64(clientId, secret));
ClientResponse response = webResource
.header("Authorization", autorization.toString())
.type(MediaType.APPLICATION_JSON)
.post(ClientResponse.class, authenticationInfoJson);
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
UserTokenJson userTokenJson = response.getEntity(UserTokenJson.class);
return userTokenJson.getAccessToken();
}
/**
*
* get Base64 encode of clientId et secret
* @param clientId
* @param secret
* @return
*/
public static String getBase64(String clientId, String secret) {
StringBuilder key = new StringBuilder(clientId).append(":").append(secret);
String rs = clientId + ":" + secret;
return Base64.encodeBase64String(rs.getBytes());
}
}
最佳答案
我解决了我的问题,Apache 默认情况下不会将授权 header 传递给 PHP。
您应该在 VirtualHost 定义中添加以下行:SetEnvIf Authorization "(.*)"HTTP_AUTHORIZATION=$1 :
/etc/apache2/sites-available/your_application.conf
<VirtualHost>
.... other config....
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
.... other config
</VirtualHost>
对于感兴趣的人,我通过使用 Jersey spring-boot-starter 和 json spring-boot-starter 更改了我的实现。
所以现在我有了
pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Apache Commons lib -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.13</version>
</dependency>
</dependencies>
客户端
package com.omb.akeneo.akeneoclient.client;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.client.ClientConfig;
import org.springframework.web.filter.AbstractRequestLoggingFilter;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import java.security.InvalidParameterException;
/**
* Jersy client to acces Akeneo web api
*/
public class MyAkeneoClient {
/**
* credentials to acces at Akeneo api
*/
private Credentials credential;
/**
* Endpoint of Akeneo api
*/
private String endpoint;
/**
* Jersy client
*/
private Client client;
/**
* Initialise a new Akeneo client for omb
* @param username
* @param password
* @param endpoint
*/
public KAkeneoClient(String clientId, String secret, String username, String password, String endpoint) {
// Check input params
checkParams(clientId, secret, username, password, endpoint);
this.credential = new Credentials(clientId, secret, username, password);
this.endpoint = endpoint;
client = ClientBuilder.newClient( new ClientConfig().register( AbstractRequestLoggingFilter.class ) );
}
private void checkParams(String clientId, String secret, String username, String password, String endpoint) throws InvalidParameterException {
if(StringUtils.isBlank(username)) {
throw new InvalidParameterException("The username parameter is not valid");
}
if(StringUtils.isBlank(username)) {
throw new InvalidParameterException("The username parameter is not valid");
}
if(StringUtils.isBlank(password)) {
throw new InvalidParameterException("The password parameter is not valid");
}
if(StringUtils.isBlank(endpoint)) {
throw new InvalidParameterException("The endpoint parameter is not valid");
}
}
public Client getClient() {
return client;
}
public String getEndpoint() {
return endpoint;
}
}
泽西客户端
package com.omb.akeneo.akeneoclient.utils;
import com.omb.akeneo.akeneoclient.Constants;
import com.omb.akeneo.akeneoclient.client.MyAkeneoClient;
import com.omb.akeneo.akeneoclient.json.UserAuthenticationInfoJson;
import com.omb.akeneo.akeneoclient.json.UserTokenJson;
import org.apache.commons.codec.binary.Base64;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
public class AuthUtil {
/**
*
* @param clientId
* @param secret
* @param endpoint
* @param authenticationInfoJson
* @return
*/
public static String getAccesToken(final String clientId, final String secret, final String endpoint, final UserAuthenticationInfoJson authenticationInfoJson) {
MyAkeneoClient akeneoClient = new MyAkeneoClient(clientId, secret, authenticationInfoJson.getUsername(), authenticationInfoJson.getPassword(), endpoint);
StringBuilder url = new StringBuilder(akeneoClient.getEndpoint()).append(Constants.GET_ACCES_TOKEN_ENDPOINT);
WebTarget webTarget = akeneoClient.getClient().target(url.toString());
StringBuilder autorization = new StringBuilder("Basic ").append(AuthUtil.getBase64(clientId, secret));
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON);
invocationBuilder.header("Authorization", autorization.toString());
Response response = invocationBuilder.post(Entity.entity(authenticationInfoJson, MediaType.APPLICATION_JSON));
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
UserTokenJson userTokenJson = response.readEntity(UserTokenJson.class);
return userTokenJson.getAccessToken();
}
/**
*
* get Base64 encode of clientId et secret
* @param clientId
* @param secret
* @return
*/
public static String getBase64(String clientId, String secret) {
StringBuilder key = new StringBuilder(clientId).append(":").append(secret);
String rs = clientId + ":" + secret;
return Base64.encodeBase64String(rs.getBytes());
}
}
关于java - 使用 JSONConfiguration.FEATURE_POJO_MAPPING 的 HTTP 错误代码 422,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59502882/