当别人访问我的博客系统时,如果需要评论,就需要登录。如果此时要求注册,就比较麻烦,并且会引起访问者的反感。于是就采用第三方登录。目前支持QQ、微博登录。
QQ登录
QQ互联开放平台为第三方网站提供了丰富的API。第三方网站接入QQ互联开放平台后,即可通过调用平台提供的API实现用户使用QQ帐号登录网站功能,且可以获取到腾讯QQ用户的相关信息。
1、认证成为开发者
要使用腾讯提供的QQ登录API,就必须在QQ互联管理中心新建应用以获取应用的APPID 和 APP KEY,新建应用之前需要认证成为开发者,否则应用无法提交审核。认证成为开发者就是提供一些个人资料,比如联系方式,身份证号,身份证照片等,提交腾讯审核,审核通过即可成为开发者。
2、新建网站应用
点击上图中创建应用按钮,进行创建应用。填写应用信息,包括网站名称、类别、简介、网站地址、网站回调地址、网站备案号等。网站回调地址即用户授权QQ登录后的回调地址。新建的网站应用需通过审核才能让其他人使用QQ登录功能,如果审核未通过,只有网站所有者能使用QQ登录功能。
微博登录
微博登录的准备工作同QQ登录的准备工作,在微博开放平台上注册成为开发者,创建应用,提交审核等。
3、网站中添加QQ登录、微博登录功能
(1)网站中添加QQ、微博登录标识
<span data-platform-id="3" class="login-logo" title="QQ登录"
onclick="oRegisterBtn.loginQQ()">
<i class="layui-icon" style="font-size: 40px; color: #1E9FFF;"></i>
</span>
<span data-platform-id="3" class="login-logo" title="微博登录"
onclick="oRegisterBtn.weiboLogin()">
<i class="layui-icon" style="font-size: 40px; color: #EE2C2C;"></i>
</span>
(2)loginQQ、weiboLogin
/**
* 第三方QQ登录
*/
loginQQ: function() {
let clientId = '101528188';
let redirect_uri = 'http://22815l1b14.iask.in/thirdLogin/qqLogin';
let state = '123456789';
window.open(`https://graph.qq.com/oauth2.0/authorize?
client_id=${clientId}&response_type=code&redirect_uri=${encodeURIComponent(redirect_uri)}&state=${state}`);
},
/**
* 微博登录
*/
weiboLogin: function(){
let weiboAppId = '2191145838';
let weiboAuthPath = 'http://22815l1b14.iask.in/thirdLogin/weiboLogin';
window.open(`https://api.weibo.com/oauth2/authorize?client_id=${weiboAppId}&response_type=code&redirect_uri=${encodeURIComponent(weiboAuthPath)}`);
},
(3)QQ、微博登录成功后回调处理
QQ登录步骤如下:户成功登录并授权,则会跳转到指定的回调地址,并在回调地址后面带上code值——>通过code获取access token——>通过acess token获取openId——>通过openId获取QQ信息(昵称、头像、性别等)
微博登录步骤如下:户成功登录并授权,则会跳转到指定的回调地址,并在回调地址后面带上code值——>通过code获取access token和uid——>通过acess token和uid获取微博信息(昵称、头像、性别等)
具体步骤腾讯、微博开放平台上有详细步骤,不再赘述。详见腾讯开放平台接入文档、微博开放平台文档
/**
*
* @ClassName::ThirdPartyLoginController @Description: 第三方登录控制器
* @author :柯雷
* @date :2018年11月29日 下午1:51:45
*
*/
@Controller
@RequestMapping("/thirdLogin")
public class ThirdPartyLoginController {
/** 微博第三方登录信息 */
private static final String APP_KEY_WEIBO = "2191145838";
private static final String APP_SECRECT_WEIBO = "e8066160a6a5ab6afa7775147993465e";
private static final String REDIRECT_URI_WEIBO = "http://22815l1b14.iask.in/thirdLogin/weiboLogin";
/** QQ第三方登录信息 */
private static final String APP_KEY_QQ = "101528188";
private static final String APP_SECRECT_QQ = "7975cb8105e679e90e87d02c297dbb6a";
private static final String REDIRECT_URI_QQ = "http://22815l1b14.iask.in/thirdLogin/qqLogin";
/**
* @Description 用户处理对象
*/
@Autowired
UserService userServiceImpl;
/**
* 日志打印对象
*/
private static final Logger logger = LoggerFactory.getLogger(ThirdPartyLoginController.class);
/**
* @throws
* UnsupportedEncodingException @Title:qqLogin @Description:qq登录成功回调函数 @param
* :@return @return :String @throws
*/
@RequestMapping("/qqLogin")
@ResponseBody
public String qqLoginCallBack(HttpServletRequest request, Model model) throws UnsupportedEncodingException {
logger.info("【ThirdPartyLoginController.qqLoginCallBack】QQ登录成功回调函数");
// 返回参数
Map<String, Object> rtnMap = new HashMap<>();
// 1、用户登录成功并授权后跳转到回调地址待的参数code
String code = request.getParameter("code");
try {
Map<String, Object> params = new HashMap<>();
params.put("client_id", APP_KEY_QQ);
params.put("client_secret", APP_SECRECT_QQ);
params.put("grant_type", "authorization_code");
params.put("code", code);
params.put("redirect_uri", REDIRECT_URI_QQ);
// 2、通过code值获取access token
String auth_token = "{\"" + HttpRequestUtil.doGet("https://graph.qq.com/oauth2.0/token", params)
.replaceAll("&", "\",\"").replaceAll("=", "\":\"") + "\"}";
Map<String, Object> authMap = JSONObject.parseObject(auth_token);
Integer errorCode = (Integer) authMap.get("code");
String errorMsg = (String) authMap.get("msg");
if (errorCode != null && errorCode != 0) {
throw new Exception(errorMsg);
}
String access_token = (String) authMap.get("access_token");
// 3、根据access token获取openID
String open_id = HttpRequestUtil.doGet("https://graph.qq.com/oauth2.0/me?access_token=" + access_token);
open_id = open_id.substring(10, open_id.length() - 2);
Map<String, Object> operidMap = JSONObject.parseObject(open_id);
errorCode = (Integer) operidMap.get("code");
errorMsg = (String) operidMap.get("msg");
if (errorCode != null && errorCode != 0) {
throw new Exception(errorMsg);
}
String openid = (String) operidMap.get("openid");
// 4、根据access token和openid获取QQ信息
String user = HttpRequestUtil.doGet("https://graph.qq.com/user/get_user_info?access_token=" + access_token
+ "&oauth_consumer_key=" + APP_KEY_QQ + "&openid=" + openid);
Map<String, Object> qqUserMap = JSONObject.parseObject(user);
errorCode = (Integer) qqUserMap.get("ret");
errorMsg = (String) qqUserMap.get("msg");
if (errorCode != null && errorCode != 0) {
throw new Exception(errorMsg);
}
// 请求参数
Map<String, Object> userMap = new HashMap<>();
userMap.put("PHOTO", qqUserMap.get("figureurl_1"));
userMap.put("USERNAME", qqUserMap.get("nickname"));
userMap.put("LOGINID", openid);
userMap.put("USERTYPE", "3");
// 5、登录成功在本地用户表中保存用户信息,并将用户信息放在session中
HttpSession session = request.getSession();
session.setAttribute("user", login(userMap));
rtnMap.put("code", Constants.AJAX_FHZ_CG);
rtnMap.put("message", "登录成功");
} catch (Exception e) {
logger.info("【ThirdPartyLoginController.qqLoginCallBack】QQ登录回调失败");
rtnMap.put("code", Constants.AJAX_FHZ_SB);
rtnMap.put("message", "登录失败:" + e.getMessage());
}
String html = "<script language='javaScript' type='text/javaScript'>window.opener.oRegisterBtn.loginCallBack("
+ JSONObject.toJSONString(rtnMap) + ");window.close();</script>";
return html;
}
/**
* @Title:webLoginCallBack @Description:TODO @param : @return :void @throws
*/
@RequestMapping("/weiboLogin")
@ResponseBody
public String weiboLoginCallBack(HttpServletRequest request) {
logger.info("【ThirdPartyLoginController.webLoginCallBack】微博登录成功回调函数");
// 返回参数
Map<String, Object> rtnMap = new HashMap<>();
// 1、用户登录成功后跳转到回调地址带的参数code
String code = request.getParameter("code");
try {
// get auth_token
Map<String, Object> params = new HashMap<>();
params.put("client_id", APP_KEY_WEIBO);
params.put("client_secret", APP_SECRECT_WEIBO);
params.put("grant_type", "authorization_code");
params.put("redirect_uri", REDIRECT_URI_WEIBO);
params.put("code", code);
// 2、根据code获取access token和uid
String auth_token = HttpRequestUtil.doPost("https://api.weibo.com/oauth2/access_token", params);
Map<String, Object> resp = JSONObject.parseObject(auth_token);
Integer errorCode = (Integer) resp.get("error_code");
String errorMsg = (String) resp.get("error_description");
if (errorCode != null && errorCode != 0) {
throw new Exception(errorMsg);
}
String accessToken = (String) resp.get("access_token");
String uid = (String) resp.get("uid");
// 3、根据accessToken和uid换取用户信息
String userStr = HttpRequestUtil
.doGet("https://api.weibo.com/2/users/show.json?access_token=" + accessToken + "&uid=" + uid);
Map<String, Object> resp2 = JSONObject.parseObject(userStr);
errorCode = (Integer) resp2.get("error_code");
errorMsg = (String) resp2.get("error_description");
if (errorCode != null && errorCode != 0) {
throw new Exception(errorMsg);
}
String nickname = (String) resp2.get("screen_name");
String encode = Util.getEncoding(nickname);
// 如果字符串编码是 ISO-8859-1则转换
if ("ISO-8859-1".equals(encode)) {
nickname = new String(nickname.getBytes(encode), "utf-8");
}
// 微博180*180高清头像
String avatar = (String) resp2.get("avatar_large");
// 请求参数
Map<String, Object> userMap = new HashMap<>();
userMap.put("PHOTO", avatar);
userMap.put("USERNAME", nickname);
userMap.put("LOGINID", uid);
userMap.put("USERTYPE", "5");
// 4、登录成功在本地用户表中保存用户信息,并将用户信息放在session中
HttpSession session = request.getSession();
session.setAttribute("user", login(userMap));
rtnMap.put("code", Constants.AJAX_FHZ_CG);
rtnMap.put("message", "登录成功");
} catch (Exception e) {
logger.info("【ThirdPartyLoginController.webLoginCallBack】微博登录回调失败");
rtnMap.put("code", Constants.AJAX_FHZ_SB);
rtnMap.put("message", "登录失败:" + e.getMessage());
}
String html = "<script language='javaScript' type='text/javaScript'>window.opener.oRegisterBtn.loginCallBack("
+ JSONObject.toJSONString(rtnMap) + ");window.close();</script>";
return html;
}
/**
* @Title:login @Description:第三方登录 @param :@param params @param :@return @return
* :Map<String,Object> @throws
*/
private Map<String, Object> login(Map<String, Object> params) {
logger.info("【ThirdPartyLoginController.login】登录:" + params);
// 判断用户是否存在
Map<String, Object> user = userServiceImpl.findUserByLoginid((String) params.get("LOGINID"));
if (Util.isEmpty(user)) {
// 用户不存在,则新增
params.put("PASSWORD", ""); // 密码为空
params.put("EMAIL", "");
params.put("TELEPHONE", "");
params.put("STATE", "1");
params.put("MEMO", "");
params.put("OPERATORID", "0");
userServiceImpl.saveUser(params);
user = userServiceImpl.findUserByLoginid((String) params.get("LOGINID"));
} else {
// 用户不存在,则新增
user.put("USERNAME", params.get("USERNAME")); // 密码为空
user.put("PHOTO", params.get("PHOTO"));
userServiceImpl.saveUser(user);
}
return user;
}
}