超详细接入微信支付、支付宝支付 - 微信公众号获取OpenID

1、介绍
1.1、OpenID是什么

openId是用户在当前微信公众号下的唯一标识,就是说通过这个openId,就能区分在这个公众号下具体是哪个用户。

1.2 、拓展:UnionID的作用

如果开发者拥有多个移动应用、网站应用和公众账号,可通过获取用户基本信息中的unionid来区分用户的唯一性,因为同一用户,对同一个微信开放平台下的不同应用(移动应用、网站应用和公众账号),unionid是相同的。

2、网页授权获取OpenID

微信网页授权获取OpenID和用户信息官方文档

2.1、网页授权流程

网页授权流程分为四步:

  1. 用户同意授权,获取code
  2. 通过code换取网页授权access_token(得到openid)
  3. 刷新access_token(如果需要)
  4. 拉取用户信息(需scope为 snsapi_userinfo)

如果只需要OpenID,只要1、2步就可以了。本文章只提供获取openId的示例代码,获取用户信息,可自行参考微信官方文档

2.2、配置网页授权域名

微信处于安全考虑,获取微信OpenID或用户信息的网页地址,必须在微信公众号中配置(网页授权域名)。

公众号配置网页授权域名流程:

  • 开发者需要先到公众平台官网中的 设置与开发 => 公众号设置 => 功能设置 => 网页授权域名 的配置选项中,修改网页授权域名;

  • 填写的是域名(是一个字符串),而不是URL,因此请勿加 http:// 等协议头;

  • 授权回调域名配置规范为全域名,比如需要网页授权的域名为:www.qq.com,配置以后此域名下面的页面http://www.qq.com/music.htmlhttp://www.qq.com/login.html 都可以进行OAuth2.0鉴权。但http://pay.qq.comhttp://music.qq.comhttp://qq.com 无法进行OAuth2.0鉴权。

    如何配置下载文件,可参考此链接 微信公众号网页授权域名设置

3、Java代码
3.1、maven引用

需要用到hutoolHttpUtil工具类,也可自己实现httpget方法。

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.27</version>
</dependency>
3.2、Controller类
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 微信公众号获取 OpenID Controller
 */
@Slf4j
@Controller
@Scope("prototype")
@RequestMapping("/wechat/")
public class WechatPublicGetOpenIDController {

    @Resource
    private WechatPublicGetOpenIDService wechatPublicGetOpenIDService;

    //获取code
    @RequestMapping(value = "/getCode", method = RequestMethod.GET)
    public void getCode(HttpServletRequest request , HttpServletResponse response) throws IOException {
        //获取code重定向地址
        String pageUrl = wechatPublicGetOpenIDService.getCode(request);
        response.sendRedirect(pageUrl);
    }


    /**
     获取openId
     @param code 微信code
     @param state 获取微信code时,传的附加参数
     **/
    @RequestMapping(value = "/getOpenId",method = RequestMethod.GET)
    public void getOpenId(@RequestParam("code") String code, @RequestParam("state") String state , HttpServletResponse response) throws IOException {
        String pageUrl = wechatPublicGetOpenIDService.wechatCode(code , state);
        //重定向回前端
        response.sendRedirect(pageUrl);
    }
}
3.3、Service类
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kz.tppd.common.enums.CommonErrorEnum;
import com.kz.tppd.common.exceptions.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Enumeration;

/**
 * 微信公众号获取 OpenID service
 */
@Slf4j
@Service
public class WechatPublicGetOpenIDService {

    /**
     * 获取code重定向地址
     * @return 地址
     */
    public String getCode(HttpServletRequest request) throws UnsupportedEncodingException {
        //校验是不是微信浏览器打开
        String payMethod = getPayMethod(request);
        if(payMethod == null){
            throw new RuntimeException("请用微信");
        }

        String wechatPublicAppid = "微信公众号appId";

        //state 用户信息(建议加密),回传时用到
        String state = "";

        //getOpenIdUrl 自己的获取openId公网地址(获取code成功后,会重定向回该地址))
        String getOpeniIdUrl = "https://自己的网页授权域名/wechat/getOpenId";
        return oauth2buildAuthorizationUrl(wechatPublicAppid , getOpeniIdUrl, state);
    }

    /**
     * 构建认证url
     * @param appId appId
     * @param redirectURI 重定向地址
     * @param state 用户信息,回传时用到
     * @return 地址
     */
    private String oauth2buildAuthorizationUrl(String appId, String redirectURI, String state) throws UnsupportedEncodingException {
        return String.format("https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=%s#wechat_redirect",
                appId, URLEncoder.encode(redirectURI , "UTF-8"),  StringUtils.trimToEmpty(state));
    }

    /**
     * 获取支付方式
     * @param request http request
     * @return 支付方式
     */
    private String getPayMethod(HttpServletRequest request){
        String userAgent = null;
        Enumeration<String> em = request.getHeaderNames();
        while (em.hasMoreElements()) {
            String name = em.nextElement();
            String value = request.getHeader(name);
            if("user-agent".equals(name)){
                userAgent = value;
                break;
            }
        }
        if(StringUtils.isBlank(userAgent)){
            return null;
        }

        if(userAgent.contains("MicroMessenger")){
            return "WECHAT";
        } else if(userAgent.contains("AlipayClient")){
            return "ALIPAY";
        }
        log.info("userAgent:{}" , userAgent);
        return null;
    }

    /**
     * 静默授权-微信code
     * @param code 微信code
     * @param state url中传的加密参数
     * @return 地址
     */
    public String wechatCode(String code, String state){
        //获取微信openId
        String openId = getWechatOpenId(code);

        //state为,获取code时,自己设置的附加参数
        return "前端获取OpenID后的成功页面";
    }

    /**
     * 获取微信openId
     * @param code 微信code
     * @return 微信openId
     */
    private String getWechatOpenId(String code){
        String wechatPublicAppid = "微信公众号appId";
        String wechatPublicAppSecret = "微信公众号开发密钥";

        String url = String.format("https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code"
                , wechatPublicAppid , wechatPublicAppSecret , code);
        log.info("微信获取openId 请求地址:{}" , url);
        String httpReponse = HttpUtil.get(url);
        log.info("微信获取openId 返回参数:{}" , httpReponse);
        if(StringUtils.isBlank(httpReponse)){
            throw new RuntimeException("微信获取openId返回参数为空");
        }

        JSONObject jsonObject = JSON.parseObject(httpReponse);
        //返回失败
        if(jsonObject.containsKey("errcode")){
            throw new BaseException(CommonErrorEnum.BUSINESS_ERROR.getCode() , jsonObject.getLong("errcode") + ":" + jsonObject.getString("errmsg"));
        }

        String openId = jsonObject.getString("openid");
        if(StringUtils.isBlank(openId)){
            throw new BaseException(CommonErrorEnum.BUSINESS_ERROR.getCode() , "微信返回的openId为空");
        }
        return openId;
    }
}
3.4、测试

在微信公众号中,重定向访问如下地址:

https://自己的网页授权域名/wechat/getCode

必须访问网页授权域名,不然没有权限。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值