最近在做一个项目时,客户要求网站能够集成QQ登录的功能,以前没做过这方面的开发,于是去QQ的开放平台官网研究了一下相关资料,经过自己的艰苦探索,终于实现了集成QQ登录的功能,现在把相关的开发经验总结一下,希望对有这方面需求的朋友有所帮助。
一.前期准备
首先你需要登录QQ的开发平台注册一个账号,QQ互联平台官方地址:http://connect.qq.com/ 进去后注册一个开发账号,完了登录后台会有类似如下的一个后台,填好相关信息,具体可以参考下图。最后我们会有一个APP ID和APP KEY ,有了这两个东西才能实现后面的集成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>节点下加入如下配置
1
2
3
4
|
<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事件里加如下方法)
1
2
3
4
5
6
7
8
9
10
|
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号在QQ平台登录),QQ平台会通过我们上面配置的回调地址也就是我这边填的http://www.mylanqiu.com/Account/WeiboConnect/返回到这个页面,并会返回一个code给我们,我们到时会使用这个code再去QQ开发平台获取access_token,并通过这个access_token获取登录的相关用户信息。具体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/// <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登录了。下面给出辅助类的源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
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
; }
}
}
|