分为两步:
1. 获取code
2. 利用code获取openid 获取code时要提供redirect_uri,请求获取code的URL后会跳转到redirect_uri,在redirect_uri页面利用code获取openid
一、准备工作:
1. 申请公众号
申请公众号开发者账号:前往 微信公众平台 申请公众号开发者账号,并完成账号认证。
配置公众号开发设置:登录微信公众平台,在“开发-基本配置”中配置好公众号的相关信息,包括服务器配置、公众号名称、AppID、AppSecret等。
2. 申请小程序
申请小程序:前往 微信公众平台 | 小程序 申请小程序,具体可以按照页面引导操作
如果你已经认证了公众号,可以复用公众号的资质快速注册小程序,如下图所示:
二、实现:
工具类
@Slf4j
@Component
public class WeChatUtils {
public static final String appid = WxPublicConfig.appId;
public static final String secret = WxPublicConfig.secret;
// 获取code
public final static String CODE_URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
//获取网页access_token的接口地址
public final static String WEB_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=APPSECRET&code=CODE&grant_type=authorization_code";
//获取用户信息地址
public final static String USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN";
// 获取access_token的接口地址(GET) 限2000(次/天)
public final static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
// 发送模板消息
public static final String SEND_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
/**
* 生成获取code的url
*
* @param backUrl
* @return
*/
public String getCodeUrl(String backUrl, String state) {
String requestUrl = null;
state = state == null ? "" : state;
try {
requestUrl = CODE_URL.replace("APPID", appid).replace("REDIRECT_URI", URLEncoder.encode(backUrl, "UTF-8")).replace("STATE", state);
} catch (Exception e) {
e.printStackTrace();
}
return requestUrl;
}
/**
* 获取微信网页access_token 和 openid
*
* @param code
* @return
*/
public JSONObject getWebAccessTokenAndOpenid(String code) {
String requestUrl = WEB_ACCESS_TOKEN_URL.replace("APPID", appid).replace("APPSECRET", secret).replace("CODE", code);
return HttpUtils.httpPost(requestUrl, new JSONObject());
}
/**
* 网页授权作用域为snsapi_userinfo,则此时开发者可以通过access_token和openid拉取用户信息了
* https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html
*
* @param webAccessToken
* @param openid
* @return
*/
public JSONObject getUserInfo(String webAccessToken, String openid) {
String requestUrl = USERINFO_URL.replace("ACCESS_TOKEN", webAccessToken).replace("OPENID", openid);
return HttpUtils.httpPost(requestUrl, new JSONObject());
}
public String getToken() {
return getToken(null);
}
/**
* 获取access_token 先从Redis获取,如果没有再调微信获取并存Redis
*
* @param forceRefresh 如果为“1”直接从微信获取并存Redis
* @return
*/
public String getToken(String forceRefresh) {
String accessToken = null;
String requestUrl = ACCESS_TOKEN_URL.replace("APPID", appid).replace("APPSECRET", secret);
// 调用接口获取token
JSONObject jsonObject = HttpUtils.httpPost(requestUrl, new JSONObject());
// 如果请求成功//jsonObject.getString("errcode")
if (null != jsonObject) {
accessToken = jsonObject.getString("access_token");
}
log.debug("forceRefresh" + forceRefresh + "获取access_token:" + accessToken);
return accessToken;
}
}
链接解析:
获取code:https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
appid:公众号的AppID
公众号的唯一标识,可以在公众号后台获取到AppID
redirect_uri:用户同意授权后的回调URL
授权后重定向的回调链接地址,需使用 urlEncode 对链接进行处理
response_type:返回类型,固定填写code
scope:应用授权作用域
snsapi_userinfo:固定值 ,表示获取用户信息的权限范围
snsapi_userinfo:弹出授权页面,可通过openid拿到昵称、性别、所在地。并且, 即使在未关注的情况下,只要用户授权,也能获取其信息
state:自定义参数
重定向后会带上state参数,开发者可以填写a-zA-Z0-9的参数值,最多128字节
#wechat_redirect:固定传递
必须带此参数
控制层
@RestController
@RequestMapping("/wx/public")
public class WxPublicController {
@Resource
WxPublicService wxPublicService;
/**
* 获取openId
*
* @param code
* @return
*/
@GetMapping("/getOpenId")
@ResponseBody
public ResultBean getOpenId(String code) {
if (code == null || code.equals("")) {
return ResultBean.error("未获取到code");
}
return wxPublicService.getOpenId(code);
}
}
Service层
public interface WxPublicService {
/**
* 获取openId
* @param code
* @return
*/
public ResultBean getOpenId(String code);
}
ServiceImpl层
@Service
public class WxPublicServiceImpl implements WxPublicService {
@Resource
WeChatUtils weChatUtils;
@Override
public ResultBean getOpenId(String code) {
if (code == null) {
return ResultBean.error("未获取到code");
}
JSONObject jsonObject = weChatUtils.getWebAccessTokenAndOpenid(code);
if (jsonObject != null && jsonObject.size() > 0) {
if (jsonObject.getString("errcode") == null) {
String openId = jsonObject.getString("openid");
String accessToken = jsonObject.getString("access_token");
if (openId == null) {
ResultBean.error("未获取到openId");
}
return ResultBean.success(openId);
} else {
return ResultBean.error(jsonObject.getString("errmsg"));
}
} else {
return ResultBean.error("未获取到信息");
}
}
}
三、遇到的问题
1. 如何调试
其实调试问题,微信官方也已经考虑到了这个问题,在微信公众号的后台,他们提供了一下开发者工具,可以让我们在开发阶段进行便捷的测试,如下图所示
在这里,我们主要使用的是 “公众平台测试账号” 这个工具,下面我们看一下这个工具是如何使用的。
-
第一步
点击 “公众平台测试账号” ,用自己微信扫码进行登录,然后就进入到了主页,在主页中我们可以看到给我们生成了测试的 appID 和 appsecret,这两个重要的参数以供我们测试授权使用
-
第二步
在当前页面中我们找到 “测试号二维码” 一栏,使用需要调试的微信扫码关注测试公众号,如下图所示:
-
第三步
在当前页面继续向下滚动页面,找到 “网页授权获取用户基本信息”,点击修改,添加授权回调域名,如下图所示
完成上面的两步后,我们就可以进行愉快的测试了,可以使用手机微信,或者是微信开发者工具进行调试!
注意:调试阶段,可以使用域名或IP都可以,在正式上线环境下,必须使用备案的域名才可以!
2. redirect_uri
redirect_uri 必须提前在微信公众号后台中维护好授权回调域名,否则会报 “10003:redirect_uri域名与后台配置不一致”
redirect_uri 必须使用 urlEncode 进行编码处理
使用 Vue 框架开发的,建议使用 history 路由模式,可以避免微信回调链接的各种参数拼接问题
使用 Vue 开发时,如果你非要使用 hash 路由模式,也不是不可以解决,只能在路由拦截器中处理一下 # 拼接的问题,重新整理成正确的路由链接就可以了