OAuth2.0开放授权实现微信扫码登录第三方平台
承灿 2023/12/1
# OAuth2.0开放授权实现微信扫码登录第三方平台
# 开发前准备
微信公众平台 (qq.com) (opens new window)
需要注册微信测试号

- 测试号信息是自动生成的,注意后面需要替换WechatUtil里面的APPID和SECRET
- 接口配置信息,URL需要搞一个内网穿透,打通你的电脑和微信之间的网络,这个很简单,下载:https://www.cpolar.com/这个应用,里面配置把你的本地服务端口给代理出去,URL可能用https会有问题,换http的试试,https-443,http80,你的服务是80,所以可能会有问题。
- JS接口安全域名:这个可以不弄
- 找到网页账号,点击编辑,配置OAuth2授权域名




# 相关依赖
hutool和google.zxing在生成Qrcode要用到
其他都是一些常见的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.5</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.32</version>
</dependency>
</dependencies>
# 实体类
# 获取access_token返回参数实体类
@Data
public class TokenInfo {
private String access_token;
private int expires_in;
private String refresh_token;
private String openid;
private String scope;
}
# 用户信息实体类
@Data
public class WeChatUserInfo {
private String openid;
private String nickname;
private int sex;
private String language;
private String city;
private String province;
private String country;
private String headimgurl;
private List<String> privilege;
}
# Controller控制器
package com.lcc.wechatdemo.controller;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.lcc.wechatdemo.model.entity.WeChatUserInfo;
import com.lcc.wechatdemo.util.WechatUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.net.URLEncoder;
/**
* @author: lichengcan
* @date: 2023-12-01 11:04
* @description 微信登录练习demo
**/
@RestController
@RequestMapping()
@Slf4j
public class WeChatController {
@Value("${wx.APPID}")
String APPID;
@Value("${wx.REDIRECTURL}")
String REDIRECTURL;
@Autowired
RestTemplate restTemplate;
@Autowired
WechatUtil wechatUtil;
@GetMapping("/wxCheck")
public String wxSignatureCheck(@RequestParam(value = "signature") String signature,
@RequestParam(value = "timestamp") String timestamp,
@RequestParam(value = "nonce") String nonce,
@RequestParam(value = "echostr") String echostr) {
//这里需要检验signature,确认是来自微信服务器
//1)将token、timestamp、nonce三个参数进行字典序排序
//2)将三个参数字符串拼接成一个字符串进行sha1加密
//3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信
//TODO 省略校验
log.info("收到微信校验请求,echostr:{}" + echostr);
return echostr;
}
/**
* 微信登录,生成登录二维码
* 如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
*
* @param response
* @throws Exception
*/
@GetMapping("/wxLogin")
@ResponseBody
public void wxLogin(HttpServletResponse response) throws Exception {
//redirectUrl是回调地址,需要转成UrlEncode格式
String redirectUrl = URLEncoder.encode(REDIRECTURL+"wxCallBack", "UTF-8");
//构造生成二维码链接地址
String url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid="+APPID+"&redirect_uri="
+ redirectUrl + "&response_type=code&scope=snsapi_userinfo#wechat_redirect";
//构造生成二维码,然后跳转上面的地址
response.setContentType("image/png");
QrCodeUtil.generate(url, 300, 300, "jpg", response.getOutputStream());
}
/**
* 通过code换取网页授权access_token
* 如果用户同意授权,页面将跳转至 redirect_uri/?code=CODE&state=STATE。
* code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。
*
* @param code
* @param state
* @param request
* @param response
* @param session
* @return
*/
@RequestMapping(value = "/wxCallBack")
@ResponseBody
public WeChatUserInfo wxCallBack(String code,
String state,
HttpServletRequest request,
HttpServletResponse response,
HttpSession session) {
WeChatUserInfo accessToken = wechatUtil.getUserInfo(code);
//TODO 缓存用户信息,构造session
return accessToken;
}
}
# RestTemplate配置类
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
# 工具类
二维码生成工具类
public class QrCodeTest {
/**
* L、M、Q、H 由低到高。
* 低级别的像素块更大,可以远距离识别,但是遮挡就会造成无法识别。
* 高级别则相反,像素块小,允许遮挡一定范围,但是像素块更密集。
* @param args
*/
public static void main(String[] args) {
QrConfig config = new QrConfig();
//设置容错级别
config.setErrorCorrection(ErrorCorrectionLevel.H);
QrCodeUtil.generate("https://hutool.cn/",300,300, FileUtil.file("d:/qrcode.jpg"));
}
}
微信接口工具类
@Component
public class WechatUtil {
@Value("${wx.APPID}")
String APPID;
@Value("${wx.SECRET}")
String SECRET;
public WeChatUserInfo getUserInfo(String code) {
//通过code换取网页授权access_token
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" +
APPID + "&secret=" + SECRET + "&code=" + code + "&grant_type=authorization_code";
RestTemplate restTemplate = new RestTemplate();
//1.获取token
String accessToken = restTemplate.getForObject(url, String.class);
TokenInfo tokenInfo = JSON.parseObject(accessToken, TokenInfo.class);
//2.获取用户信息
String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=" + tokenInfo.getAccess_token() + "&openid=" + tokenInfo.getOpenid() + "&lang=zh_CN";
String userInfo = restTemplate.getForObject(userInfoUrl, String.class);
WeChatUserInfo weChatUserInfo = JSON.parseObject(userInfo, WeChatUserInfo.class);
return weChatUserInfo;
}
}
# 配置文件yml
wx:
# 换成你自己的微信 ID、SECRET
APPID: wxa90967105d3402f4
SECRET: ab13896b831b85cba266ca4166f3d500
# cpolor代理的域名
REDIRECTURL: https://3524e8fe.r9.cpolar.top/
# 测试
访问域名+/wxLogin测试

获取到用户相关信息

# 问题记录
1使用微信扫码后没有授权页面,直接返回了用户信息
2返回的用户信息缺少了一部分,sex,language,city等都是空
相关文档:
https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/iOS_WKWebview.html
https://www.cpolar.com/