1、前言
今天我们就来讲解下最后一篇如何使用SpringSocial来处理类似微信、QQ社交账号登录自己的平台,也就是大家说的第三方登录,获取社交账户所在平台的用户信息,与自己平台信息做个绑定的操作,两个系统之间是通过UserId交换信息的,这点一定要注意,平台用户表(Users)之间是社交用户表(UserConnection)之间关系如下所示:
Users表:
id | name | age |
---|---|---|
1 | David | 18 |
2 | Sam | 22 |
3 | Tom | 30 |
UserConnection表:
userId | providerId | providerUserId | accessToken | secret |
---|---|---|---|---|
1 | xxxxxxxxx | |||
2 | xxxxxxxxx | |||
3 | sian | xxxxxxxxx |
这里我要提一下,在你没有登录你自己的平台系统之前你点击微信登录的时候要进行判断是否已经绑定,判断的依据是通过providerId和providerUserId从UserConnection表里面查询出社交账户信息,然后通过对应的userId再通过SocialUserDetailsService提供的loadUserByUserId方法查询出系统平台的User用户信息。
1、如果已经绑定(说明上面查询到了)就直接生成token并返回给前端;
2、如果没有(说明上面没有查询到)就需要注册并绑定了(往两张表中插入数据并建立关系)。
2、QQ的实现
首先我们来看看QQ的实现,我把代码都贴出来,遇到关键的地方我会讲解一下,其它的自己看看就明白了
上面是具体的代码目录结构,你没必要和我一模一样,只要能实现就好。
QQUserInfo
package com.awbeci.ssb.core.social.qq.api;
public class QQUserInfo {
/**
* 返回码
*/
private String ret;
/**
* 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。
*/
private String msg;
/**
*
*/
private String openId;
/**
* 不知道什么东西,文档上没写,但是实际api返回里有。
*/
private String is_lost;
/**
* 省(直辖市)
*/
private String province;
/**
* 市(直辖市区)
*/
private String city;
/**
* 出生年月
*/
private String year;
/**
* 用户在QQ空间的昵称。
*/
private String nickname;
private String constellation;
/**
* 大小为30×30像素的QQ空间头像URL。
*/
private String figureurl;
/**
* 大小为50×50像素的QQ空间头像URL。
*/
private String figureurl_1;
/**
* 大小为100×100像素的QQ空间头像URL。
*/
private String figureurl_2;
/**
* 大小为40×40像素的QQ头像URL。
*/
private String figureurl_qq_1;
/**
* 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100×100的头像,但40×40像素则是一定会有。
*/
private String figureurl_qq_2;
/**
* 性别。 如果获取不到则默认返回”男”
*/
private String gender;
/**
* 标识用户是否为黄钻用户(0:不是;1:是)。
*/
private String is_yellow_vip;
/**
* 标识用户是否为黄钻用户(0:不是;1:是)
*/
private String vip;
/**
* 黄钻等级
*/
private String yellow_vip_level;
/**
* 黄钻等级
*/
private String level;
/**
* 标识是否为年费黄钻用户(0:不是; 1:是)
*/
private String is_yellow_year_vip;
public String getRet() {
return ret;
}
public void setRet(String ret) {
this.ret = ret;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getIs_lost() {
return is_lost;
}
public void setIs_lost(String is_lost) {
this.is_lost = is_lost;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getYear() {
return year;
}
public void setYear(String year) {
this.year = year;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getFigureurl() {
return figureurl;
}
public void setFigureurl(String figureurl) {
this.figureurl = figureurl;
}
public String getFigureurl_1() {
return figureurl_1;
}
public void setFigureurl_1(String figureurl_1) {
this.figureurl_1 = figureurl_1;
}
public String getFigureurl_2() {
return figureurl_2;
}
public void setFigureurl_2(String figureurl_2) {
this.figureurl_2 = figureurl_2;
}
public String getFigureurl_qq_1() {
return figureurl_qq_1;
}
public void setFigureurl_qq_1(String figureurl_qq_1) {
this.figureurl_qq_1 = figureurl_qq_1;
}
public String getFigureurl_qq_2() {
return figureurl_qq_2;
}
public void setFigureurl_qq_2(String figureurl_qq_2) {
this.figureurl_qq_2 = figureurl_qq_2;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getIs_yellow_vip() {
return is_yellow_vip;
}
public void setIs_yellow_vip(String is_yellow_vip) {
this.is_yellow_vip = is_yellow_vip;
}
public String getVip() {
return vip;
}
public void setVip(String vip) {
this.vip = vip;
}
public String getYellow_vip_level() {
return yellow_vip_level;
}
public void setYellow_vip_level(String yellow_vip_level) {
this.yellow_vip_level = yellow_vip_level;
}
public String getLevel() {
return level;
}
public void setLevel(String level) {
this.level = level;
}
public String getIs_yellow_year_vip() {
return is_yellow_year_vip;
}
public void setIs_yellow_year_vip(String is_yellow_year_vip) {
this.is_yellow_year_vip = is_yellow_year_vip;
}
public String getConstellation() {
return constellation;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
}
public interface QQ {
QQUserInfo getUserInfo();
}
QQImpl
package com.awbeci.ssb.core.social.qq.api.impl;
public class QQImpl extends AbstractOAuth2ApiBinding implements QQ {
private Logger logger = LoggerFactory.getLogger(getClass());
//http://wiki.connect.qq.com/openapi%E8%B0%83%E7%94%A8%E8%AF%B4%E6%98%8E_oauth2-0
private static final String QQ_URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";
//http://wiki.connect.qq.com/get_user_info(access_token由父类提供)
private static final String QQ_URL_GET_USER_INFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";
//appId 配置文件读取
private String appId;
//openId 请求QQ_URL_GET_OPENID返回
private String openId;
/**
* 工具类
*/
private ObjectMapper objectMapper = new ObjectMapper();
/**
* 构造方法获取openId
*/
public QQImpl(String accessToken, String appId) {
//access_token作为查询参数来携带。
super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
this.appId = appId;
String url = String.format(QQ_URL_GET_OPENID, accessToken);
String result = getRestTemplate().getForObject(url, String.class);
logger.info("【QQImpl】 QQ_URL_GET_OPENID={} result={}", QQ_URL_GET_OPENID, result);
this.openId = StringUtils.substringBetween(result, "\"openid\":\"", "\"}");
}
public QQUserInfo getUserInfo() {
String url = String.format(QQ_URL_GET_USER_INFO, appId, openId);
String result = getRestTemplate().getForObject(url, String.class);
logger.info("【QQImpl】 QQ_URL_GET_USER_INFO={} result={}", QQ_URL_GET_USER_INFO, result);
QQUserInfo userInfo = null;
try {
userInfo = objectMapper.readValue(result, QQUserInfo.class);
userInfo.setOpenId(openId);
log