登陸整合實現-QQ互聯認證(ASP.NET版本)


首先 我們創建一個qq.ashx的頁面,這個頁面會跳轉到QQ的請求界面
代碼如下:
        QQSettingConfig qqSettingConfig = MySiteConfig.GetConfig<QQSettingConfig>();//配置對象 配置QQ的 app id appkey 回調地址
        public void ProcessRequest(HttpContext context)
        {
            context.Response.ContentType = "text/plain";
            string state = new Random(100000).Next(99, 99999).ToString();//隨機數
            context.Session["state"] = state;
            string callback = System.Web.HttpUtility.UrlEncode(qqSettingConfig.CallBackAddress + "/QQCallBack.aspx", Encoding.UTF8);//回調處理地址
            string url = string.Format("https://graph.qq.com/oauth2.0/authorize?client_id={0}&response_type=code&redirect_uri={1}&state={2}", qqSettingConfig.APPID, callback, state);//互聯地址
            context.Response.Redirect(url);
        }

 

代碼比較簡單,就是進行一個跳轉的操作,其中qqSettingConfig是讀取配置文件 里面定義了appid 和appkey 這個需要先到騰訊互聯的網站申請
state 是一個隨機數,這個隨機數我這里寫入到session中,騰訊請求后會返回來一個callback的頁面 這個頁面也是我們自己填寫的 ,在c騰訊在返回來請求我們的地址的時候會將這個state傳回來 然后外面和我們的session的state進行對比 防止中途被黑客攔截了
 
我這里的回調處理地址就是qqSettingConfig.CallBackAddress + "/QQCallBack.aspx 前面的配置 你可以寫死也可以讀取配置文件 就是你申請的時候的回調地址
 
然后外面看我們的回調地址
 
回調地址,首先我們也需要配置文件
QQSettingConfig qqSettingConfig = MySiteConfig.GetConfig<QQSettingConfig>();//配置對象 配置QQ的 app id appkey 回調地址

 

然后在pageload事件里面
 
       
protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                try
                {
                    string code = HttpContext.Current.QueryString["code"];
                    string state = HttpContext.Current.QueryString["state"];
                    ValidCodeState(code, state);
                    QQOauthInfo qqOauthInfo = GetOauthInfo(code);
                    string openID = GetOpenID(qqOauthInfo);
                    string nickName = GetUserInfo(qqOauthInfo, openID);
                    if (string.IsNullOrEmpty(nickName))
                    {
                        WriteErrMsg("獲取不到昵稱");
                    }
 
                    #region 開始進行注冊或者登錄
                    OauthUserModel oauthUserModel = BLL.OauthUserBll.GetInfoByOpenId("qq", openID);
                    if (!oauthUserModel.IsNull)
                    {
                        //已經綁定過則登錄
                        DealLogin(oauthUserModel);
                    }
                    else
                    {
                        //進行綁定
                        this.TxtRegUserName.Text = nickName;
                        this.hidenNiName.Value = nickName;
                        this.hidenOpenID.Value = openID;
                        this.LabelNiName.Text = nickName;
                        this.LabelOpenID.Text = openID;
                    }
                    #endregion
                }
                catch (Exception ex)
                {
                    //ShowError("出錯了:"+ ex.Message);
                }
 
            }
        }

 

 
騰訊在跳轉到我們指定的回調地址的時候 會傳回來code 和state 我們首先來驗證這兩個是否合法
       
/// <summary>
        /// 驗證code和state
        /// </summary>
        /// <param name="code"></param>
        /// <param name="state"></param>
        private void ValidCodeState(string code, string state)
        {
            if (string.IsNullOrEmpty(code) || string.IsNullOrEmpty(state))
            {
                ShowError("CODE或者STATE為空");
            }
            if (Session["state"] == null || Session["state"].ToString() != state)
            {
                ShowError("STATE不正確");
            }
        }  

 

