Social实现QQ登入符合Oauth2协议,基本步骤如上图,步骤1-5都是固定的(Social已经封装好),步骤6获取的用户信息各不相同需要自定义,步骤7就是我们的登入原理了。
接着通过SocialAuthenticationFilter加入过滤器链中
public interface QQ {
QQUserInfo getUserInfo() ;
}
public class QQImpl extends AbstractOAuth2ApiBinding implements QQ{
protected final Log logger = LogFactory.getLog(getClass());
private String openid;
private String appId;
private ObjectMapper objectMapper = new ObjectMapper();
//获取用户openid的url
private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";
//获取用户信息的url (注:accessToken不用传,系统会自动加上去)
private static final String URL_GET_USERINFO ="https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s";
public QQImpl(String accessToken,String appId) {
super(accessToken,TokenStrategy.ACCESS_TOKEN_PARAMETER);
this.appId = appId;
//通过Access Token,得到对应用户身份的OpenID。
//https://graph.qq.com/oauth2.0/me?access_token=F679F117539B5042872183269AF866E5
//callback( {"client_id":"101726424","openid":"6F204B99FF2E96686342B71B7FFC384A"} );
String url_openid = String.format(URL_GET_OPENID,accessToken);
String tar = getRestTemplate().getForObject(url_openid, String.class);
logger.info("通过Access Token,得到对应用户身份的OpenID,返回数据 【"+ tar +"】");
this.openid = StringUtils.substringBetween(tar,"\"openid\":\"","\"}");
}
/**
* 获取用户信息
* @return
*/
@Override
public QQUserInfo getUserInfo() {
String url_user = String.format(URL_GET_USERINFO,this.appId);
String tar = getRestTemplate().getForObject(url_user, String.class);
logger.info("获取用户信息,返回数据 【"+ tar +"】");
QQUserInfo qqUserInfo = null;
try {
qqUserInfo = objectMapper.readValue(tar, QQUserInfo.class);
} catch (IOException e) {
logger.info("获取用户信息失败 【"+ e.getMessage() +"】");
}
return qqUserInfo;
}
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;
/**
* 大小为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 figureurl_qq;
private String figureurl_type;
/**
* 性别。 如果获取不到则默认返回”男”
*/
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;
private String constellation;
public String getConstellation() {
return constellation;
}
public void setConstellation(String constellation) {
this.constellation = constellation;
}
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 getFigureurl_qq() {
return figureurl_qq;
}
public void setFigureurl_qq(String figureurl_qq) {
this.figureurl_qq = figureurl_qq;
}
public String getFigureurl_type() {
return figureurl_type;
}
public void setFigureurl_type(String figureurl_type) {
this.figureurl_type = figureurl_type;
}
}
public class QQApiAdapter implements ApiAdapter {
@Override
public boolean test(QQ api) {
return true;
}
@Override
public void setConnectionValues(QQ api, ConnectionValues values) {
//将qq用户数据转成通用的connection数据
QQUserInfo userInfo = api.getUserInfo();
values.setDisplayName(userInfo.getNickname());
values.setImageUrl(userInfo.getFigureurl_qq_1());
values.setProfileUrl(null);
values.setProviderUserId(userInfo.getOpenId());
}
@Override
public UserProfile fetchUserProfile(QQ api) {
return null;
}
@Override
public void updateStatus(QQ api, String message) {
}
}
public class QQServiceProvider extends AbstractOAuth2ServiceProvider {
private String appId;
private static final String URL_AUTHORIZE = "https://graph.qq.com/oauth2.0/authorize";
private static final String URL_ACCESS_TOKEN = "https://graph.qq.com/oauth2.0/token";
/**
* Create a new {@link OAuth2ServiceProvider}.
*
* @param oauth2Operations the OAuth2Operations template for conducting the OAuth 2 flow with the provider.
*/
public QQServiceProvider(String appId,String appSecret) {
//super(oauth2Operations);
super(new OAuth2Template(appId, appSecret, URL_AUTHORIZE,URL_ACCESS_TOKEN));
}
@Override
public QQ getApi(String accessToken) {
return new QQImpl(accessToken,appId);
}
}
public class QQConnectionFactory extends OAuth2ConnectionFactory {
/**
* Create a {@link OAuth2ConnectionFactory}.
*
* @param providerId the provider id e.g. "facebook"
* @param serviceProvider the ServiceProvider model for conducting the authorization flow and obtaining a native service API instance.
* @param apiAdapter the ApiAdapter for mapping the provider-specific service API model to the uniform {@link Connection} interface.
*/
public QQConnectionFactory(String providerId,String appId,String appSecret) {
super(providerId,new QQServiceProvider(appId,appSecret),new QQApiAdapter() );
}
}
基本的类已经编写完成,接下来就是把各个类通过配置串联起来。