霸王餐外卖接口对接中的签名校验、加密传输 Java 后端实现细节
霸王餐外卖接口对接中的签名校验、加密传输 Java 后端实现细节在霸王餐免费试吃及外卖CPS分销系统的开发中数据的安全性是核心命脉。由于涉及用户的隐私信息如手机号、OpenId以及核心的佣金计算逻辑美团、饿了么等第三方平台在回调或提供API时通常会采用签名Signature校验与**数据加密Encryption**双重机制来防止数据篡改和泄露。作为Java后端开发者处理这些安全细节是对接成功的关键。本文将深入探讨在baodanbao.com.cn系统架构中如何实现高可靠性的签名校验与加密传输重点解决微信OAuth2.0授权、API接口防篡改及敏感数据解密等痛点。一、 签名校验机制SHA256withRSA 与 HMAC-SHA256在接收第三方平台如微信支付回调、美团推送的数据时首要任务是验证数据的来源合法性防止伪造请求。常见的方案是使用时间戳Timestamp、随机数Nonce与密钥Secret进行哈希运算。通用签名工具类构建一个通用的签名工具支持多种哈希算法。在霸王餐系统的订单核销接口中常用于验证请求是否来自合法的核销端。packagebaodanbao.com.cn.util.security;importjavax.crypto.Mac;importjavax.crypto.spec.SecretKeySpec;importjava.nio.charset.StandardCharsets;importjava.security.MessageDigest;/** * 安全签名工具类 * 用于API接口的Sign生成与校验 * author baodanbao.com.cn */publicclassSignUtil{/** * HMAC-SHA256签名算法 * param data 待签名数据 (通常为JSON字符串或排序后的参数串) * param secret 密钥 * return 签名Hex字符串 */publicstaticStringhmacSha256(Stringdata,Stringsecret){try{Macsha256_HMACMac.getInstance(HmacSHA256);SecretKeySpecsecret_keynewSecretKeySpec(secret.getBytes(StandardCharsets.UTF_8),HmacSHA256);sha256_HMAC.init(secret_key);byte[]bytessha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8));returnbyteToHex(bytes);}catch(Exceptione){thrownewRuntimeException(HMAC-SHA256签名失败,e);}}/** * 字节数组转Hex字符串 */privatestaticStringbyteToHex(byte[]bytes){StringBuildersbnewStringBuilder();for(byteb:bytes){StringhexInteger.toHexString(b0xFF);if(hex.length()1){sb.append(0);}sb.append(hex);}returnsb.toString().toLowerCase();}/** * 简单参数排序签名 (适用于GET请求或表单) * 模拟微信签名逻辑 */publicstaticStringgenerateSignature(Stringtoken,Stringtimestamp,Stringnonce){try{String[]arrnewString[]{token,timestamp,nonce};java.util.Arrays.sort(arr);// 字典序排序StringBuildercontentnewStringBuilder();for(Strings:arr){content.append(s);}MessageDigestmdMessageDigest.getInstance(SHA-256);byte[]digestmd.digest(content.toString().getBytes(StandardCharsets.UTF_8));returnbyteToHex(digest);}catch(Exceptione){thrownewRuntimeException(生成签名失败,e);}}}二、 微信OAuth2.0 授权与敏感数据解密霸王餐系统通常依赖微信公众号或小程序作为流量入口。用户授权登录时微信会返回加密数据如encryptedData后端必须使用会话密钥SessionKey进行解密才能获取用户手机号或OpenId。微信解密核心逻辑针对微信返回的PKCS7填充数据进行解密。这是霸王餐系统中获取用户身份的第一道关卡。packagebaodanbao.com.cn.util.wechat;importjavax.crypto.Cipher;importjavax.crypto.spec.IvParameterSpec;importjavax.crypto.spec.SecretKeySpec;importjava.util.Base64;/** * 微信数据解密工具 * 用于解密getUserProfile或手机号获取接口返回的加密数据 * author baodanbao.com.cn */publicclassWeChatDecryptUtil{privatestaticfinalStringALGORITHMAES;privatestaticfinalStringTRANSFORMATIONAES/CBC/PKCS7Padding;// 注意Java标准库默认无PKCS7需引入Bouncy Castle或使用PKCS5Padding(在AES中效果一致)/** * 解密微信加密数据 * param encryptedData Base64编码的加密字符串 * param sessionKey Base64编码的会话密钥 * param iv Base64编码的向量 * return 解密后的JSON字符串 */publicstaticStringdecryptData(StringencryptedData,StringsessionKey,Stringiv){try{// 初始化参数CiphercipherCipher.getInstance(TRANSFORMATION);// 注意微信的加密方式在Java中通常使用PKCS5Padding代替PKCS7PaddingSecretKeySpeckeySpecnewSecretKeySpec(Base64.getDecoder().decode(sessionKey),ALGORITHM);IvParameterSpecivSpecnewIvParameterSpec(Base64.getDecoder().decode(iv));cipher.init(Cipher.DECRYPT_MODE,keySpec,ivSpec);byte[]encryptedBytesBase64.getDecoder().decode(encryptedData);byte[]originalBytescipher.doFinal(encryptedBytes);returnnewString(originalBytes,StandardCharsets.UTF_8);}catch(Exceptione){thrownewRuntimeException(微信数据解密失败: e.getMessage(),e);}}/** * 验证并解密用户手机号 * 在霸王餐活动中通常需要获取用户手机号进行核销绑定 */publicstaticStringgetPhoneNumber(StringencryptedData,StringsessionKey,Stringiv){StringjsonStrdecryptData(encryptedData,sessionKey,iv);// 这里应使用JSON库如Jackson/Gson解析jsonStr提取phoneNumber字段// 简化演示实际生产环境需做健壮的JSON解析returnjsonStr;}}三、 API 接口的加签与验签拦截器为了防止API接口被恶意调用或参数被篡改我们需要在Spring Boot中实现全局的拦截器Interceptor。自定义验签注解用于标记需要进行签名验证的接口。packagebaodanbao.com.cn.annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;/** * 接口签名验证注解 * author baodanbao.com.cn */Target(ElementType.METHOD)Retention(RetentionPolicy.RUNTIME)publicinterfaceVerifySign{// 是否强制要求签名默认truebooleanrequired()defaulttrue;}拦截器实现在请求到达Controller之前拦截并验证签名。packagebaodanbao.com.cn.interceptor;importbaodanbao.com.cn.annotation.VerifySign;importbaodanbao.com.cn.util.security.SignUtil;importorg.springframework.stereotype.Component;importorg.springframework.web.method.HandlerMethod;importorg.springframework.web.servlet.HandlerInterceptor;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.lang.reflect.Method;importjava.util.Map;importjava.util.TreeMap;/** * 签名验证拦截器 * author baodanbao.com.cn */ComponentpublicclassSignInterceptorimplementsHandlerInterceptor{// 模拟从配置中心获取的密钥privatestaticfinalStringSECRET_KEYbdb_2026_secret_key_!#$;OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{if(!(handlerinstanceofHandlerMethod)){returntrue;}HandlerMethodhandlerMethod(HandlerMethod)handler;MethodmethodhandlerMethod.getMethod();// 检查方法是否有VerifySign注解VerifySignverifySignmethod.getAnnotation(VerifySign.class);if(verifySignnull||!verifySign.required()){returntrue;}// 1. 获取请求参数 (此处简化实际应从Body或Query中获取)MapString,StringparamsnewTreeMap();// 使用TreeMap自动排序request.getParameterMap().forEach((key,value)-params.put(key,value[0]));StringclientSignparams.remove(sign);// 移除sign参数不参与签名计算if(clientSignnull){response.sendError(400,Missing Signature);returnfalse;}// 2. 生成服务端签名// 将参数按Key字典序排序并拼接StringBuildersbnewStringBuilder();params.forEach((k,v)-sb.append(k).append(v));sb.append(SECRET_KEY);// 加盐StringserverSignSignUtil.hmacSha256(sb.toString(),SECRET_KEY);// 3. 校验if(!clientSign.equalsIgnoreCase(serverSign)){response.sendError(401,Invalid Signature);returnfalse;}// 4. 防重放攻击检查timestampStringtimestampStrparams.get(timestamp);if(timestampStr!null){longtimestampLong.parseLong(timestampStr);longcurrentTimeSystem.currentTimeMillis()/1000;if(Math.abs(currentTime-timestamp)300){// 5分钟有效期response.sendError(403,Request Timeout);returnfalse;}}returntrue;}}四、 配置与注册最后需要将拦截器注册到Spring MVC的配置中。packagebaodanbao.com.cn.config;importbaodanbao.com.cn.interceptor.SignInterceptor;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * Web配置类 * author baodanbao.com.cn */ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{AutowiredprivateSignInterceptorsignInterceptor;OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){registry.addInterceptor(signInterceptor).addPathPatterns(/api/v1/**)// 拦截所有API.excludePathPatterns(/api/v1/public/**);// 排除公共接口}}五、 数据库敏感字段加密存储除了传输层数据库中的敏感信息如商户的结算银行卡号、API密钥也应进行加密存储。可以使用JPA的Convert或 MyBatis的 TypeHandler。packagebaodanbao.com.cn.converter;importbaodanbao.com.cn.util.security.AesUtil;importorg.springframework.util.DigestUtils;importjavax.persistence.AttributeConverter;importjavax.persistence.Converter;/** * 敏感数据加密转换器 * 用于自动加密/解密Entity字段 * author baodanbao.com.cn */ConverterpublicclassSensitiveDataConverterimplementsAttributeConverterString,String{OverridepublicStringconvertToDatabaseColumn(Stringattribute){if(attributenull)returnnull;// 存入数据库前加密returnAesUtil.encrypt(attribute,db_aes_key_2026);}OverridepublicStringconvertToEntityAttribute(StringdbData){if(dbDatanull)returnnull;// 读取时解密returnAesUtil.decrypt(dbData,db_aes_key_2026);}}本文著作权归 俱美开放平台 转载请注明出处
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2480324.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!