在开发中,如果web产品需要使用到微信的功能,比如微信授权登录、微信支付、微信投票等,我是开发的东东是一个web项目,然而如果需要接入微信的话,就需要使用道微信的微信网页开发相关的功能。
其中我们需要的东西就是拿到微信服务器的回调,比如用户扫码登录我们的web项目时,用户正确授权之后,微信服务器能回调到我们期望的url并且返回相应的参数信息。
网页授权流程分为四步:
具体的接口和参数说明参考官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
其中需要注意的时: 第一步获取code时,scope参数的设置,当scope参数值为snsapi_base时 (不弹出授权页面,直接跳转,只能获取用户openid),当scope参数值为snsapi_userinfo时 (弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息 )
这里我直接贴开发及代码步骤:
0. 在微信公众号后台配置域名
需要注意的是只有微信认证的服务号才有微信网页授权的权限。
在开发的时候我们可以使用申请的测试号进行调试开发,测试号拥有大部分服务号有的接口权限。
然后需要在这两个地方设置JS接口的安全域名(开发阶段可以使用内网穿透域名):
第一处:
第二处(向下拉):
分别设置好就可以使用安全域名开始开发了
在后端写代码时,一般会使用官方的SDK:weixin-java-mp(如果向官网那样每一个步骤发送请求拼接参数真的太不友好了)
com.github.binarywang weixin-java-mp 2.7.0
wechat: mpAppId: wx90a9158b6acc5584 mpAppSecret: ec23a5d78f12afa569c64794570d753c // 后端项目回调地址 projecturl: http://uhi4iv.natappfree.cc/
WechatAccountConfig.java
package cn.kt.mywxdemo.wechatmp.config; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Map; /** * Created by tao. * Date: 2023/3/21 15:02 * 描述: */ @Data @Component //从配置文件里获取 @ConfigurationProperties(prefix = "wechat") public class WechatAccountConfig { /** * 公众平台id */ private String mpAppId; /** * 公众平台密钥 */ private String mpAppSecret; /** * 微信模版id */ private MaptemplateId; }
WechatMpConfig.java
package cn.kt.mywxdemo.wechatmp.config; import me.chanjar.weixin.mp.api.WxMpConfigStorage; import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; /** * Created by tao. * Date: 2023/3/21 15:00 * 描述: */ @Component public class WechatMpConfig { @Autowired private WechatAccountConfig accountConfig; /** * @author :tao * @date :Created in 2021/3/12 10:15 * @param: : * @return: WxMpService 对象 * 配置wxMpConfigStorage,返回 WxMpService 对象 */ @Bean public WxMpService wxMpService() { WxMpService wxMpService = new WxMpServiceImpl(); wxMpService.setWxMpConfigStorage(wxMpConfigStorage()); return wxMpService; } /** * @author :tao * @date :Created in 2021/3/12 10:20 * @param: : * @return: WxMpConfigStorage 对象 * 配置AppId、和AppSecret,获取WxMpConfigStorage 对象 */ @Bean public WxMpConfigStorage wxMpConfigStorage() { WxMpInMemoryConfigStorage wxMpConfigStorage = new WxMpInMemoryConfigStorage(); wxMpConfigStorage.setAppId(accountConfig.getMpAppId()); wxMpConfigStorage.setSecret(accountConfig.getMpAppSecret()); return wxMpConfigStorage; } }
WxJsController.java
package cn.kt.mywxdemo.wechatmp.controller; import lombok.extern.slf4j.Slf4j; import me.chanjar.weixin.common.api.WxConsts; import me.chanjar.weixin.common.exception.WxErrorException; import me.chanjar.weixin.mp.api.WxMpService; import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; import me.chanjar.weixin.mp.bean.result.WxMpUser; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; /** * Created by tao. * Date: 2023/3/21 15:04 * 描述: */ @Controller @RequestMapping("/wechat") @Slf4j public class WxJsController { @Autowired private WxMpService wxMpService; @Value("${wechat.projecturl}") private String projectUrl; @GetMapping("/auth") @ResponseBody public String auth(@RequestParam(value = "echostr", defaultValue = "没有获取到") String echostr) { return echostr; } /** * @author :tao * @param: : * @return: 重定向到获取用户信息的类 * 微信授权登录 */ @GetMapping("/authorize") public String authorize(@RequestParam(value = "returnUrl", defaultValue = "https://qkongtao.cn/") String returnUrl) throws UnsupportedEncodingException { log.info("【微信网页授权】进来了,参数={}", returnUrl); System.out.println("进来了:" + returnUrl); //1. 配置 //2. 调用方法 String url = projectUrl + "wechat/userInfo"; /* * 相当于这种形式 * URLEncoder.decode(returnUrl,"UTF-8" * https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect */ String redirectUrl = wxMpService.oauth2buildAuthorizationUrl(url, WxConsts.OAUTH2_SCOPE_USER_INFO, URLEncoder.encode(returnUrl, "utf-8")); log.info("【微信网页授权】获取code,result={}", redirectUrl); return "redirect:" + redirectUrl; } /** * @author :tao * @param: : * @return: 重定向 * 获取用户信息类,最后重定向到指定url */ @GetMapping("/userInfo") public String userInfo(@RequestParam("code") String code, @RequestParam("state") String returnUrl) throws WxErrorException { /*当用户同意授权后,会回调所设置的url并把authorization code传过来, 然后用这个code获得access token,其中也包含用户的openid等信息*/ WxMpOAuth2AccessToken wxMpOAuth2AccessToken = new WxMpOAuth2AccessToken(); try { //获取access token wxMpOAuth2AccessToken = wxMpService.oauth2getAccessToken(code); log.info("【AccessToken:】{}", wxMpOAuth2AccessToken.getAccessToken()); } catch (WxErrorException e) { log.error("【微信网页授权】{}", e); } // 拿到openid String openId = wxMpOAuth2AccessToken.getOpenId(); log.info("【openid:】{}", openId); log.info("【我是前端要回调的地址:】{}", returnUrl + "&openid=" + openId); // 顺便获取一下用户信息 WxMpUser wxMpUser = wxMpService.oauth2getUserInfo(wxMpOAuth2AccessToken, "zh_CN"); log.info("【用户信息:】{}", wxMpUser.toString()); //注意拼接参数,第一个参数需要加问号,之后参数使用&拼接的问题 //return "redirect:" + returnUrl + "/#/?openid=" + openId; return "redirect:" + returnUrl + "&openid=" + openId; } }
上述代码已经处理好了微信授权的流程,我们调用只需要使用/authorize接口,并且传入回调url(授权之后需要重定向的路径)即可进行授权
示例如下
uhi4iv.natappfree.cc为后台绑定域名
http://uhi4iv.natappfree.cc/wechat/authorize?returnUrl=https://qkongtao.cn?1=1
使用微信打开结果:
由于我已经刚刚授权过了,就进行了静默授权。否则将弹出授权选项需要用户确认。
需要提前说明:
参考官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#3
如果网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了。
请求方法:
http:GET(请使用https协议):
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
参数说明:
请求结果:
昵称乱码需要使用utf8重新编码:String result = new String(nickname, “utf-8”);
在上面的controller中也顺便把用户信息也进行获取了一下:
后台输出结果如下:
官方文档:https://developers.weixin.qq.com/doc/offiaccount/User_Management/Get_users_basic_information_UnionID.html#UinonId
其实和上面差不多,也是通过openid和access_token换取用户信息
接口如下:
接口调用请求说明 http请求方式: GET https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
参数说明:
结果如下:
可以看出相比较微信网页授权,基础公众号关注可获取用户信息相对少了很多。
源码链接:https://gitee.com/qkongtao/my-wx-demo