1 主要就是驗證非空 state和session里面的state進行驗證 防止被中途攔截了
然后外面在調用另外的地址 獲取token
QQOauthInfo qqOauthInfo = GetOauthInfo(code); 
方法如下
 /// <summary>
        /// 獲取oauth信息
        /// </summary>
        /// <param name="code"></param>
        /// <returns></returns>
        private QQOauthInfo GetOauthInfo(string code)
        {
            string callback = System.Web.HttpUtility.UrlEncode(qqSettingConfig.CallBackAddress + "/QQCallBack.aspx", 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", qqSettingConfig.APPID, qqSettingConfig.APPKEY, code, callback);
            string res = LoadHtmlUserGetType(url, Encoding.UTF8);
            if (!res.Contains("access_token="))
            {
                ShowError("出錯了:空access_token");
            }
            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];
            if (string.IsNullOrEmpty(qqOauthInfo.AccessToken) || string.IsNullOrEmpty(qqOauthInfo.ExpiresIn) || string.IsNullOrEmpty(qqOauthInfo.RefreshToken))
            {
                ShowError("獲取access_token等信息為空");
            }
            return qqOauthInfo;
        }
        /// <summary>
        /// 截取字符串中兩個字符串中的字符串
        /// </summary>
        /// <param name="str">字符串</param>
        /// <param name="startStr">開始字符串</param>
        /// <param name="endStr">結束字符串</param>
        /// <returns></returns>
        public 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;  
        } 
 
返回來 我封裝了一個實體對象 
   
public class QQOauthInfo
    {
        public string AccessToken { get; set; }
        public string ExpiresIn { get; set; }
        public string RefreshToken { get; set; }
    } 

 

代碼沒什么 就是獲取返回來的token 和有效期expresein等
 
2 這里我用了本方法 就是截取字符串,其實他是一個json對象的, 同學們可以使用json解析工具,對他進行解析
 
