微信 获取signature签名

本文是使用java语言调用微信提供的接口,获取签名的详细过程,大致步骤如下:

  1. 在官网生成appId 与 appSecret,然后通过appId 与 appSecret调用接口获取到Access token
  2. 通过Access token调用微信提供的接口获取到jsapi_ticket
  3. 最后使用jsapi_ticket、随机字符串、时间戳、url拼接字符串,在使用sha1进行加密得到签名
  4. 将appid、时间戳、随机字符串、签名返回给前端

具体过程如下:
首先是请求参数:

package com.ncb.mbank.api.service.openact.dto.req;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import java.io.Serializable;

/**
 * @Description: 微信获取签名的请求参数
 * @Author 胡尚
 * @Date: 2022/1/4 11:40
 * @Version 1.0
 */
@Data
public class GetWeChatSignatureReq implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "appid")
    @NotBlank(message = "appid不能為空")
    private String appId;

    @ApiModelProperty(value = "appSecret")
    @NotBlank(message = "appSecret不能為空")
    private String appSecret;

    @ApiModelProperty(value = "url",required = true)
    @NotBlank(message = "url不能為空")
    private String url;

}

接下来是业务层

package com.ncb.mbank.api.service.openact.bizsvc.impl;

import com.alibaba.fastjson.JSON;
import com.ncb.mbank.api.framework.core.constants.ErrorCodeConstants;
import com.ncb.mbank.api.framework.core.exception.ApplicationException;
import com.ncb.mbank.api.framework.web.constants.HsAccountConst;
import com.ncb.mbank.api.framework.web.utils.MbankHsUtils;
import com.ncb.mbank.api.framework.web.utils.RsaUtil;
import com.ncb.mbank.api.restclient.gateway.feignclient.WeChatFeignClient;
import com.ncb.mbank.api.service.openact.bizsvc.MWeChatTencentBizSvc;
import com.ncb.mbank.api.service.openact.dto.req.GetWeChatSignatureReq;
import com.ncb.mbank.api.service.openact.dto.resp.GetWeChatSignatureResp;
import com.ncb.mbank.api.service.openact.dto.resp.RsaEncryptResp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Description:
 * @Author 胡尚
 * @Date: 2022/1/4 11:54
 * @Version 1.0
 */
@Service
@Slf4j
public class MWeChatTencentBizSvcImpl implements MWeChatTencentBizSvc {

    /**
     * 调用微信公众号的接口 获取Access token 必输的一个请求参数 该值是固定的
     */
    private final static String GRANT_TYPE = "client_credential";

    /**
     * 调用微信公众号的接口 获取jsapi_ticket 必输的一个请求参数 该值是固定的
     */
    private final static String GET_JSAPI_TICKET_TYPE = "jsapi";

    @Autowired
    private WeChatFeignClient weChatFeignClient;

    @Override
    public GetWeChatSignatureResp getWeChatSignature(GetWeChatSignatureReq req) throws ApplicationException {
        // 调用微信公众号的接口 获取Access token
        String accessToken = getAccessToken(req);
        if (StringUtils.isEmpty(accessToken)) {
            log.error("调用微信公众号的接口 未获取Access token ");
            throw new ApplicationException(ErrorCodeConstants.CLI_GET_ACCESS_TOKEN_ERROR);
        }

        // 调用微信公众号的接口 获取jsapi_ticket
        String jsapiTicket = getJsapiTicket(accessToken);
        if (StringUtils.isEmpty(accessToken)) {
            log.error("调用微信公众号的接口 未获取jsapi_ticket ");
            throw new ApplicationException(ErrorCodeConstants.CLI_GET_JSAPI_TICKET_ERROR);
        }

        // 签名加密算法
        GetWeChatSignatureResp resp = getSignature(jsapiTicket, req.getUrl());
        resp.setAppId(req.getAppId());
        return resp;
    }

    @Override
    public String getAccessToken(GetWeChatSignatureReq req) throws ApplicationException {
        Map<String, Object> reqMap = new HashMap<>();
        reqMap.put("grant_type", GRANT_TYPE);
        reqMap.put("appid", req.getAppId());
        reqMap.put("secret", req.getAppSecret());
        log.info("调用微信的接口 获取AccessToken,请求数据为:\n{}", JSON.toJSONString(reqMap));
        String accessTokenResp = weChatFeignClient.getAccessToken(reqMap);
        log.info("调用微信的接口 获取AccessToken,响应数据为:\n{}", accessTokenResp);
        return JSON.parseObject(accessTokenResp).getString("access_token");
    }

    @Override
    public String getJsapiTicket(String accessToken) throws ApplicationException {
        Map<String, Object> reqMap = new HashMap<>();
        reqMap.put("type", GET_JSAPI_TICKET_TYPE);
        reqMap.put("access_token", accessToken);
        log.info("调用微信的接口 获取jsapi_ticket,请求数据为:\n{}", JSON.toJSONString(reqMap));
        String jsapiTicketResp = weChatFeignClient.getJsapiTicket(reqMap);
        log.info("调用微信的接口 获取jsapi_ticket,响应数据为:\n{}", jsapiTicketResp);
        return JSON.parseObject(jsapiTicketResp).getString("ticket");
    }

    @Override
    public GetWeChatSignatureResp getSignature(String jsapiTicket, String url) throws ApplicationException {
        GetWeChatSignatureResp resp = new GetWeChatSignatureResp();
        // 生成随机字符串
        String nonceStr = MbankHsUtils.createNonceStr();
        // 时间戳
        long timestamp = System.currentTimeMillis();
        // 通过jsapi_ticket、随机字符串、时间戳
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("jsapi_ticket=").append(jsapiTicket).append("&")
                .append("noncestr=").append(nonceStr).append("&")
                .append("timestamp=").append(timestamp).append("&")
                .append("url=").append(url.indexOf("#") >= 0 ? url.substring(0, url.indexOf("#")) : url);
        String signatureStr = stringBuilder.toString();
        log.info("微信签名 she1加密前的数据:{}", signatureStr);
        String signature = DigestUtils.sha1Hex(signatureStr);
        log.info("微信签名,she1加密后的数据:{}", signature);

        // 返回数据
        resp.setNonceStr(nonceStr);
        resp.setTimestamp(String.valueOf(timestamp));
        resp.setSignature(signature);
        return resp;
    }
}

这里使用FeignClient方式调用微信的接口

package com.ncb.mbank.api.restclient.gateway.feignclient;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Map;

/**
 * @Description: 微信相关接口
 * @Author 胡尚
 * @Date: 2022/1/4 11:59
 * @Version 1.0
 */
@FeignClient(name = "weChatFeignClient", url = "https://api.weixin.qq.com", path = "/cgi-bin")
public interface WeChatFeignClient {

    @GetMapping("/token")
    String getAccessToken(@RequestParam Map<String, Object> map);

    @GetMapping("/ticket/getticket")
    String getJsapiTicket(@RequestParam Map<String, Object> map);
}

需要注意的几点是,通过jsapi_ticket、随机字符串、时间戳、url拼接时,=左边需要使用小写,需要按照字典顺序升序摆放。


版权声明:本文为qq_44027353原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。