基于OAuth2.0与美团开放平台规范实现外卖霸王餐API的安全认证机制

基于OAuth2.0与美团开放平台规范实现外卖霸王餐API的安全认证机制

在当前互联网生态中,第三方开发者通过接入美团开放平台提供的API来扩展自身业务已成为常见模式。以"外卖霸王餐"类功能为例,其核心在于调用美团的订单、用户、门店等接口,实现免单核销、活动发放等操作。然而,这类高敏感操作必须建立在严格的安全认证机制之上。本文将围绕OAuth2.0协议与美团开放平台的认证规范,详细阐述如何安全地实现此类API调用,并提供完整的Java代码示例。

美团开放平台认证机制概述

美团开放平台采用OAuth2.0作为授权框架,结合应用密钥(appKey/appSecret)和访问令牌(access_token)进行身份验证。开发者需先在美团开放平台注册应用,获取 appKey 与 appSecret。每次调用受保护的API前,需携带有效的 access_token,该 token 通过授权码模式或客户端凭证模式获取。

对于"霸王餐"类服务,通常属于服务端到服务端(Server-to-Server)调用,推荐使用客户端凭证模式(Client Credentials Grant) ,即直接使用 appKey 和 appSecret 换取 access_token。

获取Access Token的实现

以下为使用 Java 实现获取 access_token 的核心逻辑,包路径遵循 juwatech.cn.* 命名规范:

java 复制代码
package juwatech.cn.auth;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;

public class MeituanAuthClient {

    private static final String TOKEN_URL = "https://openapi.meituan.com/oauth/access_token";
    private static final String APP_KEY = "your_app_key";
    private static final String APP_SECRET = "your_app_secret";

    public String fetchAccessToken() throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost post = new HttpPost(TOKEN_URL);
        post.setHeader("Content-Type", "application/json");

        String jsonBody = String.format(
            "{\"appkey\":\"%s\",\"secret\":\"%s\",\"grant_type\":\"client_credentials\"}",
            APP_KEY, APP_SECRET
        );
        post.setEntity(new StringEntity(jsonBody, StandardCharsets.UTF_8));

        HttpResponse response = httpClient.execute(post);
        String responseBody = EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
        ObjectMapper mapper = new ObjectMapper();
        JsonNode root = mapper.readTree(responseBody);

        if (root.has("access_token")) {
            return root.get("access_token").asText();
        } else {
            throw new RuntimeException("Failed to obtain access token: " + responseBody);
        }
    }
}

签名机制与请求构造

美团要求所有API请求必须包含签名(sign),以防止参数被篡改。签名算法为 HMAC-SHA256,使用 appSecret 对按字典序排序的请求参数进行签名。

以下为封装带签名的HTTP请求工具类:

java 复制代码
package juwatech.cn.util;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class MeituanSignUtil {

    public static String generateSign(Map<String, String> params, String appSecret) {
        // 按 key 字典序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);

        StringBuilder sb = new StringBuilder();
        for (String key : keys) {
            sb.append(key).append(params.get(key));
        }
        sb.append(appSecret);

        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(secretKeySpec);
            byte[] hash = mac.doFinal(sb.toString().getBytes(StandardCharsets.UTF_8));
            StringBuilder hex = new StringBuilder();
            for (byte b : hash) {
                String hexStr = Integer.toHexString(0xff & b);
                if (hexStr.length() == 1) hex.append('0');
                hex.append(hexStr);
            }
            return hex.toString().toLowerCase();
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            throw new RuntimeException("Signature generation failed", e);
        }
    }
}

调用霸王餐核销API示例

假设我们要调用美团的"霸王餐核销"接口(伪接口路径 /v1/free-meal/verify),需构造带 access_token 和 sign 的请求:

java 复制代码
package juwatech.cn.api;

import juwatech.cn.auth.MeituanAuthClient;
import juwatech.cn.util.MeituanSignUtil;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

public class FreeMealApiInvoker {

    private static final String VERIFY_URL = "https://openapi.meituan.com/v1/free-meal/verify";
    private static final String APP_KEY = "your_app_key";
    private static final String APP_SECRET = "your_app_secret";

    public String verifyFreeMeal(String orderId, String userId) throws Exception {
        MeituanAuthClient authClient = new MeituanAuthClient();
        String accessToken = authClient.fetchAccessToken();

        Map<String, String> params = new HashMap<>();
        params.put("appkey", APP_KEY);
        params.put("orderid", orderId);
        params.put("userid", userId);
        params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));

        String sign = MeituanSignUtil.generateSign(params, APP_SECRET);
        params.put("sign", sign);

        // 构造 JSON 请求体
        StringBuilder json = new StringBuilder("{");
        for (Map.Entry<String, String> entry : params.entrySet()) {
            json.append("\"").append(entry.getKey()).append("\":\"").append(entry.getValue()).append("\",");
        }
        json.setLength(json.length() - 1); // 移除最后一个逗号
        json.append("}");

        CloseableHttpClient client = HttpClients.createDefault();
        HttpPost post = new HttpPost(VERIFY_URL);
        post.setHeader("Authorization", "Bearer " + accessToken);
        post.setHeader("Content-Type", "application/json");
        post.setEntity(new StringEntity(json.toString(), StandardCharsets.UTF_8));

        HttpResponse response = client.execute(post);
        return EntityUtils.toString(response.getEntity(), StandardCharsets.UTF_8);
    }
}

安全注意事项

  1. appSecret 必须保密:严禁硬编码在前端或客户端代码中,应存于服务端配置中心或环境变量。
  2. access_token 缓存:避免频繁请求 token,可缓存至其过期前(通常2小时)。
  3. HTTPS 强制使用:所有与美团API的通信必须通过 HTTPS。
  4. 参数校验:服务端应对传入的 orderId、userId 等做合法性校验,防止注入攻击。

本文著作权归吃喝不愁app开发者团队,转载请注明出处!

相关推荐
大模型玩家七七7 小时前
基于语义切分 vs 基于结构切分的实际差异
java·开发语言·数据库·安全·batch
Hello.Reader15 小时前
Flink ZooKeeper HA 实战原理、必配项、Kerberos、安全与稳定性调优
安全·zookeeper·flink
智驱力人工智能16 小时前
小区高空抛物AI实时预警方案 筑牢社区头顶安全的实践 高空抛物检测 高空抛物监控安装教程 高空抛物误报率优化方案 高空抛物监控案例分享
人工智能·深度学习·opencv·算法·安全·yolo·边缘计算
数据与后端架构提升之路16 小时前
论系统安全架构设计及其应用(基于AI大模型项目)
人工智能·安全·系统安全
市场部需要一个软件开发岗位18 小时前
JAVA开发常见安全问题:Cookie 中明文存储用户名、密码
android·java·安全
lingggggaaaa18 小时前
安全工具篇&动态绕过&DumpLsass凭据&Certutil下载&变异替换&打乱源头特征
学习·安全·web安全·免杀对抗
凯子坚持 c18 小时前
CANN-LLM:基于昇腾 CANN 的高性能、全功能 LLM 推理引擎
人工智能·安全
QT.qtqtqtqtqt19 小时前
未授权访问漏洞
网络·安全·web安全
ba_pi21 小时前
每天写点什么2026-02-04(2.1)信息安全
安全·web安全
枷锁—sha1 天前
Burp Suite 抓包全流程与 Xray 联动自动挖洞指南
网络·安全·网络安全