JAVA(SpringBoot)对接微信登录
目录
1 申请测试账号
1.1 登录测试平台
1.2 配置接口配置信息
编辑
1.3 配置JS接口安全域名
1.4 配置网页授权获取用户基本信息
2:接口代码
2.1 微信登录流程
2.2 依赖导入:
2.2.1 工具类:
2.3 创建微信用户实体类
2.4 接口功能
3 测试
1 申请测试账号
1.1 登录测试平台
链接: 微信公众平台测试
1.2 配置接口配置信息
在这一步,需要拥有能接入公网的服务器,或者利用内网穿透将自己的接口暴漏给微信,让微信的回调能成功访问到我们的接口
在可以将我们的接口暴漏在公网的前提下,我们可以书写接口配置接口配置信息的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 (有域名使用域名即可)
1.3 配置JS接口安全域名
在测试公众号中,可以使用 IP + 端口 的形式设置安全域名,这里的域名填写上述服务你所部署的服务器地址即可
1.4 配置网页授权获取用户基本信息
这里的授权回调页面域名和JS接口安全域名保持一致即可
2:接口代码
2.1 微信登录流程
微信客户端发送登录请求 -> 访问微信授权接口 -> 微信回调,j将授权code发送到我们的服务器 -> 通过code,appid,appsecret获取微信针对该用户的accsess_token,openid等信息-> 通过accsess_token,openid获取用户信息
2.2 依赖导入:
在下叙代码中使用到了hutool的工具类,swagger的工具类,通过maven的pom文件导入:(注:实体类使用了一些mybatis-plus的注解,如无用删除即可)
<!-- hutool工具依赖--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.10</version></dependency><!-- Swagger3 --><dependency><groupId>io.springfox</groupId><artifactId>springfox-boot-starter</artifactId><version>3.0.0</version></dependency><!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui --><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>3.0.0</version></dependency><!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter --><dependency><groupId>com.github.xiaoymin</groupId><artifactId>knife4j-spring-boot-starter</artifactId><version>3.0.3</version></dependency>
2.2.1 工具类:
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;}
}
2.3 创建微信用户实体类
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;
}
2.4 接口功能
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 "<h1>看样子成功了,没你事了退下吧</h1>";}@ResponseBody@GetMapping("/refreshToken")@ApiOperation("刷新token")public R refreshToken() {Long userId = 1L;WXUser wxUser = wxUserService.getOne(new LambdaUpdateWrapper<WXUser>().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<WXUser>().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);}}
3 测试
微信扫码关注测试公众号
生成一个二维码调用获取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