最近在做一个项目时,客户要求网站能够集成QQ登录的功能,以前没做过这方面的开发,于是去QQ的开放平台官网研究了一下相关资料,经过自己的艰苦探索,终于实现了集成QQ登录的功能,现在把相关的开发经验总结一下,希望对有这方面需求的朋友有所帮助。

一.前期准备

首先你需要登录QQ的开发平台注册一个账号,QQ互联平台官方地址:​​http://connect.qq.com/​​ 进去后注册一个开发账号,完了登录后台会有类似如下的一个后台,填好相关信息,具体可以参考下图。最后我们会有一个APP ID和APP KEY ,有了这两个东西才能实现后面的集成QQ登录功能。

网站集成QQ登录功能(转)_开发平台


二.开发工作

当我们的账号审核后,QQ开发平台会给我们一个APP ID和APP KEY,有了这两个,我们就可以进行开发的工作了。
QQ的登录采用的是OAuth2.0协议,OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容。具体的内容可以参考QQ的API文档http://wiki.connect.qq.com/oauth2-0%e7%ae%80%e4%bb%8b
QQ的开发平台已经有PHP,JAVA,JS等版本的SDK了,如果是要用到这些语言进行开发的可以直接参考这些SDK,我这边直接讲一下ASP.NET版本(MVC)的开发。

第一步.先在WebConfig中的 <appSettings>节点下加入如下配置

​​<add key=​​​​"QQAppID"​​​ ​​value=​​​​"QQ平台给的APP ID"​​​ ​​/>​​
​​<add key=​​​​"QQAppKey"​​​ ​​value=​​​​"QQ开发平台给的APP KEY"​​​​/>​​
​​<add key=​​​​"QQCallBack"​​​ ​​value=​​​​"http://www.mylanqiu.com/Account/QQConnect/"​​​​/>​​
​​<add key=​​​​"QQAuthorizeURL"​​​ ​​value=​​​​"https://graph.qq.com/oauth2.0/authorize"​​​ ​​/>​​

第二步.在Controllers中加一个登陆的Action(我这边用的是MVC的开发方式,如果是传统.NET的可以直接在.aspx的Page_Load事件里加如下方法)

​​public​​​ ​​ActionResult LoginQQ()​​
​​{​​
​​string​​​ ​​state = ​​​​new​​​ ​​Random(100000).Next(99, 99999).ToString();​​​​//随机数​​
​​Session[​​​​"QQState"​​​​] = state;​​
​​string​​​ ​​appID = ConfigurationManager.AppSettings[​​​​"QQAppID"​​​​];​​
​​string​​​ ​​qqAuthorizeURL = ConfigurationManager.AppSettings[​​​​"QQAuthorizeURL"​​​​];​​
​​string​​​ ​​callback = ConfigurationManager.AppSettings[​​​​"QQCallBack"​​​​];​​
​​string​​​ ​​authenticationUrl = ​​​​string​​​​.Format(​​​​"{0}?client_id={1}&response_type=code&redirect_uri={2}&state={3}"​​​​, qqAuthorizeURL, appID, callback, state);​​​​//互联地址​​
​​return​​​ ​​new​​​ ​​RedirectResult(authenticationUrl);​​
​​}​​

这一步主要是实现去QQ平台进行身份验证,直观点也就是点击后会去出现如下截图的画面

网站集成QQ登录功能(转)_System_02


第三步.在点击了上图的同意登录后(也就是已经使用QQ号在QQ平台登录),QQ平台会通过我们上面配置的回调地址也就是我这边填的​​http://www.mylanqiu.com/Account/WeiboConnect/​​返回到这个页面,并会返回一个code给我们,我们到时会使用这个code再去QQ开发平台获取access_token,并通过这个access_token获取登录的相关用户信息。具体代码如下:

