Question

I am trying to consume a RESTful API using AA. My API receives email and password request parameters (not JSON!) and returns an APIKey (which I use Jackson2 to deserialize).

Ideally, I want to use a regular old Map<String, String> to send the email and password, but it appears AA requires me to use a MultiValueMap (which is a Map<K,List<V>>), or a custom class (Event, which has no source shown).

When using a MultiValueMap, an array is sent. I am not sending an array of email and passwords, I am sending a single email and password:

// LoginFragment.java            
MultiValueMap<String, String> credentials = new LinkedMultiValueMap<String, String>();
credentials.add("email", email);
credentials.add("password", password);
APIKey resp = userRest.login(credentials);


// UserRest.java
@Post("user/login")
public APIKey login(MultiValueMap credentials);

Which trips up my API, because it expects a String rather than an array of Strings.

So I'm thinking I have to create a custom Credentials object to hold my email and password, and somehow get it serialized to be sent to the server. Could someone help me out with this?

Était-ce utile?

La solution

Have you not looked at using the built in Authentication mechanisms that Android Annotations provides? Like Basic Auth or OAuth? This might be a cleaner solution.

https://github.com/excilys/androidannotations/wiki/Authenticated-Rest-Client

I have used the Basic Auth options - https://github.com/excilys/androidannotations/wiki/Rest%20API

You just need to add a method to your interface:

void setHttpBasicAuth(String username, String password);

Then call that before making the API call. There should be a similar option for OAuth.

EDIT: You can create a Login POJO to POST to your API:

@JsonInclude(JsonInclude.Include.NON_NULL)
@Generated("org.jsonschema2pojo")
@JsonPropertyOrder({
        "name",
        "password"

})
public class Login{
    @JsonProperty("name")
    private String name;
    @JsonProperty("password")
    private String password;

}

and then in your API Interface you can do the following:

  @Post("user/login")
    public APIKey login(Login credentials);

This will then POST your data to the /user/login method. You might need to add an interceptor depending on what kind of data you wish to parse ie converters = { MappingJacksonHttpMessageConverter.class } etc.

Autres conseils

I know you already figured it out but check out the rest interceptor I use. Basically it attaches an api_key,access_token, and a hmac_sig to each request in the headers. Then you can validate the credientials server side

@EBean(scope = Scope.Singleton)
public class RestInterceptor implements ClientHttpRequestInterceptor {

private int requestCount = 0;

@Pref
MyPrefs_ myPrefs;

private RequestListener mRequestListener;

public interface RequestListener {
    void report(int count);
}

public void setOnRequestListener(RequestListener requestListener) {
    this.mRequestListener = requestListener;
}

public ClientHttpResponse intercept(HttpRequest request, byte[] data, ClientHttpRequestExecution execution)
        throws IOException {

    if (mRequestListener != null) {
        requestCount++;
        mRequestListener.report(requestCount);
    }

    HttpHeaders headers = request.getHeaders();

    long unixTime = System.currentTimeMillis() / 1000L;

    headers.add("request_time", String.valueOf(unixTime));

    if (myPrefs.accessToken().exists()) {

        headers.add("access_token", myPrefs.accessToken().get());


        String hmacInput; //left this part out but basically do something unique to the request here and do the same on the other side.

        String hmacKey = myPrefs.accessToken().getOr("");


        try {
            String hmacSig = hmacSha1(hmacInput, hmacKey);

            headers.add("hmac_sig", hmacSig);

        }
        catch (InvalidKeyException e) {

            e.printStackTrace();
        }
        catch (NoSuchAlgorithmException e) {

            e.printStackTrace();
        }


    }
    if (myPrefs.userId().exists()) {
        headers.add("user_id", String.valueOf(myPrefs.userId().get()));
    }

    headers.add("api_key", "somerandomstring");

    ClientHttpResponse t = execution.execute(request, data);

    if (mRequestListener != null) {

        requestCount--;
        mRequestListener.report(requestCount);
    }

    return t;
}


public void resetRequestCount() {
    this.requestCount = 0;
}

public static String hmacSha1(String value, String key) throws UnsupportedEncodingException,
        NoSuchAlgorithmException, InvalidKeyException {
    String type = "HmacSHA1";
    SecretKeySpec secret = new SecretKeySpec(key.getBytes(), type);
    Mac mac = Mac.getInstance(type);
    mac.init(secret);
    byte[] bytes = mac.doFinal(value.getBytes());
    return bytesToHex(bytes);
}

private final static char[] hexArray = "0123456789abcdef".toCharArray();

private static String bytesToHex(byte[] bytes) {
    char[] hexChars = new char[bytes.length * 2];
    int v;
    for (int j = 0; j < bytes.length; j++) {
        v = bytes[j] & 0xFF;
        hexChars[j * 2] = hexArray[v >>> 4];
        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
    }
    return new String(hexChars);
}

}

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top