目录
1 申请测试账号
1.1 登录测试平台
1.2 配置接口配置信息
编辑
1.3 配置JS接口安全域名
1.4 配置网页授权获取用户基本信息
2:接口代码
2.1 微信登录流程
2.2 依赖导入:
2.2.1 工具类:
2.3 创建微信用户实体类
2.4 接口功能
3 测试
链接: 微信公众平台测试
在这一步,需要拥有能接入公网的服务器,或者利用内网穿透将自己的接口暴漏给微信,让微信的回调能成功访问到我们的接口
在可以将我们的接口暴漏在公网的前提下,我们可以书写接口配置接口配置信息的URL:(注意:这里只是简单配置URL,未添加验证微信服务器流程,详细配置请参考:点击进入)
import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping("/weChat") public class WeChatController{ @GetMapping("/verifyToken") public String verifyToken(HttpServletRequest request) { return request.getParameter("echostr"); } }
比如我们的服务器地址是 119.3.248.100 ,上述服务部署在了该服务器8080端口上,那么按照上述代码的路径,URL就可配置为:http://119.3.248.100:8080/weChat/verifyToken (有域名使用域名即可)
在测试公众号中,可以使用 IP + 端口 的形式设置安全域名,这里的域名填写上述服务你所部署的服务器地址即可
这里的授权回调页面域名和JS接口安全域名保持一致即可
微信客户端发送登录请求 -> 访问微信授权接口 -> 微信回调,j将授权code发送到我们的服务器 -> 通过code,appid,appsecret获取微信针对该用户的accsess_token,openid等信息-> 通过accsess_token,openid获取用户信息
在下叙代码中使用到了hutool的工具类,swagger的工具类,通过maven的pom文件导入:(注:实体类使用了一些mybatis-plus的注解,如无用删除即可)
cn.hutool hutool-all5.8.10 io.springfox springfox-boot-starter3.0.0 io.springfox springfox-swagger-ui3.0.0 com.github.xiaoymin knife4j-spring-boot-starter3.0.3
import cn.hutool.http.HttpUtil; import com.alibaba.fastjson2.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Map; /** * 微信登录工具类 * * @author * @date 2023/11/1 15:28 */ public class WeiXinUtil { private static final String appId = "xxxx"; private static final String appsecret = "xxxx"; private static final String getCodeUrl = "https://open.weixin.qq.com/connect/oauth2/authorize"; private static final String redirectUrl = "http://xxxxx/v1/login/getAccessToken"; private static final String getAccessTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token"; private static final String refreshTokenUrl = "https://api.weixin.qq.com/sns/oauth2/refresh_token"; private static final String getUserInfo = "https://api.weixin.qq.com/sns/userinfo"; /** * 获取微信授权code * @param state 附加信息 * @return */ public static String getCode(String state) { try { StringBuffer url = new StringBuffer(); url.append("redirect:") .append(getCodeUrl) .append("?appid=") .append(appId) .append("&redirect_uri=") .append(URLEncoder.encode(redirectUrl, "UTF-8")) .append("&response_type=code&scope=snsapi_userinfo&state=") .append(state) .append("#wechat_redirect"); return url.toString(); } catch (UnsupportedEncodingException e) { throw new RuntimeException("URL格式化异常"); } } /** * 获取微信AccessToken * @param code 用户code * @return */ public static Map, ?> getAccessToken(String code) { StringBuffer url = new StringBuffer(); url.append(getAccessTokenUrl) .append("?appid=") .append(appId) .append("&secret=") .append(appsecret) .append("&code=") .append(code) .append("&grant_type=authorization_code"); String rs = HttpUtil.get(url.toString()); Map map = JSONObject.parseObject(rs, Map.class); if (null == map.get("errcode")) { return map; } else { throw new RuntimeException("获取access_token出错"); } } /** * 刷新AccessToken * @param refreshToken * @return */ public static Map refreshToken(String refreshToken) { StringBuffer url = new StringBuffer(); url.append(refreshTokenUrl) .append("?appid=") .append(appId) .append("&grant_type=refresh_token&refresh_token=") .append(refreshToken); String rs = HttpUtil.get(url.toString()); Map map = JSONObject.parseObject(rs, Map.class); if (null == map.get("errcode")) { return map; } else { throw new RuntimeException("刷新access_token出错"); } } /** * 获取用户信息 * @param accessToken * @param openid * @return */ public static String getUserInfo(String accessToken, String openid) { StringBuffer url = new StringBuffer(); url.append(getUserInfo) .append("?access_token=") .append(accessToken) .append("&openid=") .append(openid) .append("&lang=zh_CN"); String rs = HttpUtil.get(url.toString()); return rs; } }
import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * * 微信用户信息 * @author * @date 2023/11/1 16:20 */ @TableName(value = "wx_user") @Data public class WXUser implements Serializable { private static final long serialVersionUID = -40356785423868312L; @TableId(type = IdType.AUTO) private Long id; /** * 系统用户id */ private Long userId; /** * 用户的唯一标识 */ private String openid; /** * access_token */ private String accessToken; /** * refresh_token */ private String refreshToken; /** * 用户昵称 */ private String nickname; /** * 性别(0未知,1男性,2女性) */ private String sex; /** * 用户个人资料填写的省份 */ private String province; /** * 普通用户个人资料填写的城市 */ private String city; /** * 国家,如中国为CN */ private String country; /** * 用户头像 */ private String headimgurl; /** * 用户特权信息,json 数组 */ private String privilege; /** * */ private String unionid; private Date createTime; private Date updateTime; private Long createBy; private Long updateBy; }
import javax.servlet.http.HttpServletRequest; @Controller @RequestMapping("/weChat") public class WeChatController{ @ResponseBody @GetMapping("/verifyToken") @ApiOperation("微信Token验证") public String verifyToken(HttpServletRequest request) { return request.getParameter("echostr"); } @GetMapping("/getCode") @ApiOperation("获取微信code") public String weiXinLogin(@RequestParam(defaultValue = "123") String state) { return WeiXinUtil.getCode(state); } @ResponseBody @GetMapping("/getAccessToken") @ApiOperation("获取token") public String getAccessToken(@RequestParam String code) { Map result = WeiXinUtil.getAccessToken(code); String accessToken = result.get("access_token").toString(); String refreshToken = result.get("refresh_token").toString(); String openid = result.get("openid").toString(); WXUser wxUser = new WXUser(); wxUser.setAccessToken(accessToken); wxUser.setRefreshToken(refreshToken); wxUser.setCreateTime(new Date()); wxUser.setUserId(1L); wxUser.setOpenid(openid); wxUserService.save(wxUser); return "看样子成功了,没你事了退下吧
"; } @ResponseBody @GetMapping("/refreshToken") @ApiOperation("刷新token") public R refreshToken() { Long userId = 1L; WXUser wxUser = wxUserService.getOne(new LambdaUpdateWrapper().eq(WXUser::getUserId, userId)); Map result = WeiXinUtil.refreshToken(wxUser.getRefreshToken()); String accessToken = result.get("access_token").toString(); String refreshToken = result.get("refresh_token").toString(); WXUser wxUserUpdate = new WXUser(); wxUserUpdate.setId(wxUser.getId()); wxUserUpdate.setAccessToken(accessToken); wxUserUpdate.setRefreshToken(refreshToken); wxUserUpdate.setUpdateTime(new Date()); wxUserService.updateById(wxUserUpdate); return R.data(accessToken); } @ResponseBody @GetMapping("/getUserInfo") @ApiOperation("获取用户信息") public R getUserInfo() { Long userId = 1L; WXUser wxUser = wxUserService.getOne(new LambdaUpdateWrapper ().eq(WXUser::getUserId, userId)); String accessToken = wxUser.getAccessToken(); String openid = wxUser.getOpenid(); String userInfoJsom = WeiXinUtil.getUserInfo(accessToken, openid); WXUser userInfo = JSONObject.parseObject(userInfoJsom, WXUser.class); userInfo.setId(wxUser.getId()); userInfo.setUpdateTime(new Date()); wxUserService.updateById(userInfo); return R.data(userInfo); } }
微信扫码关注测试公众号
生成一个二维码调用获取code的接口,百度搜索 将获取code的URL路径填入码,手机微信扫码即可 : 草料文本二维码生成器,微信通过此入口即可访问获取code的页面, 注意:一定要使用手机微信客户端扫码二维码
流程:
获取code中的 redirect_uri 参数可以配置为我们的微信登录接口,这里为了演示功能,配置成了获取access_token 的接口
1. 通过获取code的接口,微信会通过我们配置的redirect_uri参数回调我们的接口,并会携带上code参数,同时注意此接口不要添加@ResponseBody 的注解
2. 微信回调获取access_token的接口,我们可以获取到access_token,refresh_token,openid这三个重要参数,这也是获取用户个人信息的关键
3. 刷新access_token的步骤可省略,有需要时可以调用此功能
4. 获取用户信息,这里获取用户信息的前提是我们在获取code的接口中,参数中的授权范围参数写为snsapi_userinfo