1、HTML页面
<div class="formRow other">
<p>第三方登录</p>
<ul class="clear">
<li>
<a href="${path}/login/qqLogin"><img src="${resources}/images/login/qq.png"></a>
</li>
<li>
<a href=""><img src="${resources}/images/login/wb.png"></a>
</li>
<li>
<a href="${path}/login/wxLogin"><img src="${resources}/images/login/wx.png"></a>
</li>
</ul>
</div>
2、调转到登录方法,会根据Oauth2.0协议规范调,调用getAuthorizeURL方法return返回authorizeURL,并带上相应参数
/**
* QQ用户第三方登录页面
* @throws IOException
*/
@RequestMapping(value="/qqLogin",method = RequestMethod.GET)
public void qqLogin(Model model,HttpServletRequest request, HttpServletResponse response) throws IOException {
try {
response.sendRedirect(new Oauth().getAuthorizeURL(request));
} catch (QQConnectException e) {
e.printStackTrace();
}
}
3、QQ第三方登录中SDK源代码,返回authorizeURL
public String getAuthorizeURL(ServletRequest request)throws QQConnectException
{
String state = RandomStatusGenerator.getUniqueState();
((HttpServletRequest)request).getSession().setAttribute("qq_connect_state", state);
String scope = QQConnectConfig.getValue("scope");
if ((scope != null) && (!scope.equals(""))) {
return getAuthorizeURL("code", state, scope);
}
return QQConnectConfig.getValue("authorizeURL").trim() + "?client_id=" + QQConnectConfig.getValue("app_ID").trim() + "&redirect_uri=" + QQConnectConfig.getValue("redirect_URI").trim() + "&response_type=" + "code" + "&state=" + state;
}
4、根据返回的返回authorizeURL,跳到指定的回调地址,
如果之前用第三方QQ成功登录过,根据该登录QQ的信息找到与之绑定的会员信息,存到session中,并返回index首页,
如果之前没有用第三方QQ登录过,则进入绑定页面bindfirst
/**
* QQ第三方登录之后,获取qq相关信息之后的跳转
*/
@RequestMapping(value="/qqLoginAfter",method=RequestMethod.GET)
public String qqLoginAfter(Model model,Member member,ThirdMember thirdMember,HttpServletRequest request, HttpServletResponse response) throws Exception {
try {
AccessToken accessTokenObj = (new Oauth()).getAccessTokenByRequest(request);
String accessToken = null,
openID = null;
long tokenExpireIn = 0L;
if (accessTokenObj.getAccessToken().equals("")) {
// 我们的网站被CSRF攻击了或者用户取消了授权,做一些数据统计工作
System.out.print("没有获取到响应参数");
} else {
accessToken = accessTokenObj.getAccessToken();
tokenExpireIn = accessTokenObj.getExpireIn();
request.getSession().setAttribute("demo_access_token", accessToken);
request.getSession().setAttribute("demo_token_expirein", String.valueOf(tokenExpireIn));
// 利用获取到的accessToken 去获取当前用的openid -------- start
OpenID openIDObj = new OpenID(accessToken);
openID = openIDObj.getUserOpenID();
request.getSession().setAttribute("demo_openid", openID);
// 利用获取到的accessToken 去获取当前用户的openid --------- end
UserInfo qzoneUserInfo = new UserInfo(accessToken, openID);
UserInfoBean userInfoBean = qzoneUserInfo.getUserInfo();
/**
* 1、通过openID和状态判断是否有对应的第三方登录会员的这条记录
* 2、如果存在该条记录,进入网站首页。
* 3、如果不存在,进获取获取用户信息,先进入绑定账号页面,可已绑定以前注册过的,也可以当前进行注册,然后再绑定。
* 绑定成功之后,member表里面插入一条数据,third_member第三方登录表里面也插入一天数据,并且关联member_id
*/
Boolean hasthirdmember = thirdMemberService.findByOpenIdAndStatus(openID,StatusEnum.NORMAL.getValue());
if(hasthirdmember){
thirdMember = thirdMemberService.findThirdMemberByOpenIdAndStatus(openID,StatusEnum.NORMAL.getValue());
member = memberService.get(thirdMember.getMember().getId());
request.getSession().setAttribute("loginMember", member);
return "redirect:/index";
}else{
request.getSession().setAttribute("openID", openID);
request.getSession().setAttribute("userInfoBean", userInfoBean);
String headurl = userInfoBean.getAvatar().getAvatarURL100(); //头像 100*100
model.addAttribute("headurl", headurl);
return "bindfirst";
}
}
} catch (QQConnectException e) {
logger.error("很抱歉,我们没能正确获取到您的信息", e);
}
return "redirect:/index";
}
5、已经有热点账号,点击绑定,调用绑定的方法
<div class="sub">
<p>已经有热点账号?立即去<a href="${path}/index/qqLoginAfterBDSPage">绑定账号</a></p>
</div>
6、进入绑定页面
/**
* QQ第三方登录之后的跳转进入绑定页面 --有账号,绑定操作---页面
*/
@RequestMapping(value="/qqLoginAfterBDSPage",method=RequestMethod.GET)
public String qqLoginAfterBDSPage() throws Exception {
return "bindsecond";
}
//---------------QQ绑定已有账号----------------
function bind(){
$.ajax({
type:"post",
url:"${path}/index/qqLoginAfterBDSecond",
data:$("#bind-form").serialize(),
success:function(data){
if(data.code==200){
common.alert({content:data.msg});
window.location.href="${path}/index";
}else{
common.alert({content:data.msg});
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
common.alert({content:'网络异常'});
}
})
}
8、绑定方法,绑定成功之后,保存第三方登录QQ的信息
/**
* QQ第三方登录之后的跳转进入绑定页面 --有账号,绑定操作
*/
@RequestMapping(value="/qqLoginAfterBDSecond",method=RequestMethod.POST)
@ResponseBody
public ResultObject qqLoginAfterBDSecond(Model model,String username,String password,ThirdMember thirdMember,HttpServletRequest request, HttpServletResponse response) throws Exception {
Member member =null;
if(CommonUtil.isPhone(username)){
member = memberService.findMemberByPhone(username);
if (member == null) {
return new ResultObject("500", "该账号不存在", "");
}
}else if(CommonUtil.isEmail(username)){
member = memberService.findMemberByEmail(username);
if (member == null) {
return new ResultObject("500", "该账号不存在", "");
}
}else{
member = memberService.findMemberByUsername(username);
if(member == null){
return new ResultObject("500", "该账号不存在", null);
}
}
//判断账户 密码
boolean flagUsername =( member != null );
if (!flagUsername) {
return new ResultObject("500", "用户名不存在", "");
}
boolean flagPassword =(member.getPassword().equals(MD5.toMD5(password)) );
if (!flagPassword) {
return new ResultObject("500", "密码错误", "");
}
//判断账户状态
if(member.getStatus()!=StatusEnum.NORMAL.getValue()){
return new ResultObject("300", "会员已经被停用", "");
}
String openID = (String) request.getSession().getAttribute("openID");
UserInfoBean userInfoBean = (UserInfoBean) request.getSession().getAttribute("userInfoBean");
String nickname = userInfoBean.getNickname(); //昵称
String headurl = userInfoBean.getAvatar().getAvatarURL100(); //头像 100*100
String sex = userInfoBean.getGender(); //性别
/*-------------得到openID 昵称,姓名,性别,头像,类型,保存到第三方登录的数据库表中----------------*/
int sexNum =0 ;
if(sex.equals("男")){
sexNum = 1;
}else if(sex.equals("女")){
sexNum = 2;
}else{
sexNum = 0;
}
thirdMember.setThirdType(1);
thirdMember.setOpenId(openID);
thirdMember.setMember(member);
thirdMember.setName(nickname);
thirdMember.setSex(sexNum);
thirdMember.setHeadUrl(headurl);
thirdMember.setStatus(StatusEnum.NORMAL.getValue());
thirdMember.setCreateTime(new Date());
thirdMemberService.save(thirdMember);
request.getSession().setAttribute("loginMember", member);
return new ResultObject("200", "绑定成功", "");
}
9、如果没有热点账号,就直接注册,注册完成提交之后的同时进行绑定
/* ---------------- 注册 ---------------- */
function register(){
if($('#reg_form').valid()){
$.ajax({
type:"post",
url:"${path}/reg/qqLoginAfterbindReg",
data:$("#bind_first").serialize(),
success:function(data){
if(data.code==200){
window.location.href="${path}/index";
}else{
common.alert({content:data.msg});
}
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
common.alert({content:'网络异常'});
}
})
}
}
10、注册并且绑定的方法,成功之后,保存会员注册相关信息,并保存第三方登录QQ的信息,同时把该会员存到session中,并返回index首页,
/**
* QQ第三方登录之后的跳转进入绑定页面--没有账号,注册绑定操作
*/
@RequestMapping(value="/qqLoginAfterbindReg",method=RequestMethod.POST)
@ResponseBody
public ResultObject qqLoginAfterbindReg(Member member,@ModelAttribute("memberInfo") MemberInfo memberInfo,ThirdMember thirdMember,
String random,RedirectAttributes redirectAttributes,HttpServletRequest request){
try {
/** -------- redis获取验证码 -------- **/
String randomInRedis = redisService.get("redis_login_"+member.getPhone());
if(randomInRedis != null && !randomInRedis.equals(random)){
return new ResultObject("500", "短信验证码错误", null);
}
/** -------- 获取QQ用户相关信息 -------- **/
String openID = (String) request.getSession().getAttribute("openID");
UserInfoBean userInfoBean = (UserInfoBean) request.getSession().getAttribute("userInfoBean");
String nickname = userInfoBean.getNickname(); //昵称
String headurl = userInfoBean.getAvatar().getAvatarURL100(); //头像 100*100
String sex = userInfoBean.getGender(); //性别
/*-------------得到openID 昵称,姓名,性别,头像,类型,保存到第三方登录的数据库表中----------------*/
int sexNum =0 ;
if(sex.equals("男")){
sexNum = 1;
}else if(sex.equals("女")){
sexNum = 2;
}else{
sexNum = 0;
}
thirdMember.setThirdType(1);
thirdMember.setOpenId(openID);
thirdMember.setMember(member);
thirdMember.setName(nickname);
thirdMember.setSex(sexNum);
thirdMember.setHeadUrl(headurl);
thirdMember.setStatus(StatusEnum.NORMAL.getValue());
thirdMember.setCreateTime(new Date());
/** -------- 把获取的QQ用户的头像,性别,昵称保存到会员相关的表中-------- **/
member.setHeadUrl(headurl);
memberInfo.setSex(sexNum);
/** -------- 会员注册-------- **/
ResultObject rs = memberService.register(member,memberInfo);
/** -------- 第三方登录表中保存数据-------- **/
thirdMemberService.save(thirdMember);
//登录
request.getSession().setAttribute("loginMember", member);
//记录地理位置
recordService.saveMemberLocationRecord(member,request);
return rs;
} catch (Exception e) {
logger.error("注册出错", e);
return new ResultObject("500", "注册出错", null);
}
}
附加:
1、需要引入QQ第三方登录的jar包
<!-- QQ登录-->
<dependency>
<groupId>net.gplatform</groupId>
<artifactId>Sdk4J</artifactId>
<version>2.0</version>
</dependency>
2、需要引入QQ第三方登录SDK文档中的配置文件,里面包含app_ID、app_KEY、redirect_URI、scope等相关信息
QQ互联API列表
QQ互联SDK下载
使用说明:1.直接引入Sdk4J.jar 包至项目工程内。
2.修改qqconnectconfig.properties 文件,在指定修改的地方填写自己app的相关信息和要获取的scope权限(前4行信息)注意不要试图修改api的请求地址,
这里之所以暴露出来是为了方便兼容以后的变动。
3.将qqconnectconfig.properties文件放到自己的项目的context ClassLoader的可以加载的目录下,一般放在项目的src目录即可。
4.查看demo程序,结合api doc文档,进行接口的调用。