拾人牙慧篇之———QQ微信的第三方登录实现
一、写在前面
关于qq微信登录的原理之流我就不一一赘述了,对应的官网都有,在这里主要是展示我是怎么实现出来的,看了好几个博客,有的是直接复制官网的,有的不知道为什么实现不了。我只能保证我的这个是我实现后才贴出来的,本文有看不懂的地方请结合官网看。(话说我感觉我写博客废话好多)
二、准备工作
通过以下官网获得相应AppID和AppSecret以及对应的回调地址。
QQ登录官网:https://connect.qq.com
微信登录官网:https://open.weixin.qq.com
三、登录实现第三方
3.1、QQ授权登录实现
这里的实现主要用JS_SDK来实现,通过这种实现回调地址基本没有什么用,区别于这种实现方式:如何在自己的网站上实现QQ授权登录?。步骤就不一一说了,直接上代码(红色部分为qq授权相关的,里面的appid和回调地址改成自己申请时候的既可)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%String path = request.getContextPath() ;%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta charset="UTF-8"> <title>登录页</title> <link href="<%=path%>/resource/css/public.css" rel="stylesheet" type="text/css" /> <link href="<%=path%>/resource/css/index.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="<%=path%>/resource/js/tools/jquery-1.8.2.min.js"></script> <script type="text/javascript" src="<%=path%>/resource/js/tools/base.js"></script> <script type="text/javascript" src="http://qzonestyle.gtimg.cn/qzone/openapi/qc_loader.js" data-appid="1013XXXXX" data-redirecturi="http://www.xxxxxx.com/qqlogincheck.jsp" charset="utf-8"> </script> <script type="text/javascript"> var PATH ='<%=path%>'; var FROM='${from}'; jQuery(function(){ loginEnterCheck(); }); function getOs(){ var OsObject = ""; if (navigator.userAgent.indexOf("MSIE") > 0) { return "MSIE"; } if (isFirefox = navigator.userAgent.indexOf("Firefox") > 0) { return "Firefox"; } if (isSafari = navigator.userAgent.indexOf("Safari") > 0) { return "Safari"; } if (isCamino = navigator.userAgent.indexOf("Camino") > 0) { return "Camino"; } if (isMozilla = navigator.userAgent.indexOf("Gecko/") > 0) { return "Gecko"; } } //回车键登陆,支持火狐和IE浏览器; function loginEnterCheck(){ //获取当前浏览器; var browser = getOs(); if(browser=="Firefox"){ //判断IE还是火狐浏览器; $("html").die().live("keydown",function(event){ if(event.keyCode==13){ //调用登陆方法; $(".J_login_btn").click(); } }); }else if(browser=="" || browser=="MSIE"){ document.onkeydown=function(){ if(event.keyCode==13||event.which==13){ $(".J_login_btn").click(); } } }else{ if(event.keyCode==13||event.which==13){ $(".J_login_btn").click(); } } } function getInfo() { if(QC.Login.check()){ QC.api("get_user_info") .success(function(s){//成功回调 QC.Login.getMe(function(openId, accessToken){ var _data={loginName:s.data.nickname,openId:openId,otype:1,token:accessToken}; //console.log(_data); $.ajax({ url:PATH+"/security/qqlogin.do", type:"POST", data:_data, dataType:'json', success:function(result) { if(result.code==200){ //登录成功 window.location.href=PATH+'/'; }else{ if(result.code==101){ $("#openId").val(result.openId); console.info(result); $("#loginName_qw").val(result.loginName); var fm=document.getElementById("qqcheckForm"); // fm.action=""; fm.submit(); } } } }); }) }) .error(function(f){//失败回调 alert("获取用户信息失败!登录失败!"); location.href = "/security/toLoginPage.do"; }) .complete(function(c){//完成请求回调 //alert("获取用户信息完成!"); }); }else{ alert("请先登录qq!"); location.href = "/security/toLoginPage.do"; } } function qqlogin(){ QC.Login({}, function (reqData, opts) {//登录成功 getInfo(); }, function (opts) { alert('注销成功'); } ); QC.Login.showPopup({ appId:"10139XXXX", redirectURI:"http://www.xxxxxx.com/qqlogincheck.jsp" }); } </script> <script type="text/javascript" src="<%=path%>/resource/js/login.js"></script> </head> <body onkeydown="loginEnterCheck();"> <form method="post" action="<%=path%>/security/toQwRegisterPage.do" id="qqcheckForm"> <input type="hidden" id="openId" name="openId"> <input type="hidden" id="loginName_qw" name="loginName_qw"> </form> <div class="m_header"> <div class='m_header_logo fix m_setWidth'> <a href='http://www.xxxxxx.com' class='m_logo'> <img src='<%=path%>/resource/images/logo.png' /> </a> <span class='welcome_title'>欢迎登录</span> </div> </div> <div class="m_login_wrapper"> <div class='m_login m_setWidth fix'> <div class='m_login_from'> <div class='m_login_box'> <p class='m_login_title'>西玛会员</p> <div class='m_login_input fix'> <i class='m_login_user'></i> <input name="loginName" type='text' placeholder='用户名' class='m_input J_user'/> </div> <div class='m_login_input fix'> <i class='m_login_lock'></i> <input name="password" type='password' placeholder='密码' class='m_input J_password'/> </div> <div class='m_login_handle fix'> <span class='m_square_box c_switch checked'><span class='m_square'></span><i class='m_square_text'>自动登录</i></span> <a href='<%=path%>/security/findPassword.do' class='m_forget_password'>忘记密码</a> </div> <button class='c_btn c_btn_green J_login_btn'>登录</button> <div class='m_login_handle fix'> <a >其他登录方式></a> </div> <div class='m_header_title_left '> <a style="margin-right: 10px;" onclick="qqlogin()" > <img src='<%=path%>/resource/images/login/btn_qzone.png' alt="QQ授权登录 " > </a> <a style="margin-right: 10px;" href="http://open.weixin.qq.com/connect/qrconnect?appid=wx1fbfXXXXXX&redirect_uri=http%3A%2F%2Fwww.xxxxxx.com%2Fsecurity%2FgetWebchatCode.do&response_type=code&scope=snsapi_login&state=3d6be0a4035d839573b04816624a415e#wechat_redirect"> <img src='<%=path%>/resource/images/login/btn_weixin.png' alt="微信授权登录 "> </a> </div> <div class='m_to_register'> <a href='<%=path%>/security/toRegisterPage.do'>免费注册></a> </div> </div> </div> </div> </div> <jsp:include page="../public/buttom.jsp" flush="true" /> </body> </html>
这里用到的是 QC.Login.showPopup,期间遇到了showPopup 这种不能回调的情况,参考了:QC.Login.showPopup可有回调? 。
qq授权后台处理思路:通过点击qq登录,登录成功后回调,在回调中通过 QC.api("get_user_info")获取登录后的信息,在后台通过qq的openid来查询数据库,若是库中有值,则直接进入登录成功流程,若是没有值则跳转到手机号注册流程。(回调地址里面基本为空)
3.2、微信授权登录实现
上面代码的蓝色部分即为微信登录的连接,相应地方改成申请的既可.
这里有三个地方需要注意:
1、地址需要改成转义后的,%3A%2F%2F就等于://这样的形式。
2、若是前面微信开放平台的是https,对应的回调也是https。
3、这里写的回调地址是http://www.xxxxxx.com/security/getWebchatCode.do,但是微信申请里写http://www.xxxxxx.com既可。
下面看看微信登录成功后的后台处理代码
/** * 微信登录获取code */ @RequestMapping(value = "/getWebchatCode.do") public ModelAndView getWebchatCode(HttpServletRequest request, HttpServletResponse response) { String code = request.getParameter("code"); System.out.println("微信登录获取code=="+code); String url="https://api.weixin.qq.com/sns/oauth2/access_token?appid="+appid+"&secret=XXX&code="+code+"&grant_type=authorization_code"; Map<String, Object> map = new HashMap<String, Object>(); map.put("from", code); try { JSONObject jb = HttpUtils.httpRequest(url,"GET",null); System.out.println("通过code获取token=="+jb.toString()); String access_token= jb.getString("access_token"); JSONObject userinfo = HttpUtils.httpRequest("https://api.weixin.qq.com/sns/userinfo?access_token="+access_token+"&openid="+appid+"","GET",null); System.out.println("通过token获取=="+userinfo.toString()); String loginName= userinfo.getString("nickname"); String openId=userinfo.getString("openid"); Member member = memberService.selectOneByWeixinOpenId(openId); if (member != null ) {//通过qq唯一openID判断该qq是否之前用过,同时判断loginName是否唯一 member.setLastLoginTime(new Date()); memberService.update(member); // 设置线程变量 CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_USER_ID, member.getId()); CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_MEMBER, member); CurrentThreadContext.setValue(CurrentThreadContext.CURRENT_MANAGE_SHOP_ID, member.getManageShopId()); // 单点登录Cookie Cookie cookie_sso = new Cookie(CurrentThreadContext.COOKIES_LOGIN_KEY, AESUtil.encrypt(loginName, PropertiesUtil.getInstance().getValue("security.cipher.key"))); cookie_sso.setMaxAge(-1); cookie_sso.setDomain(PropertiesUtil.getInstance().getValue("security.root.domain")); cookie_sso.setPath("/"); response.addCookie(cookie_sso); // 用户Cookie loginName = DESUtil.strEnc(loginName, PropertiesUtil.getInstance().getValue("security.cipher.key"), "", ""); String shopFlage = ""; if (member.getManageShopId() != null) { Shop t = new Shop(); t.setId(member.getManageShopId()); Shop shop = shopApiService.selectOne(t); if (shop != null && shop.getStatus() != null && shop.getStatus().equals(ShopConstant.SHOP_STATUS_3)) { shopFlage = member.getManageShopId().toString(); } } Cookie cookie_memberinfo = new Cookie(CurrentThreadContext.COOKIES_MEMBERINFO, loginName + "|" + shopFlage + "|" + member.getId()); cookie_memberinfo.setMaxAge(-1); cookie_memberinfo.setDomain(PropertiesUtil.getInstance().getValue("security.root.domain")); cookie_memberinfo.setPath("/"); response.addCookie(cookie_memberinfo); map.put("code", "200"); map.put("msg", "登录成功"); return new ModelAndView("redirect:/",map); } else { //qq授权的不存在,跳转到输入手机验证码的地方 map.put("code", "101"); Member membertemp = memberService.selectOneByLoginName(loginName); if(membertemp!=null){ map.put("loginName", loginName+"_xima"+new Random().nextInt(1000)); }else{ map.put("loginName", loginName); } map.put("wqType", "weixin"); map.put("openId", openId); /* map.put("msg", "用户名或密码不正确");*/ return new ModelAndView("security/qwRegister",map); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return new ModelAndView("security/login",map); }
主要是几次握手过程。
四、总结
qq微信的第三方登录按照官方文档一步一步实习还是比较容易的,有什么问题可以交流交流。
以上用到的连接若是对该作者造成影响的,可以联系删掉。