獲得了這三個之后 我們再來獲得openid
string openID = GetOpenID(qqOauthInfo); 
方法如下
        /// <summary>
        /// 獲取QQ賬號的OpenID
        /// </summary>
        /// <param name="qqOauthInfo"></param>
        /// <returns></returns>
        private string GetOpenID(QQOauthInfo qqOauthInfo)
        {
            string res = LoadHtmlUserGetType("https://graph.qq.com/oauth2.0/me?access_token=" + qqOauthInfo.AccessToken, Encoding.UTF8);
            if (!res.Contains("openid"))
            {
                WriteErrMsg("出錯了:獲取用戶的openid出錯");
            }
            return CutString(res, @"openid"":""", @"""}");
        } 

 

 

很簡單 就是繼續請求一個地址 然后再截取出openid
 
有了openid后,我們繼續獲取用戶名
string nickName = GetUserInfo(qqOauthInfo, openID); 
 
方法如下
        /// <summary>
        /// 獲取QQ昵稱
        /// </summary>
        /// <param name="qqOauthInfo"></param>
        /// <param name="openID"></param>
        /// <returns></returns>
        private 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, qqSettingConfig.APPID, openID);
            string resUserInfo = LoadHtmlUserGetType(urlGetInfo, Encoding.UTF8);
            if (!resUserInfo.Contains("\"msg\": \"\""))
            {
                WriteErrMsg("出錯了:獲取用戶信息出錯");
            }
            return CutString(resUserInfo, @"""nickname"": """, @""",");
        } 

 

 

 
也是一樣 請求一個地址 然后截取出nickname
 
有了這個nickname后 我們就可以 進行下一步操作了
if (string.IsNullOrEmpty(nickName))
                    {
                        ShowError("獲取不到昵稱");
                    }
                    #region 開始進行注冊或者登錄
                    OauthUserModel oauthUserModel = BLL.OauthUserBll.GetInfoByOpenId("qq", openID);
                    if (!oauthUserModel.IsNull)
                    {
                        //已經綁定過則登錄
                        DealLogin(oauthUserModel);
                    }
                    else
                    {
                        //進行綁定
                        this.TxtRegUserName.Text = nickName;
                        this.hidenNiName.Value = nickName;
                        this.hidenOpenID.Value = openID;
                        this.LabelNiName.Text = nickName;
                        this.LabelOpenID.Text = openID;
                    }
                    #endregion 

 

 
比如 我們先檢查我們的數據庫 改賬號是否已經綁定過了,注意 我們要保存openid 來判斷 因為openid是唯一標記這個QQ賬號的 用戶名是不能標記的
BLL.OauthUserBll.GetInfoByOpenId("qq", openID);
 
為了統一一張表,方便以后擴展其他的登錄整合 這里加了個“qq”的標志字段
 
這張表的sql語句如下:
if exists(
   select 1 from sys.systable 
   where table_name='PE_C_OauthUser'
     and table_type in ('BASE', 'GBL TEMP')
) then
    drop table PE_C_OauthUser
end if;
 
/*==============================================================*/
/* Table: PE_C_OauthUser                                        */
/*==============================================================*/
create table PE_C_OauthUser 
(
   ID                   int                            not null,
   NiName               nvarchar(50)                   null,
   UserName             nvarchar(50)                   null,
   Type                 nvarchar(50)                   null,
   AddTime              datetime                       null,
   Status               int                            null,
   OpenID               nvarchar(150)                  null,
   UserID               int                            null,
   constraint PK_PE_C_OAUTHUSER primary key clustered (ID)
);
 
comment on table PE_C_OauthUser is 
'用戶和QQ或者微信等其他的Oauth關聯';
 
comment on column PE_C_OauthUser.ID is 
'主鍵ID';
 
comment on column PE_C_OauthUser.NiName is 
'昵稱從QQ或者微信取得的昵稱';
 
comment on column PE_C_OauthUser.UserName is 
'我方系統用戶名';
 
comment on column PE_C_OauthUser.Type is 
'類型:如QQ WEIXIN';
 
comment on column PE_C_OauthUser.AddTime is 
'添加時間';
 
comment on column PE_C_OauthUser.Status is 
'狀態';
 
comment on column PE_C_OauthUser.OpenID is 
'是QQ則openid  微信則';
 
comment on column PE_C_OauthUser.UserID is 
'我方系統用戶ID';
 
if exists(
   select 1 from sys.systable 
   where table_name='PE_C_OauthUser'
     and table_type in ('BASE', 'GBL TEMP')
) then
    drop table PE_C_OauthUser
end if;
 
/*==============================================================*/
/* Table: PE_C_OauthUser                                        */
/*==============================================================*/
create table PE_C_OauthUser 
(
   ID                   int                            not null,
   NiName               nvarchar(50)                   null,
   UserName             nvarchar(50)                   null,
   Type                 nvarchar(50)                   null,
   AddTime              datetime                       null,
   Status               int                            null,
   OpenID               nvarchar(150)                  null,
   UserID               int                            null,
   constraint PK_PE_C_OAUTHUSER primary key clustered (ID)
);
 
comment on table PE_C_OauthUser is 
'用戶和QQ或者微信等其他的Oauth關聯';
 
comment on column PE_C_OauthUser.ID is 
'主鍵ID';
 
comment on column PE_C_OauthUser.NiName is 
'昵稱從QQ或者微信取得的昵稱';
 
comment on column PE_C_OauthUser.UserName is 
'我方系統用戶名';
 
comment on column PE_C_OauthUser.Type is 
'類型:如QQ WEIXIN';
 
comment on column PE_C_OauthUser.AddTime is 
'添加時間';
 
comment on column PE_C_OauthUser.Status is 
'狀態';
 
comment on column PE_C_OauthUser.OpenID is 
'是QQ則openid  微信則';
 
comment on column PE_C_OauthUser.UserID is 
'我方系統用戶ID';

如果發現已經綁定了 則直接登錄就可以了
if (!oauthUserModel.IsNull)
                    {
                        //已經綁定過則登錄
                        DealLogin(oauthUserModel);
                    }

 


 
登錄的方法 根據你自己系他來實現
 
否則的話 就將這些nickname 等信息 寫到textbox hidden等控件中 讓用戶來進行操作
 
 //進行綁定
                        this.TxtRegUserName.Text = nickName;
                        this.hidenNiName.Value = nickName;
                        this.hidenOpenID.Value = openID;
                        this.LabelNiName.Text = nickName;

                        this.LabelOpenID.Text = openID;

 

 
用戶可以選擇兩種方式 進行
一種是注冊新的賬號,然后綁定 ,另外一種是綁定已經注冊的賬號

 
這兩種方式 都需要輸入密碼 第一種要輸入兩次 需要實現 同時注冊 同時添加到綁定表 就是上面的表 另外一種就是直接插入綁定表就可以了
這里面的代碼 就不貼出來了,用戶根據自己的辦法來實現
綁定新賬號 的方式 就是先注冊一個 然后插入綁定表 然后登錄
 
綁定已有賬號的方式 就先判斷密碼是否正確 正確就插入綁定表 然后登錄
 
//添加到綁定表
            OauthUserModel oauthUserModelNew = new OauthUserModel();
            oauthUserModelNew.AddTime = DateTime.Now;
            oauthUserModelNew.NiName = this.hidenNiName.Value;
            oauthUserModelNew.OpenID = this.hidenOpenID.Value;
            oauthUserModelNew.Status = 1;
            oauthUserModelNew.Type = "qq";
            oauthUserModelNew.UserID = usersInfo.UserId;
            oauthUserModelNew.UserName = usersInfo.UserName;
            if (!BLL.OauthUserBll.Add(oauthUserModelNew))
            {
                ShowError("綁定失敗");
            }  

 

 感謝閱讀,希望對你有幫助,更多資料 可以加群討論的....
 
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM