前言
在集成百度地图 API 时,若开启了 SN 权限校验,Java 开发者常会遇到签名生成的难题。本文结合搜索 2.0 接口,梳理 SN 签名的核心逻辑与 Java 实现细节,帮助解决常见的校验失败问题。
SN 签名简介
什么是 SN 签名
SN(Signature)是百度地图用于验证请求合法性的安全机制。相比仅使用 AK 的访问方式,启用 SN 校验能有效防止密钥泄露导致的滥用风险。在之前的开发中,我们可能仅申请了应用并分配了 AK,通过 AK 完成接口调用。但在使用部分高级服务或特定配置下,必须携带 SN 参数。
根据官方文档,当 AK 的校验方式为 SN 校验时,sn 和 timestamp 为必填参数。这确保了每次请求的唯一性和时效性。
如何开启 SN 签名
登录百度地图开放平台控制台,创建新应用或修改现有应用的校验方式。注意:
- 服务端 AK 不再支持浏览器端使用,请根据场景选择'服务端 AK'或'浏览器端 AK'。
- 请求校验方式默认使用 IP 限制,此处需选择 SN 校验。
提交后,系统会生成对应的 SK(Secret Key),请务必保存好,后续签名计算将用到它。
SN 签名算法
SN 的计算依赖于参数顺序。GET 请求建议使用 LinkedHashMap 保持插入顺序;POST 请求则可用 TreeMap 自动排序。核心流程如下:
- 将所有请求参数(不含 sn)按 key 排序拼接成字符串。
- 在字符串末尾追加 SK。
- 对整体字符串进行 UTF-8 URL 编码。
- 对编码后的字符串进行 MD5 加密,生成小写 32 位签名。
以检索接口为例,基础路径为 https://api.map.baidu.com/place/v2/search?,配合 query、region 等参数即可生成完整签名。
Java 中的应用
本节以地点搜索为例,展示如何在 Java 环境中实现 SN 签名的生成及具体调用。
请求 Map 参数化
首先定义一个数据请求参数 Map。由于 GET 请求依赖参数顺序,这里使用 LinkedHashMap。
Map<String, String> params = new LinkedHashMap<>();
String query = "邮政";
String region = "158"; // 158 表示长沙市
String scope = "2";
String output = "json";
String ret_coordtype = "WGS84";
int pageSize = 20;
int pageNum = 0;
params.put("query", query);
params.put("region", region);
params.put("output", output);
params.put("scope", scope);
params.put("ret_coordtype", ret_coordtype);
params.put("page_size", String.valueOf(pageSize));
params.put("page_num", String.valueOf(pageNum));
params.put("ak", AK);
这个 Map 是生成 SN 签名的基础,后续的认证过程都会基于此结构。
SN 签名生成
为了处理中文及特殊字符,需先统一编码。核心是将 Map 拼接成请求字符串,并追加 SK。
// 对 Map 内所有 value 作 utf8 编码,拼接返回结果
public String toQueryString(Map<?, ?> data) throws UnsupportedEncodingException {
StringBuffer queryString = new StringBuffer();
for (Map.Entry<?, ?> pair : data.entrySet()) {
queryString.append(pair.getKey() + "=");
// 使用 Spring 工具类或 JDK 自带转码均可,注意替换 + 为 %20
queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
}
if (queryString.length() > 0) {
queryString.deleteCharAt(queryString.length() - 1);
}
return queryString.toString();
}
// 拼接前缀和 SK,例如 /place/v2/search?...&sk=your_sk
String wholeStr = "/place/v2/search?" + paramsStr + SK;
// 再次进行 UTF-8 URL 编码
String tempStr = URLEncoder.encode(wholeStr, "UTF-8");
// 调用 MD5 加密生成 SN 值
String sn = md5(tempStr);
MD5 实现可复用标准库,关键在于确保字节数组转换回十六进制字符串时的格式正确。
搜索接口调用
构建完整的 HTTP 请求对象发送网络请求。以下代码展示了原生 Java 发起 GET 请求的逻辑。
public void requestGetSN(String strUrl, Map<String, String> param) throws Exception {
if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
return;
}
StringBuffer queryString = new StringBuffer();
queryString.append(strUrl);
for (Map.Entry<?, ?> pair : param.entrySet()) {
queryString.append(pair.getKey() + "=");
queryString.append(UriUtils.encode((String) pair.getValue(), "UTF-8") + "&");
}
if (queryString.length() > 0) {
queryString.deleteCharAt(queryString.length() - 1);
}
java.net.URL url = new URL(queryString.toString());
URLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.connect();
InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
BufferedReader reader = new BufferedReader(isr);
StringBuffer buffer = new StringBuffer();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
}
reader.close();
isr.close();
System.out.println("Response: " + buffer.toString());
}
在 Main 方法中组装参数,填入您的 AK 和 SK 即可运行。成功的话,控制台将返回包含位置数据的 JSON 响应。
APP SN 校验失败可能的原因
实际开发中,签名错误通常由以下几个细节导致。
字符编码问题
API 请求中包含中文或特殊字符(如 query、region)时,必须进行 UTF-8 编码。URL 非保留字(a-z, A-Z, 0-9, -, _, ., ~)无需编码,其余字符(包括中文、问号、空格等)均需转义。例如 region 取值为 ?北京,其中的问号也必须编码。
参数顺序
SN 算法对参数顺序敏感。如果随意调整请求参数的顺序,计算出的 MD5 值必然不同,导致服务端校验失败。
例如,未替换前的 SN 值为 ba424c6d...,调整后变为 0d5e1ea0...,此时接口会返回 APP SN 校验失败。因此,务必保证本地生成的参数顺序与服务端期望一致,通常遵循 LinkedHashMap 的插入顺序。
timestamp 的设置
官方文档规定设置 SN 后 timestamp 必填。但在实测中,部分版本未传递该参数也不影响请求。建议在实际项目中仍遵循文档要求添加该字段,以确保兼容性。
总结
本文详细拆解了 Java 环境下百度地图 SN 权限签名的生成流程与调用实践。从参数构造、编码处理到 MD5 加密,每一步都直接影响接口的可用性。遇到校验失败时,优先检查参数顺序和字符编码。掌握这些细节,能帮助开发者更稳定地集成百度地图服务。