​​/// <summary>​​
​​/// QQ回调页面​​
​​/// </summary>​​
​​public​​​ ​​ActionResult QQConnect()​​
​​{​​
​​if​​​ ​​(!​​​​string​​​​.IsNullOrEmpty(Request.Params[​​​​"code"​​​​]) && !​​​​string​​​​.IsNullOrEmpty(Request.Params[​​​​"state"​​​​]))​​
​​{​​
​​var​​​ ​​code = Request.Params[​​​​"code"​​​​];​​
​​var​​​ ​​state = Request.Params[​​​​"state"​​​​];​​
​​string​​​ ​​requestState = Session[​​​​"QQState"​​​​] == ​​​​null​​​ ​​? ​​​​""​​​ ​​: Session[​​​​"QQState"​​​​].ToString();​​
​​if​​​ ​​(state == requestState)​​
​​{​​
​​try​​
​​{​​
​​QQOAuthHelper QAuthHelper = ​​​​new​​​ ​​QQOAuthHelper();​​​​//这是一个辅助类,代码会在下面给出​​
​​QQOauthInfo qqOauthInfo = QAuthHelper.GetOauthInfo(code);​​
​​string​​​ ​​openID = QAuthHelper.GetOpenID(qqOauthInfo);​​​​//获取用的OpenID,这个ID是QQ给我们的用户的唯一ID,可以作为我们系统用户唯一性的判断存在我们自己的库中​​
​​Session[​​​​"QQOpenID"​​​​] = openID;​​
​​string​​​ ​​nickName = QAuthHelper.GetUserInfo(qqOauthInfo, openID);​​​​//获取用户的昵称​​
​​UserAccount userAccount = AccountBLL.GetUserAccountByOpenID(OAuthPlatform.QQ.ToString(), openID);​​
​​if​​​ ​​(userAccount != ​​​​null​​​​)​​​​//判断是否是已用该OpenID是否已在我们的库中,若已存在则允许登录​​
​​{​​
​​SetAuthCookie(userAccount);​​
​​Response.Write(​​​​"<script> window.opener.location.reload();window.close();</script>"​​​​);​​
​​}​​
​​ViewData[​​​​"NickName"​​​​] = nickName;​​
​​}​​
​​catch​​​ ​​(Exception ex)​​
​​{​​

​​return​​​ ​​new​​​ ​​RedirectResult(​​​​"~/Error/Error.htm"​​​​);​​
​​}​​
​​}​​
​​else​​
​​{​​
​​return​​​ ​​new​​​ ​​RedirectResult(​​​​"~/Error/Error.htm"​​​​);​​
​​}​​
​​}​​
​​else​​
​​{​​
​​return​​​ ​​new​​​ ​​RedirectResult(​​​​"~/Error/Error.htm"​​​​);​​
​​}​​
​​return​​​ ​​View();​​
​​}​​

通过上面的步骤就可以实现网站集成QQ登录了。下面给出辅助类的源代码:

​​using​​​ ​​System;​​
​​using​​​ ​​System.Text;​​
​​using​​​ ​​System.Configuration;​​
​​using​​​ ​​System.Collections.Generic;​​
​​using​​​ ​​System.Linq;​​
​​using​​​ ​​System.Net;​​
​​using​​​ ​​System.Web;​​
​​using​​​ ​​System.IO;​​
​​namespace​​​ ​​Com.ABC.Mylanqiu.BLL​​
​​{​​
​​public​​​ ​​class​​​ ​​QQOAuthHelper​​
​​{​​
​​string​​​ ​​appID = ConfigurationManager.AppSettings[​​​​"QQAppID"​​​​];​​
​​string​​​ ​​appKey = ConfigurationManager.AppSettings[​​​​"QQAppKey"​​​​];​​
​​/// <summary>​​
​​/// 获取oauth信息​​
​​/// </summary>​​
​​/// <param name="code"></param>​​
​​/// <returns></returns>​​
​​public​​​ ​​QQOauthInfo GetOauthInfo(​​​​string​​​ ​​code)​​
​​{​​
​​string​​​ ​​callback = System.Web.HttpUtility.UrlEncode(ConfigurationManager.AppSettings[​​​​"QQCallBack"​​​​], Encoding.UTF8);​​
​​string​​​ ​​url = ​​​​string​​​​.Format(​​​​"https://graph.qq.com/oauth2.0/token?grant_type={0}&client_id={1}&client_secret={2}&code={3}&redirect_uri={4}"​​​​, ​​​​"authorization_code"​​​​, appID, appKey, code, callback);​​
​​string​​​ ​​res = LoadHtmlUserGetType(url, Encoding.UTF8);​​
​​QQOauthInfo qqOauthInfo = ​​​​new​​​ ​​QQOauthInfo();​​
​​qqOauthInfo.AccessToken = CutString(res, ​​​​"access_token="​​​​, ​​​​"&expires_in="​​​​);​​
​​qqOauthInfo.ExpiresIn = CutString(res, ​​​​"&expires_in="​​​​, ​​​​"&refresh_token="​​​​);​​
​​qqOauthInfo.RefreshToken = res.Split(​​​​new​​​ ​​string​​​​[] { ​​​​"&refresh_token="​​​ ​​}, StringSplitOptions.None)[1];​​
​​return​​​ ​​qqOauthInfo;​​
​​}​​
​​/// <summary>​​
​​/// 截取字符串中两个字符串中的字符串​​
​​/// </summary>​​
​​/// <param name="str">字符串</param>​​
​​/// <param name="startStr">开始字符串</param>​​
​​/// <param name="endStr">结束字符串</param>​​
​​/// <returns></returns>​​
​​private​​​ ​​string​​​ ​​CutString(​​​​string​​​ ​​str, ​​​​string​​​ ​​startStr, ​​​​string​​​ ​​endStr)​​
​​{​​
​​int​​​ ​​begin, end;​​
​​begin = str.IndexOf(startStr, 0) + startStr.Length; ​​​​//开始位置​​
​​end = str.IndexOf(endStr, begin); ​​​​//结束位置​​
​​return​​​ ​​str.Substring(begin, end - begin); ​​​​//取搜索的条数,用结束的位置-开始的位置,并返回​​
​​}​​
​​/// <summary>​​
​​/// 通过GET方式获取页面的方法​​
​​/// </summary>​​
​​/// <param name="urlString">请求的URL</param>​​
​​/// <param name="encoding">页面编码</param>​​
​​/// <returns></returns>​​
​​public​​​ ​​string​​​ ​​LoadHtmlUserGetType(​​​​string​​​ ​​urlString, Encoding encoding)​​
​​{​​

​​HttpWebRequest httpWebRequest = ​​​​null​​​​;​​
​​HttpWebResponse httpWebRespones = ​​​​null​​​​;​​
​​Stream stream = ​​​​null​​​​;​​
​​string​​​ ​​htmlString = ​​​​string​​​​.Empty;​​
​​try​​
​​{​​
​​httpWebRequest = WebRequest.Create(urlString) ​​​​as​​​ ​​HttpWebRequest;​​
​​}​​
​​catch​​​ ​​(Exception ex)​​
​​{​​
​​throw​​​ ​​new​​​ ​​Exception(​​​​"建立页面请求时发生错误!"​​​​, ex);​​
​​}​​
​​httpWebRequest.UserAgent = ​​​​"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; Maxthon 2.0)"​​​​;​​
​​try​​
​​{​​
​​httpWebRespones = (HttpWebResponse)httpWebRequest.GetResponse();​​
​​stream = httpWebRespones.GetResponseStream();​​
​​}​​
​​catch​​​ ​​(Exception ex)​​
​​{​​
​​throw​​​ ​​new​​​ ​​Exception(​​​​"接受服务器返回页面时发生错误!"​​​​, ex);​​
​​}​​
​​StreamReader streamReader = ​​​​new​​​ ​​StreamReader(stream, encoding);​​
​​try​​
​​{​​
​​htmlString = streamReader.ReadToEnd();​​
​​}​​
​​catch​​​ ​​(Exception ex)​​
​​{​​
​​throw​​​ ​​new​​​ ​​Exception(​​​​"读取页面数据时发生错误!"​​​​, ex);​​
​​}​​
​​streamReader.Close();​​
​​stream.Close();​​
​​return​​​ ​​htmlString;​​
​​}​​
​​/// <summary>​​
​​/// 获取QQ账号的OpenID​​
​​/// </summary>​​
​​/// <param name="qqOauthInfo"></param>​​
​​/// <returns></returns>​​
​​public​​​ ​​string​​​ ​​GetOpenID(QQOauthInfo qqOauthInfo)​​
​​{​​
​​string​​​ ​​res = LoadHtmlUserGetType(​​​​"https://graph.qq.com/oauth2.0/me?access_token="​​​ ​​+ qqOauthInfo.AccessToken, Encoding.UTF8);​​
​​return​​​ ​​CutString(res, ​​​​@"openid"":"""​​​​, ​​​​@"""}"​​​​);​​
​​}​​
​​/// <summary>​​
​​/// 获取QQ昵称​​
​​/// </summary>​​
​​/// <param name="qqOauthInfo"></param>​​
​​/// <param name="openID"></param>​​
​​/// <returns></returns>​​
​​public​​​ ​​string​​​ ​​GetUserInfo(QQOauthInfo qqOauthInfo, ​​​​string​​​ ​​openID)​​
​​{​​

​​string​​​ ​​urlGetInfo = ​​​​string​​​​.Format(​​​​@"https://graph.qq.com/user/get_user_info?access_token={0}&oauth_consumer_key={1}&openid={2}"​​​​, qqOauthInfo.AccessToken,appID, openID);​​
​​string​​​ ​​resUserInfo = LoadHtmlUserGetType(urlGetInfo, Encoding.UTF8);​​
​​return​​​ ​​CutString(resUserInfo, ​​​​@"""nickname"": """​​​​, ​​​​@""","​​​​);​​
​​}​​
​​}​​
​​public​​​ ​​class​​​ ​​QQOauthInfo​​
​​{​​
​​public​​​ ​​string​​​ ​​AccessToken { ​​​​get​​​​; ​​​​set​​​​; }​​
​​public​​​ ​​string​​​ ​​ExpiresIn { ​​​​get​​​​; ​​​​set​​​​; }​​
​​public​​​ ​​string​​​ ​​RefreshToken { ​​​​get​​​​; ​​​​set​​​​; }​​
​​}​​
​​}​​

四.Demo效果

大家可以直接访问看一下实际的效果,最后感谢大家的阅读,如对你有所帮助就多多转发,以帮助更多人,正所谓:赠人玫瑰 手有余香!如有不足,还请指正!