You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android获取HERE地图OAuth Token遇401300签名不匹配错误求助

HERE地图Android端OAuth Token获取失败(401300签名不匹配)

我正按照HERE地图身份与访问管理开发者教程获取OAuth Token,iOS应用可正常获取,但Android端始终失败,持续报错:

errorCode: '401300'. Signature mismatch. Authorization signature or client credential is wrong.

以下是我的实现代码:

HEREOAuthManager.java

public void fetchOAuthToken(final HereTokenFetchListener callback) {
    String timestamp = String.valueOf(String.valueOf(Instant.now().getEpochSecond()));
    String nonce = Util.randomStringGenerator();
    String grant_type = "grant_type=client_credentials";
    String oauth_consumer_key = "&oauth_consumer_key=" + clientID;
    String oauth_nonce = "&oauth_nonce=" + nonce;
    String oauth_signature_method = "&oauth_signature_method=HMAC-SHA256";
    String oauth_timestamp = "&oauth_timestamp=" + timestamp;
    String oauth_version = "&oauth_version=1.0";

    String paramsString = grant_type + oauth_consumer_key + oauth_nonce + oauth_signature_method + oauth_timestamp + oauth_version;
    String baseString = "POST&" + Util.urlEncode(tokenEndpoint) + "&" + Util.urlEncode(paramsString);

    // Generate signature
    String secret = Util.urlEncode(clientSecret) + "&";
    String signature = Util.calculateHmacSha256(secret, baseString);

    // Construct Authorization header
    String authString = "OAuth oauth_consumer_key=\"" + clientID + "\",oauth_nonce=\"" + nonce +
            "\",oauth_signature=\"" + Util.urlEncode(signature) + "\",oauth_signature_method=\"HMAC-SHA256\"," +
            "oauth_timestamp=\"" + timestamp + "\",oauth_version=\"1.0\"";

    // Create HTTP client
    OkHttpClient client = new OkHttpClient();

    // Create request body
    RequestBody requestBody = new FormBody.Builder()
            .add("grant_type", "client_credentials")
            .build();

    // Create HTTP request
    Request request = new Request.Builder()
            .url(tokenEndpoint)
            .post(requestBody)
            .addHeader("Authorization", authString)
            .addHeader("Content-Type", "application/x-www-form-urlencoded")
            .build();
}

Utils.java

public static String calculateHmacSha256(String secret, String data) {
    try {
        String secretWithAmpersand = secret + "&";
        SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(secretKeySpec);
        byte[] hmacData = mac.doFinal(data.getBytes(StandardCharsets.UTF_8));
        String baseEncodedSignature = Base64.getEncoder().encodeToString(hmacData);
        return urlEncode(baseEncodedSignature);

    } catch (NoSuchAlgorithmException | InvalidKeyException e) {
        e.printStackTrace();
        return null;
    }
}

public static String urlEncode(String stringToEncode) {
    try {
        return java.net.URLEncoder.encode(stringToEncode, "UTF-8")
                .replace("+", "%20") // Replace '+' with '%20'
                .replace("=", "%3D")
                .replace("*", "%2A") // Replace '*' with '%2A'
                .replace("&", "%26")
                .replace( "~","%7E"); // Replace '~' with '%7E';
    } catch (java.io.UnsupportedEncodingException e) {
        e.printStackTrace();
        return null;
    }
}

public static String randomStringGenerator()
{
    String ALLOWED_CHARACTERS ="0123456789qwertyuiopasdfghjklzxcvbnm";
    final Random random=new Random();
    final StringBuilder sb=new StringBuilder(8);
    for(int i=0;i<8;++i)
        sb.append(ALLOWED_CHARACTERS.charAt(random.nextInt(ALLOWED_CHARACTERS.length())));
    return sb.toString();
}

排查出的核心问题及修复方案:

1. 签名密钥重复拼接&

在fetchOAuthToken中已将secret拼接为Util.urlEncode(clientSecret) + "&",但calculateHmacSha256里又执行了secretWithAmpersand = secret + "&",最终密钥变成urlEncode(clientSecret)&&,违反OAuth 1.0a规范(正确格式应为urlEncode(clientSecret)&)。

修复:删除calculateHmacSha256中的secretWithAmpersand变量,直接用传入的secret构建密钥:

SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");

2. 签名被双重URL编码

calculateHmacSha256已对base64签名执行urlEncode,但构造authString时又再次调用Util.urlEncode(signature),导致签名编码两次,直接引发不匹配。

修复:构造Authorization头时直接使用签名值:

String authString = "OAuth oauth_consumer_key=\"" + clientID + "\",oauth_nonce=\"" + nonce +
        "\",oauth_signature=\"" + signature + "\",oauth_signature_method=\"HMAC-SHA256\"," +
        "oauth_timestamp=\"" + timestamp + "\",oauth_version=\"1.0\"";

3. OAuth参数未按字典序排序

OAuth 1.0a要求baseString中的参数必须按字典序排序,当前直接拼接的方式存在潜在排序风险,可能因字符排序逻辑差异导致签名不匹配。

修复:用TreeMap自动排序参数后再拼接:

Map<String, String> paramsMap = new TreeMap<>();
paramsMap.put("grant_type", "client_credentials");
paramsMap.put("oauth_consumer_key", clientID);
paramsMap.put("oauth_nonce", nonce);
paramsMap.put("oauth_signature_method", "HMAC-SHA256");
paramsMap.put("oauth_timestamp", timestamp);
paramsMap.put("oauth_version", "1.0");

StringBuilder paramsBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
    if (paramsBuilder.length() > 0) {
        paramsBuilder.append("&");
    }
    paramsBuilder.append(Util.urlEncode(entry.getKey()))
                 .append("=")
                 .append(Util.urlEncode(entry.getValue()));
}
String paramsString = paramsBuilder.toString();

修复以上三点后,应该可以正常获取OAuth Token。

内容的提问来源于stack exchange,提问作者user2574903

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 16:18:09