由于QQ登录也可以在web浏览器和app端去使用,所以我们将其放在spring-security-core里面。
我们查看AbstractOAuth2ApiBinding的属性:
private final String accessToken; private RestTemplate restTemplate;
我们查看获取qq用户信息文档: https://wiki.connect.qq.com/ 查看里面的API文档,获取里面的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;
/**
* 大小为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;
//getter setter
public interface QQ {
/**
* 获取QQ信息
*/
QQUserInfo getUserInfo();
}
public class QQImpl extends AbstractOAuth2ApiBinding implements QQ {
private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";
private static final String URL_GET_USERINFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";
private String appId;
private String openId;
private ObjectMapper objectMapper = new ObjectMapper();
public QQImpl(String accessToken, String appId) {
//设置accessToken是在url参数上传递,默认在header里面
super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
this.appId = appId;
String url = String.format(URL_GET_OPENID, accessToken);
String result = getRestTemplate().getForObject(url, String.class);
System.out.println(result);
this.openId = StringUtils.substringBetween(result, "/"openid/":/"", "/"}");
}
@Override
public QQUserInfo getUserInfo() {
String url = String.format(URL_GET_USERINFO, appId, openId);
String result = getRestTemplate().getForObject(url, String.class);
System.out.println(result);
try {
return objectMapper.readValue(result,QQUserInfo.class);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("获取用户信息失败", e);
}
}
}
新建包:com.yxm.security.core.connect,创建类:
继承接口时候:需要返回一个接口泛型:这个接口泛型是前面讲的Api模块的实现类的接口;这里面指代qq。
AbstractOAuth2ServiceProvider<QQ>
QQServiceProvider代码:
public class QQServiceProvider extends AbstractOAuth2ServiceProvider<QQ> {
private String appId;
/**
*应用将用户导向认证服务器时候,导向的url;
* https://wiki.connect.qq.com/的qq互联:网站应用-->获取Access_Token->Step1:获取Authorization Code的url:PC网站:https://graph.qq.com/oauth2.0/authorize
*/
private static final String URL_AUTHORIZA="https://graph.qq.com/oauth2.0/authorize";
private static final String URL_ACCESS_TOKEN="https://graph.qq.com/oauth2.0/token";
public QQServiceProvider(String appId,String appSecret) {
/**
* 1.我们从开发流程图上看到:ServiceProvider构建需要OAuth2Operations
* 2.我们在qq互联上注册我们的应用时候,clientId,clientSecret其实就是qq提供给第三方应用的appId,appSecret,相当于app
* 的用户名/密码。
* 3.authorizeUrl,accessTokenUr对应于我们SpringSocial基本原理里面的第一步和第四步。
* authorizeUrl---应用将用户导向认证服务器时候,导向的url是什么。
* accessTokenUr---第四部我们申请token时候携带的地址
*/
super(new OAuth2Template(appId,appSecret,URL_AUTHORIZA,URL_ACCESS_TOKEN));
}
@Override
public QQ getApi(String accessToken) {
/**
* 1.我们需要获取Api的时候:由于要求是accessToken是多值得,所以QQImpl是不能通过注解:@Component来注解的
* 因为final修饰的成员变量是不可变得,一个对象有一个成员变量,是全局的,我们这里用new
* 2.接受的2个参数:
* accessToken抽象类会传给我们,我们不用管。
* appId,需要我们自己处理了:所以我们需要自己传一个,由于appId指代qq提供的id,他是唯一的。
*/
return new QQImpl(accessToken,appId);
}
}
你好 QQServiceProvider完成了的话,相当于我们右边部分已经完成了,服务提供商相关代码完成了。
到此,QQ模块功能如下: