一:对接QQ前准备工作:
1,有已备案的域名;
2,https://connect.qq.com/登录QQ互联;
3,创建应用;
进入应用管理页面创建应用,根据实际需要是创建网站应用还是移动应用,我这里是网站应用:
4,提交完之后会自动提交审核,基本上就是审核你的资料和备案的资料是否一致,所有资料必须和备案资料一模一样,否则 审核不会通过;
二,接口讲解
Step1:放置QQ登录按钮
网站需要下载“QQ登录”按钮图片,并按照UI规范将按钮放置在页面合适的位置。
Step2:获取Authorization Code
1. 打开浏览器,访问如下地址(请将client_id,redirect_uri,scope等参数值替换为你自己的):
2. 如果用户已经有登录态,会弹出提示一个确认页。如果还没有登录,会弹出登录页,如下图所示:
Step3:通过Authorization Code获取Access Token
1.发送请求到如下地址(请将参数值替换为你自己的):
2.返值值:
access_token=token&expires_in=7776000&refresh_token=A38F7F82618085969038776EA883A990
3.第三方网站可存储access token信息,以便后续调用OpenAPI访问和修改用户信息时使用。
Step4:使用Access Token来获取用户的OpenID
1. 发送请求到如下地址。(请将access_token等参数值替换)
https://graph.qq.com/oauth2.0/me?access_token=token
2.返回值:callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} )
Step5:使用Access Token以及OpenID来访问和修改用户数据
1.发送请求到get_user_info的URL(请将access_token,appid等参数值替换为你自己的): https://graph.qq.com/user/get_user_info?access_token=token&appid=APP_ID&openid=OPENID
2.返回值:
userInfo:{
"ret": 0,
"msg": "",
"is_lost":0,
"nickname": "不哭死神",
"gender": "男",
"province": "香港",
"city": "九龙城区",
"year": "2014",
"constellation": "",
"figureurl": "http:\/\/qzapp.qlogo.cn\/qzapp\/101728010\/EE5A14DF9DA6707634C34062FB2C586D\/30",
"figureurl_1": "http:\/\/qzapp.qlogo.cn\/qzapp\/101728010\/EE5A14DF9DA6707634C34062FB2C586D\/50",
"figureurl_2": "http:\/\/qzapp.qlogo.cn\/qzapp\/101728010\/EE5A14DF9DA6707634C34062FB2C586D\/100",
"figureurl_qq_1": "http://thirdqq.qlogo.cn/g?b=oidb&k=edBLoLB3PJhcj27OtGFWRw&s=40&t=1557037098",
"figureurl_qq_2": "http://thirdqq.qlogo.cn/g?b=oidb&k=edBLoLB3PJhcj27OtGFWRw&s=100&t=1557037098",
"figureurl_qq": "http://thirdqq.qlogo.cn/g?b=oidb&k=edBLoLB3PJhcj27OtGFWRw&s=140&t=1557037098",
"figureurl_type": "1",
"is_yellow_vip": "0",
"vip": "0",
"yellow_vip_level": "0",
"level": "0",
"is_yellow_year_vip": "0"
}
三:代码实现:
1,第三方对接接口定义:
/**
* 第三方登录顶级接口
*
* @author reyco
* @date 2019年7月23日
*
*/
public interface LoginService {
/**
* 登录 ---返回重定向地址
* @return
*/
String login()throws Exception;
/**
* 回调地址
* @param code 登录成功后返回的code
* @param request 参数request
* @return
* @throws Exception
*/
String callback(String code,HttpServletRequest request) throws Exception;
}
2,qq实现:
@Component("qq")
public class QQLoginServiceImpl implements LoginService{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Override
public String login() {
// 回调地址
String backUrl = PropertiesUtil.getValue("qq.callback");
// appid
String qqID = PropertiesUtil.getValue("qq.id");
String state = UUID.randomUUID().toString().replaceAll("-", "");
String url = "https://graph.qq.com/oauth2.0/authorize?client_id=" + qqID + "&response_type=code" + "&scope=all"
+ "&redirect_uri=" + URLEncoder.encode(backUrl) + "&state="+state;
return url;
}
@Override
public String callback(String code,HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
// 获取token信息
Map<String, String> map = getAccessToken(code);
String accessToken = map.get("access_token");
// 获取appid
JSONObject openidObj = getAppid(accessToken);
String appid = openidObj.getString("client_id");
String openid = openidObj.getString("openid");
// 获取用户信息
JSONObject userInfo = getUserInfo(accessToken,appid,openid);
// 获取登录ip
String ip = CusAccessObjectUtil.getIpAddress(request); // 获取登录城市
String cityName = IPDataUtils.getCityName(ip); // 获取登录用户
String loginPhone = userInfo.getString("nickname");
User u = new User(3,5,ip, cityName, loginPhone);
session.setAttribute("user", u);
return "重定向地址";
}
/**
* 获取token信息
* @param code
* @return
* @throws Exception
*/
private Map<String,String> getAccessToken(String code) throws Exception {
Map<String,String> map = new HashMap<>();
String qqID = PropertiesUtil.getValue("qq.id");
String qqKey = PropertiesUtil.getValue("qq.key");
String backURL = PropertiesUtil.getValue("qq.callback");
String get_token_url = "https://graph.qq.com/oauth2.0/token?" + "grant_type=authorization_code" + "&client_id="
+ qqID + "&client_secret=" + qqKey + "&redirect_uri=" + backURL + "&code=" + code;
String response = restTemplate.getForObject(get_token_url,String.class);
logger.info("token:"+response);
String[] responses = response.split("&");
map.put("access_token", getValue(responses,0));
map.put("expires_in", getValue(responses,1));
map.put("refresh_token", getValue(responses,2));
return map;
}
private String getValue(String[] response,Integer index) {
String values = response[index];
String[] value = values.split("=");
return value[1];
}
/**
* 获取appid
* @return
* @throws JSONException
*/
private JSONObject getAppid(String token) throws JSONException {
String get_openid_url = "https://graph.qq.com/oauth2.0/me?access_token="+token;
String response = restTemplate.getForObject(get_openid_url,String.class);
logger.info("openId"+response);
String data = response.substring(response.indexOf("{"), response.indexOf("}")+1);
JSONObject jsonObject = new JSONObject(data);
return jsonObject;
}
/**
* 获取用户信息
* @param token
* @return
* @throws Exception
*/
private JSONObject getUserInfo(String token,String appid,String openid) throws Exception {
String get_userInfo_url = "https://graph.qq.com/user/get_user_info?access_token="+token+"&appid="+appid+"&openid="+openid;
String response = restTemplate.getForObject(get_userInfo_url,String.class);
logger.info("userInfo:"+response);
JSONObject jsonObject = new JSONObject(response);
return jsonObject;
}
}
3.微博实现
@Component("weibo")
public class WBLoginServiceImpl implements LoginService{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Override
public String login() {
// 回调地址
String backUrl = PropertiesUtil.getValue("weibo.callback");
// appid
String wbId = PropertiesUtil.getValue("weibo.id");
String state = UUID.randomUUID().toString().replaceAll("-", "");
String url = "https://api.weibo.com/oauth2/authorize?"
+ "client_id="+wbId
+ "&response_type=code"
+ "&scope=all"
+ "&display=pc"
+ "&redirect_uri="+ URLEncoder.encode(backUrl)
+ "&state="+state;
return url;
}
@Override
public String callback(String code,HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
JSONObject accessToken = getAccessToken(code);
String token = accessToken.getString("access_token");
JSONObject userInfo = getUserInfo(token);
// 获取登录ip
String ip = CusAccessObjectUtil.getIpAddress(request); // 获取登录城市
String cityName = IPDataUtils.getCityName(ip); // 获取登录用户
String uid = userInfo.getString("uid");
User u = new User(3,5,ip, cityName, uid);
session.setAttribute("user", u);
return "重定向地址";
}
/**
* 获取token信息
* @param code
* @return
* @throws Exception
*/
private JSONObject getAccessToken(String code) throws Exception {
String grant_type = "authorization_code";
String wbId = PropertiesUtil.getValue("weibo.id");
String wbKey = PropertiesUtil.getValue("weibo.key");
String backURL = PropertiesUtil.getValue("weibo.callback");
String get_token_url = PropertiesUtil.getValue("weibo.get_token_url");
LinkedMultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
requestEntity.add("grant_type", grant_type);
requestEntity.add("client_id", wbId);
requestEntity.add("client_secret", wbKey);
requestEntity.add("redirect_uri", backURL);
requestEntity.add("code", code);
ResponseEntity<String> postForEntity = restTemplate.postForEntity(get_token_url, requestEntity, String.class);
String body = postForEntity.getBody();
JSONObject wbTokenObject = new JSONObject(body);
logger.info("weibo."+wbTokenObject.toString());
return wbTokenObject;
}
/**
* 获取用户信息
* @param token
* @return
* @throws Exception
*/
private JSONObject getUserInfo(String token) throws Exception {
String get_userInfo_url = PropertiesUtil.getValue("weibo.get_token_info");
LinkedMultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
requestEntity.add("access_token", token);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(get_userInfo_url, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject wbUserInfoObject = new JSONObject(body);
logger.info("weibo."+wbUserInfoObject.toString());
return wbUserInfoObject;
}
}
4.百度实现
@Component("baidu")
public class BaiduLoginServiceImpl implements LoginService{
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private RestTemplate restTemplate;
@Override
public String login() {
// 回调地址
String backUrl = PropertiesUtil.getValue("baidu.callback");
// appid
String baiduId = PropertiesUtil.getValue("baidu.id");
// 随机状态
String state = UUID.randomUUID().toString().replaceAll("-", "");
String url = "https://openapi.baidu.com/oauth/2.0/authorize?client_id="+ baiduId +"&response_type=code&display=pc"
+ "&redirect_uri="+URLEncoder.encode(backUrl) + "&state="+state;
return url;
}
@Override
public String callback(String code,HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
JSONObject accessToken = getAccessToken(code);
String token = accessToken.getString("access_token");
JSONObject userInfo = getUserInfo(token);
// 获取登录ip
String ip = CusAccessObjectUtil.getIpAddress(request); // 获取登录城市
String cityName = IPDataUtils.getCityName(ip); // 获取登录用户
String username = userInfo.getString("username");
User u = new User(3,5,ip, cityName, username);
session.setAttribute("user", u);
return "重定向地址";
}
/**
* 获取token信息
* @param code
* @return
* @throws Exception
*/
private JSONObject getAccessToken(String code) throws Exception {
String grant_type = "authorization_code";
String baiduId = PropertiesUtil.getValue("baidu.id");
String baiduKey = PropertiesUtil.getValue("baidu.key");
String backURL = PropertiesUtil.getValue("baidu.callback");
String baiudu_get_token_url = PropertiesUtil.getValue("baidu.get_token_url");
String get_token_url=baiudu_get_token_url+"?" + "grant_type=authorization_code" + "&client_id="
+ baiduId + "&client_secret=" + baiduKey + "&redirect_uri=" + backURL + "&code=" + code;;
String response = restTemplate.getForObject(get_token_url,String.class);
JSONObject baiduTokenObject = new JSONObject(response);
logger.info("baidu"+baiduTokenObject.toString());
return baiduTokenObject;
}
/**
* 获取用户信息
* @param token
* @return
* @throws Exception
*/
private JSONObject getUserInfo(String token) throws Exception {
String get_userInfo_url = PropertiesUtil.getValue("baidu.get_token_info");
LinkedMultiValueMap<String, String> requestEntity = new LinkedMultiValueMap<>();
requestEntity.add("access_token", token);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(get_userInfo_url, requestEntity, String.class);
String body = responseEntity.getBody();
JSONObject baiduUserInfo = new JSONObject(body);
logger.info("baidu_userInfo"+baiduUserInfo.toString());
return baiduUserInfo;
}
}
5,登录策略:
@Component("loginServiceContext")
public class LoginServiceContext {
@Autowired
private Map<String,LoginService> loginSerivceMap = new HashMap<String,LoginService>();
/**
* 重定向地址
* @param type
* @return
* @throws Exception
*/
public String login(String type) throws Exception {
return loginSerivceMap.get(type).login();
}
/**
* 回调地址
* @param type
* @param request
* @param response
* @return
* @throws Exception
*/
public String callback(String code,String type,HttpServletRequest request) throws Exception {
return loginSerivceMap.get(type).callback(code,request);
}
}
6.LoginController.java
@RequestMapping("login")
@Controller
public class LoginController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private LoginServiceContext loginServiceContext;
@RequestMapping("login")
public String login(String type) throws Exception {
String redirectUrl = loginServiceContext.login(type);
logger.info(redirectUrl);
return "redirect:"+redirectUrl;
}
@RequestMapping("callback")
public String callback(HttpServletRequest request,HttpServletResponse response,String code,String type) throws Exception {
HttpSession session = request.getSession();
User user = (User)session.getAttribute("user");
if (null != user) {
return "redirect:你的重定向地址";
}
String callback = loginServiceContext.callback(code,type, request);
return "redirect:"+callback;
}
}
7,html代码:
<div><a href="../login/login.do?type=qq"><img src="../imags/qq.png"/></a></div>
<div><a href="../login/login.do?type=baidu"><img src="../imags/baidu.png"/></a></div>
<div><a href="../login/login.do?type=weibo"><img src="../imags/wb.png"/></a></div>