官方文档:
微信(appid和secret)微信网页开发 /网页授权
QQ(appid和appkey)QQ互联 | 网站开发流程
一、填写审核信息
1. 申请开发者身份,以企业名义申请。申请地址:
微信开放平台(微信开放平台)
QQ互联(QQ互联官网首页)
2. 填写网站审核资料
备案号查询网站(https://beian.miit.gov.cn/#/Integrated/recordQuery)
网站名称、网站地址、主办单位名称、网站地址备案号需要和备案号网站查询结果一致。
注意:
* 项目上线后才能审核通过。必须是正式环境才可以。
* 登录页需放置QQ图标,点击图标跳转至QQ登录页面(https://graph.qq.com/oauth2.0/authorize)
* 申请的网站回调域需和代码中的一致,否则会报错(QQ)
申请的网站回调域接口不要求一致,但域名要求一致(微信)
* 微信申请需要注册账号,注册账号需要300元审核费
* 咨询客服链接:腾讯开放平台 OPEN.QQ.COM

二、代码开发(QQ登录)
1. 步骤一:用户点击QQ登录图标,跳转至QQ授权页面
<div class="login_qq">
<a class="qq" href="${baseUrl}/qqLogin">
<img alt="QQ登录" title="QQ登录" src="${staticBaseUrl}/static/img/qq_icon.png">
</a>
</div> //QQ审核获取的qppid和appkey
@Value("${qq.appid}")
private String appid;
@Value("${qq.appkey}")
private String appkey; /**
* QQ登录
* 步骤一:用户跳转至授权页面
* @author 点点
* @date 2021年6月17日
*/
@RequestMapping(value = "/qqLogin" , method = {RequestMethod.POST , RequestMethod.GET})
public String qqLogin(HttpServletRequest request, String display) throws IOException {
String redirectUri = URLEncoder.encode(request.getAttribute("baseUrl")+"/getOpenId/qq","utf-8");
String state = String.valueOf(UUID.randomUUID());
cache.set(state, "", 30*1000);
String codeUrl = "https://graph.qq.com/oauth2.0/authorize?" +
"client_id=" + appid +
"&redirect_uri=" + redirectUri +
"&response_type=code" +
"&scope=get_user_info" +
"&display=" + display +
"&state=" + state + "#qq_redirect";
return "redirect:"+codeUrl;
}官方说明:

2. 步骤二:跳转授权页面获得code,通过code换取用户授权access_token
/**
* QQ登录
* 步骤二:同意授权,获得code,通过code换取网页授权access_token
* @author 点点
* @date 2021年6月17日
*/
@RequestMapping(value = "/getOpenId/qq", method = {RequestMethod.POST,
RequestMethod.GET})
public String getQqOpenId(String code, String state,
HttpServletRequest request)
throws IOException {
//state校验,防止CSRF攻击
String stateCache = cache.get(state, String.class);
if (StringUtils.isBlank(stateCache)) {
//跳转登录页,state校验不通过
return "redirect:/login.html";
}
cache.del(state);
//若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数
if(StringUtils.isBlank(code)) {
//跳转登录页,用户未授权
return "redirect:/login.html";
}
//申请的网站回调域需和代码中的一致,否则会报错(申请的网站回调域就是redirectUri)
String redirectUri = URLEncoder.encode(
request.getAttribute("baseUrl")+"/getOpenId/qq", "utf-8");
//步骤二:通过code获取access_tokens
String atUrl = "https://graph.qq.com/oauth2.0/token?" +
"grant_type=authorization_code" +
"&client_id=" + appid +
"&client_secret=" + appkey +
"&code=" + code +
"&redirect_uri=" + redirectUri +
"&fmt=json";
String atResult = HttpUtils.sendGet(atUrl);
JSONObject atObj = JSONObject.parseObject(atResult);
String access_token = atObj.getString("access_token");
if (StringUtils.isBlank(access_token)) {
//跳转登录页,获取access_tokens失败
return "redirect:/login.html";
}
//步骤三:通过access_tokens获取openid
String openidUrl = "https://graph.qq.com/oauth2.0/me?" +
"access_token=" + access_token +
"&fmt=json";
String openidResult = HttpUtils.sendGet(openidUrl);
if (StringUtils.isBlank(openidResult)) {
//跳转登录页,获取openid失败
return "redirect:/login.html";
}
JSONObject openidObj = JSONObject.parseObject(openidResult);
String openid = openidObj.getString("openid");
//1.校验该用户是否已注册:
User user = this.userService.getModelByQqOpenid(openid);
if (user == null) {
//跳转到获取手机号页面(用户手机号码必填且唯一,不需要的可省略该步骤)
//注册方式registerType:3-QQ登录
String param = "access_token="+access_token+"&openid="+openid+"®isterType=3";
return "redirect:/settingPhone.html?" + param;
}
//2.登录
//2.1 登录校验
User userModel = userService.loginCheck(user);
if (userModel == null) {
//跳转登录页,账号已锁定
return "redirect:/login.html";
}
//2.2 登录
userService.login(userModel);
//登陆成功,跳转首页
return "redirect:/index.html";
}3. 步骤四:通过access_token和openid,获取用户信息
/**
* QQ登录(第三方注册)
* 步骤四:通过access_token和openid,获取用户信息
* @author 点点
* @date 2021年6月17日
*/
@RequestMapping(value = "/getUserInfo" , method = RequestMethod.POST)
public APIResult<String> getUserInfo(String access_token, String openid,
String phone, String verificationCode)
throws IOException {
//1.校验
// 校验手机号
//2. 注册
//步骤四:通过access_token和openid,获取用户信息
String infoUrl = "https://graph.qq.com/user/get_user_info?" +
"access_token=" + access_token +
"&openid=" + openid +
"&oauth_consumer_key=" + appid;
String infoResult = HttpUtils.sendGet(infoUrl);
JSONObject jsonObject = JSONObject.parseObject(infoResult);
//jsonObject.getString("nickname"); 昵称
//jsonObject.getString("figureurl_1"); 头像
//jsonObject.getString("gender"); 性别
//if (StringUtils.isBlank(nickname)) {
// return APIResult.error("页面失效");
//}
User user = this.userService.qqRegister(openid, phone);
//2.登录
//2.1 登录校验
User userModel = userService.loginCheck(user);
if (userModel == null) {
return APIResult.error("账号已锁定");
}
//2.2 登录
userService.login(userModel);
return APIResult.ok("登录成功");
}
三、调试
由于是正式环境,导致每次调试需要重新发包,很不方便。有以下两种调试方式:
1. 将正式环境域名映射到本地,即可本地调试。
2. 如果是客户方环境无法映射,则可在“步骤二:跳转授权页面获得code”时,将数据重新请求到本地进行调试,但是需要写两套代码,也比较麻烦。
四、代码开发(微信登录)
(偷个小懒)
1. 微信和QQ代码几乎一致,将qq的关键字替换为wx(注意区分大小写哦~)
2. 步骤一:用户点击WX登录图标,跳转至WX授权页面
String url = "https://open.weixin.qq.com/connect/qrconnect?" +
"appid=" + appid +
"&redirect_uri=" + redirectUri +
"&response_type=code" +
"&scope=snsapi_login" +
"&state=" + state + "#wechat_redirect";3. 步骤二:通过code获取access_tokens
String atUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
"appid=" + appid +
"&secret=" + secret +
"&code=" + code +
"&grant_type=authorization_code";4. 步骤三:通过access_token和openid,获取用户信息
String infoUrl = "https://api.weixin.qq.com/sns/userinfo?" +
"access_token=" + access_token +
"&openid=" + openid +
"&lang=zh_CN";
5. 用户信息部分字段
{
"openid": "OPENID",
"nickname": NICKNAME,
"sex": 1, //用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
"province":"PROVINCE",
"city":"CITY",
"country":"COUNTRY",
"headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2" ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}如果有更好的调试方法或代码有改进之处,欢迎大家留言交流~