当前位置: 首页 > news >正文

Java微信分享-签名算法实现

文章目录

  • 前言

前言

  1. 工具类 - WxJsapiSignature.java
importjava.security.MessageDigest;importjava.security.NoSuchAlgorithmException;importjava.util.UUID;publicclassWxJsapiSignature{/** * 生成微信 JS-SDK 签名 * @param jsapiTicket 微信 jsapi_ticket * @param url 当前页面 URL(不包含 # 后面的部分) * @return 签名信息对象 */publicstaticSignatureResultgenerateSignature(StringjsapiTicket,Stringurl){// 生成随机字符串StringnonceStr=createNonceStr();// 生成时间戳(秒)longtimestamp=System.currentTimeMillis()/1000;// 按字典序拼接字符串Stringstring1="jsapi_ticket="+jsapiTicket+"&noncestr="+nonceStr+"&timestamp="+timestamp+"&url="+url;// SHA1 加密Stringsignature=sha1(string1);// 返回结果SignatureResultresult=newSignatureResult();result.setNonceStr(nonceStr);result.setTimestamp(timestamp);result.setSignature(signature);returnresult;}/** * SHA1 加密 */privatestaticStringsha1(Stringstr){try{MessageDigestdigest=MessageDigest.getInstance("SHA-1");digest.update(str.getBytes());byte[]messageDigest=digest.digest();// 转换为十六进制字符串StringBuilderhexString=newStringBuilder();for(byteb:messageDigest){Stringhex=Integer.toHexString(0xFF&b);if(hex.length()==1){hexString.append('0');}hexString.append(hex);}returnhexString.toString();}catch(NoSuchAlgorithmExceptione){thrownewRuntimeException("SHA1 加密失败",e);}}/** * 生成随机字符串 */privatestaticStringcreateNonceStr(){returnUUID.randomUUID().toString().replace("-","").substring(0,16);}}
  1. 签名结果类 - SignatureResult.java
publicclassSignatureResult{privateStringnonceStr;privateLongtimestamp;privateStringsignature;// Getters and SetterspublicStringgetNonceStr(){returnnonceStr;}publicvoidsetNonceStr(StringnonceStr){this.nonceStr=nonceStr;}publicLonggetTimestamp(){returntimestamp;}publicvoidsetTimestamp(Longtimestamp){this.timestamp=timestamp;}publicStringgetSignature(){returnsignature;}publicvoidsetSignature(Stringsignature){this.signature=signature;}}
  1. Controller 示例
importorg.springframework.web.bind.annotation.*;@RestController@RequestMapping("/wechat")publicclassWechatController{@AutowiredprivateWechatServicewechatService;/** * 获取微信 JS-SDK 签名 */@PostMapping("/jsapi-signature")publicResultgetJsapiSignature(@RequestBodySignatureRequestrequest){try{Stringurl=request.getUrl();// 1. 获取 access_token(需要缓存,有效期 7200 秒)StringaccessToken=wechatService.getAccessToken();// 2. 获取 jsapi_ticket(需要缓存,有效期 7200 秒)StringjsapiTicket=wechatService.getJsapiTicket(accessToken);// 3. 生成签名SignatureResultsignature=WxJsapiSignature.generateSignature(jsapiTicket,url);// 4. 返回结果Map<String,Object>data=newHashMap<>();data.put("appId",wechatService.getAppId());data.put("timestamp",signature.getTimestamp());data.put("nonceStr",signature.getNonceStr());data.put("signature",signature.getSignature());returnResult.success(data);}catch(Exceptione){returnResult.error("获取签名失败: "+e.getMessage());}}}
  1. Service 示例(获取 access_token 和 jsapi_ticket)
importorg.springframework.stereotype.Service;importorg.springframework.web.client.RestTemplate;importcom.alibaba.fastjson.JSONObject;@ServicepublicclassWechatService{@Value("${wechat.appId}")privateStringappId;@Value("${wechat.appSecret}")privateStringappSecret;@AutowiredprivateRestTemplaterestTemplate;// 缓存 access_token(实际项目中应该用 Redis 缓存)privateStringcachedAccessToken;privatelongaccessTokenExpireTime;// 缓存 jsapi_ticketprivateStringcachedJsapiTicket;privatelongjsapiTicketExpireTime;/** * 获取 access_token */publicStringgetAccessToken(){// 检查缓存if(cachedAccessToken!=null&&System.currentTimeMillis()<accessTokenExpireTime){returncachedAccessToken;}// 请求微信接口Stringurl="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret;Stringresponse=restTemplate.getForObject(url,String.class);JSONObjectjson=JSONObject.parseObject(response);if(json.containsKey("access_token")){cachedAccessToken=json.getString("access_token");// 提前 5 分钟过期accessTokenExpireTime=System.currentTimeMillis()+(json.getInteger("expires_in")-300)*1000;returncachedAccessToken;}else{thrownewRuntimeException("获取 access_token 失败: "+response);}}/** * 获取 jsapi_ticket */publicStringgetJsapiTicket(StringaccessToken){// 检查缓存if(cachedJsapiTicket!=null&&System.currentTimeMillis()<jsapiTicketExpireTime){returncachedJsapiTicket;}// 请求微信接口Stringurl="https://api.weixin.qq.com/cgi-bin/ticket/getjsapi_ticket?access_token="+accessToken;Stringresponse=restTemplate.getForObject(url,String.class);JSONObjectjson=JSONObject.parseObject(response);if(json.getInteger("errcode")==0){cachedJsapiTicket=json.getString("ticket");// 提前 5 分钟过期jsapiTicketExpireTime=System.currentTimeMillis()+(json.getInteger("expires_in")-300)*1000;returncachedJsapiTicket;}else{thrownewRuntimeException("获取 jsapi_ticket 失败: "+response);}}publicStringgetAppId(){returnappId;}}
  1. 请求对象
publicclassSignatureRequest{privateStringurl;publicStringgetUrl(){returnurl;}publicvoidsetUrl(Stringurl){this.url=url;}}
  1. application.yml 配置
wechat: appId: wxf123456789 appSecret: your_app_secret_here

关键点:
SHA1 加密必须转换为小写十六进制字符串
参数拼接顺序必须是字典序:jsapi_ticket、noncestr、timestamp、url
URL 不能 encode,保持原样
access_token 和 jsapi_ticket 必须缓存,避免频繁请求导致限流
时间戳单位是秒,不是毫秒

http://www.cnnetsun.cn/news/90140.html

相关文章:

  • 性能测试入门:使用 Playwright 测量关键 Web 性能指标
  • 从入门到精通:R语言极值分布拟合在气象数据中的4个关键步骤
  • 仅1%人掌握的建模技术:R语言金融相关性矩阵稀疏化处理实战
  • 超越传统PLM理念,定义行业新标准:全星研发项目管理APQP软件系统
  • 【安全专家亲授】私有化Dify的SSL配置秘诀:保障数据传输不被窃取
  • Vue3+JS 高级前端面试题
  • 海康威视智能工厂,是如何走向“领航”的?
  • 《深入昇腾底层:Ascend C 编程模型与高性能算子开发实战》
  • 实战 Ascend C:从零实现高性能自定义算子
  • 掌握这3种R包,轻松完成空间转录组细胞轨迹建模!
  • 【Dify Tesseract字体适配终极指南】:破解OCR识别失败的9大字体陷阱
  • Docker + 智能Agent日志管理新思路(仅限高级工程师掌握的3种架构模式)
  • 揭秘空间转录组细胞类型注释:如何用R语言精准识别每一种细胞
  • [吾爱大神原创工具] 电话号码过滤,号码排序-乱序,清除非手机号,消重,导出(依旧颜值高)
  • Dify平台Agent版本管理全解析:从入门到高可用架构设计
  • 为什么90%的生物信息分析师都在用R做RNA结构研究?真相令人震惊
  • 【稀缺资源】Dify + Tesseract 5.3多语言支持实现路径首次公开
  • 还在手动写Dify用例?Agent驱动自动化测试已成主流!
  • RSA 加密体制及其安全性分析
  • 【视频帧提取效率翻倍秘籍】:Dify帧率设置背后的黄金参数揭秘
  • 在C#上运行YOLOv11模型---CPU版
  • 关于uniapp vue2 canvas重绘元素节点时,提示cos of null相关异常警告,导致js线程崩溃,vue响应式丢失的问题
  • 【微服务稳定性提升利器】:基于Dify与Spring AI的异常熔断与恢复策略
  • concurrent hashmap原理,扩容,扩容时怎么保证线程安全?
  • 空间转录组降维必杀技:5步用R语言完成PCA、t-SNE与UMAP优化
  • 【R语言与量子计算加速新突破】:GPU如何将量子模拟效率提升10倍?
  • AWS专家Greg Coquillo提出的 6种LLM ORCHESTRATION PATTERNS解析
  • “.商标”不等同于商标权:企业做知识产权保护,别把“后缀名”当“确权证”
  • 面向削峰填谷的电动汽车多目标优化调度策略
  • 如何在30分钟内完成Dify与Spring AI的无缝部署?资深架构师亲授秘诀