/**
* unionLoginCallbackPath
*/
@Value("${QQ_UNION_LOGIN_CALLBACK_PATH}")
private String qqUnionLoginCallbackPath;
/**
* appKey
*/
@Value("${QQ_CONSUMER_KEY}")
private String appKey;
/**
* appSecret
*/
@Value("${QQ_CONSUMER_SECRET}")
private String appSecret;
/**
* loginUrl
*/
@Value("${QQ_LOGIN_URL}")
private String loginUrl;
/**
* accessTokenUrl
*/
@Value("${QQ_ACCESS.TOKEN_URL}")
private String accessTokenUrl;
/**
* openIdUrl
*/
@Value("${QQ_OPEN_ID_URL}")
private String openIdUrl;
/**
* userInfoUrl
*/
@Value("${QQ_USER_INFO_URL}")
private String userInfoUrl;
public QQUnionLoginApi() {}
/**
* 獲得QQ登錄URL,第一步流程
* @param callBackPage
* @return
*/
public String getQQLoginUrl() {
// 獲取QQ登錄頁面的url
StringBuilder qqLoginUrl = new StringBuilder();
// QQ登陸地址 用於獲取Authorization Code
qqLoginUrl.append(this.loginUrl);
// 授權類型,此值固定為“code”
qqLoginUrl.append("?response_type=code");
// 申請QQ登錄成功後,分配給應用的appid
qqLoginUrl.append("&client_id=" + this.appKey);
// 成功授權後的回調地址,建議設置為網站首頁或網站的用戶中心。
qqLoginUrl.append("&redirect_uri=" + qqUnionLoginCallbackPath);
// 請求用戶授權時向用戶顯示的可進行授權的列表。如果要填寫多個接口名稱,請用逗號隔開。 不傳則默認請求對接口get_user_info進行授權
qqLoginUrl.append("&scope=");
// client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回調時會原樣帶回。
qqLoginUrl.append("&state=javaSdk-code");
// 用於展示的樣式。不傳則默認展示為為PC下的樣式。
// 如果傳入“mobile”,則展示為mobile端下的樣式。
qqLoginUrl.append("&display=");
LOG.info("build QQLoginUrl:" + qqLoginUrl.toString());
return qqLoginUrl.toString();
}
/**
* 獲取請求access token 的URL第二步流程
* @param authorizationCode
* @param callBackPage
* @return
*/
public String getQQAccessTokenUrl(String authorizationCode) {
StringBuilder accessTokenUrl = new StringBuilder();
// 通過Authorization Code獲取Access Token 的URl
accessTokenUrl.append(this.accessTokenUrl);
// QQ登陸地址 用於獲取Authorization Code
accessTokenUrl.append("?grant_type=authorization_code");
// 申請QQ登錄成功後,分配給應用的appid
accessTokenUrl.append("&client_id=" + this.appKey);
// 申請QQ登錄成功後,分配給網站的appkey
accessTokenUrl.append("&client_secret=" + this.appSecret);
// 登陸成功後返回的authorization code
accessTokenUrl.append("&code=" + authorizationCode);
// client端的狀態值。用於第三方應用防止CSRF攻擊,成功授權後回調時會原樣帶回。
accessTokenUrl.append("&state=javaSdk-token");
// 成功授權後的回調地址,建議設置為網站首頁或網站的用戶中心。
accessTokenUrl.append("&redirect_uri=" + qqUnionLoginCallbackPath);
return accessTokenUrl.toString();
}
/**
* 刷新access token 的URL
* @param authorizationCode
* @param callBackPage
* @return
*/
public String refreshQQAccessTokenUrl(String refresToken) {
StringBuilder refresTokenUrl = new StringBuilder();
//刷新access token 的URL
refresTokenUrl.append(this.accessTokenUrl);
// 刷新access token 的標志
refresTokenUrl.append("?grant_type=refresh_token");
// 申請QQ登錄成功後,分配給應用的appid
refresTokenUrl.append("&client_id=" + this.appKey);
// 申請QQ登錄成功後,分配給網站的appkey
refresTokenUrl.append("&client_secret=" + this.appSecret);
// 返回的refresToken
refresTokenUrl.append("&refresh_token=" + refresToken);
return refresTokenUrl.toString();
}
/**
* 獲取請求open id的URL,open id就是QQ第3方用戶ID,第3步流程
* @param accessToken
* @return
*/
public String getQQOpenIdUrl(String accessToken) {
// 換取OpenId的URL
StringBuilder openIdUrl = new StringBuilder();
// 使用Access Token來獲取用戶的OpenID 的URl
openIdUrl.append(this.openIdUrl);
// ACCESS_TOKEN
openIdUrl.append("?access_token=" + accessToken);
return openIdUrl.toString();
}
/**
* 動態拼接獲取用戶數據的url 第4部流程,獲取用戶的昵稱
* @param accessToken
* @param openId
* @return
*/
public String getQQUserInfoUrl(String accessToken, String openId) {
// 動態拼接獲取用戶數據的url
StringBuilder userInfoUrl = new StringBuilder();
// 獲取用戶數據接口的URl
userInfoUrl.append(this.userInfoUrl);
// 應用的appid
userInfoUrl.append("?oauth_consumer_key=" + this.appKey);
// 應用的accessToken
userInfoUrl.append("&access_token=" + accessToken);
// 應用的OpenID
userInfoUrl.append("&openid=" + openId);
return userInfoUrl.toString();
}
/**
* 用 authorizationCode 換取 AccessToken
*
* @param authorizationCode 換取accessToken的code
* @return AccessToken
* @throws IOException
*/
public String getQQAccessToken(String code) throws IOException {
String accessTokenUrl = getQQAccessTokenUrl(code);
LOG.info("access_token init:" + accessTokenUrl);
String accessToken = "";
String expires_in = "";
String refresh_token = "";
// 接受返回的字符串 包含accessToken
String tempStr = "";
// 請求QQ接口,回去返回數據
tempStr = doGet(accessTokenUrl);
LOG.info("access_token response:" + tempStr);
// 獲取accessToken失敗的場合
if (tempStr.indexOf("access_token") >= 0) {
accessToken = tempStr.split("&")[0].split("=")[1];
expires_in = tempStr.split("&")[1].split("=")[1];
refresh_token = tempStr.split("&")[2].split("=")[1];
//token失效則重新獲取
if(!StringUtil.isNumber(expires_in)){
accessToken = refreshQQAccessToken(refresh_token);
}
LOG.info("access_token:" + accessToken);
return accessToken;
} else {
LOG.info("access_token get fail return:" + tempStr);
return "";
}
}
/**
* 用 refreshToken 刷新 AccessToken
*
* @param refreshToken
* @return AccessToken
* @throws IOException
*/
public String refreshQQAccessToken(String refreshToken) throws IOException {
LOG.info("refresh_access_token init:" + refreshToken);
String refreshTokenUrl = refreshQQAccessTokenUrl(refreshToken);
String accessToken = "";
String expires_in = "";
// 接受返回的字符串 包含accessToken
String tempStr = "";
LOG.info("refresh_access_token url:" + refreshToken);
// 請求QQ接口,回去返回數據
tempStr = doGet(refreshTokenUrl);
LOG.info("refresh_access_token response:" + refreshToken);
// 獲取accessToken失敗的場合
if (tempStr.indexOf("access_token") >= 0) {
accessToken = tempStr.split("&")[0].split("=")[1];
expires_in = tempStr.split("&")[1].split("=")[1];
if(!StringUtil.isNumber(expires_in)){
accessToken = "";
}
LOG.info("refresh_access_token:" + accessToken);
return accessToken;
} else {
LOG.info("refresh_access_token get fail return:" + tempStr);
return "";
}
}
/**
* 根據AccessToken獲取OpenId
*
* @param accessToken AccessToken
* @return OpenId
* @throws JsonMappingException
* @throws JsonParseException
* @throws IOException
* @throws JSONException
*/
@SuppressWarnings("unchecked")
public String getQQOpenId(String accessToken) throws IOException{
// 獲取OpenId
String openId = "";
String getQQOpenIdUrl = getQQOpenIdUrl(accessToken);
LOG.info("refresh_access_token init:" + getQQOpenIdUrl);
// 請求QQ接口,回去返回數據
String interfaceData = doGet(getQQOpenIdUrl);
interfaceData = interfaceData.substring(interfaceData.indexOf("{"),interfaceData.indexOf("}") + 1);
LOG.info("get openid response:" + interfaceData);
try {
Map<String, String> map = JsonUtils.json2Object(interfaceData, HashMap.class);
LOG.info("get openid response to map:" + StringUtil.printParam(map));
if(map.get("openid")!=null){
openId = map.get("openid");
LOG.info("openid:" + openId);
}
} catch (Exception e) {
LOG.info("get QQ openid erro:" + e.getMessage());
}
return openId;
}
@SuppressWarnings("unchecked")
public String getUserNickName(String accessToken, String openId) throws IOException {
String getNickNameUrl = getQQUserInfoUrl(accessToken, openId);
LOG.info("get nickname init:" + getNickNameUrl);
// 獲取接口返回的數據
String interfaceData = doGet(getNickNameUrl);
String nickName = "";
LOG.info("get nickname response:" + interfaceData);
try {
Map<String, String> map = JsonUtils.json2Object(interfaceData, HashMap.class);
if(map.get("nickname")!=null){
// 昵稱
nickName = map.get("nickname");
LOG.info("get nickname:" + nickName);
}
} catch (Exception e) {
LOG.info("get QQ nickName erro:" + e.getMessage());
}
return nickName;
}
/**
* 鏈接QQ服務接口
*
* @param interfaceUrl
* 接口URL
*
* @return 接口返回的數據
* @throws IOException
*/
public String doGet(String interfaceUrl) throws IOException {
// 打印日志
LOG.info("QQ unionLogun doGet:" + interfaceUrl);
String interfaceData = "";
try
{
HttpResponseWrapper httpResponseWrapper = HttpsUtil.requestGetResponse(interfaceUrl);
int state = httpResponseWrapper.getStatusCode();
// 打印日志
LOG.info("QQ unionLogun doGet request Code:" + state);
// 是否請求正常
if (HttpsUtil.isCallOK(state)) {
// 獲取返回的數據流
BufferedReader input = new BufferedReader(new InputStreamReader(httpResponseWrapper.getResponseStream(),"UTF-8"));
String tempStr = "";
// 獲取返回的內容
while ((tempStr = input.readLine()) != null) {
interfaceData += tempStr.replace("\t", "");
}
}
// 關閉連接
httpResponseWrapper.close();
}
catch(Exception ex)
{
LOG.error(ex,ex);
}
// 打印日志
LOG.info("QQ unionLogun doGet return json:" + interfaceData);
return interfaceData;
}