2020年2月22日 星期六

[C# ASP.NET]實現OAuth2授權在Google上(二)-Refresh Token 運用篇

  由上一篇文章提到可以Refresh Token來再次獲取Access Token,不必再次經過User同意授權。
不過授權scope會和當初一樣(也就是說上一篇拿到的Refresh Token,一樣只能拿來呼叫GMail)

假設拿到的Refresh Token已經存到資料庫裡,我們這邊要取出該使用者的Refresh Token來呼叫同樣的Google API。

在畫面上放Label,Button控制項及input輸入欄位,如下圖
Button.Click 加入以下事件

//刷新Token事件
private void Btn_Refresh_Click(object sender, EventArgs e)
{
    //獲取Submit回來的GMail
    string StrGMail = HttpContext.Current.Request.Form["GMail"].ToString();

    if (StrGMail.Length == 0) return;

    string StrRefreshToken = "";

    //從資料中找出相對應的Refresh Token
    using (SqlConnection Conn = new SqlConnection(StrConn))
    {
        //開啟連線
        Conn.Open();

        string StrSQL = "Select RefreshToken From GoogleOAuth2 Where Gmail=@Gmail";
        SqlCommand cmd = new SqlCommand(StrSQL, Conn);
        cmd.Parameters.AddWithValue("@Gmail", StrGMail);

        try
        {
            StrRefreshToken = cmd.ExecuteScalar().ToString();
        }
        catch {
            //關閉連線
            Conn.Close();
            lbl_Msg.Text = "讀取資料庫失敗!";
            return;
        }

        //關閉連線
        Conn.Close();
    }

    //使用Refresh Token 得到 Access Token
    if (StrRefreshToken.Length > 0)
    {
        //錯誤訊息
        string StrErr= "";
        //Access Token
        string StrAccessToken = "";
        //使用Refresh Token 得到 Access Token
        StrErr += RefTokenChgAccToken(StrRefreshToken, ref StrAccessToken);

        //有錯誤的情況
        if (StrErr.Length > 0)
        {
            //顯示在畫面上,並且不繼續處理
            lbl_Msg.Text = StrErr;
            return;
        }

        //呼叫API用 Access token 去得到 GMail(這支函式和上一篇一樣)
        string GetGMail = "";
        StrErr += AccTokenChgGMail(StrAccessToken, ref GetGMail);

        //有錯誤的情況
        if (StrErr.Length > 0)
        {
            //顯示在畫面上,並且不繼續處理
            lbl_Msg.Text = StrErr;
            return;
        }

        lbl_Msg.Text = "由Google API上取得GMail為" + GetGMail;
    }

}

/// <summary>
/// 使用Refresh Token 得到 Access Token
/// </summary>
/// <param name="StrRefToken">Refresh Token</param>
/// <param name="StrAccToken">Access Token</param>
/// <returns>錯誤訊息</returns>

private string RefTokenChgAccToken(string StrRefToken, ref string StrAccToken)
{
    //Token網址(Google API Console 下載的Json內容中可找到)
    string StrUrl = "https://oauth2.googleapis.com/token";

    //Post參數
    StringBuilder StrParam = new StringBuilder();
    //client_id(Google API Console 中可以找到 此專案的編號)
    StrParam.Append("client_id=760...j8f.apps.googleusercontent.com&");
    //client_secret(Google API Console 中可以找到 此專案的密碼)
    StrParam.Append("client_secret=dHN...3b&");
    //refresh_token
    StrParam.Append("refresh_token=" + StrRefToken + "&");
    //grant_type
    StrParam.Append("grant_type=refresh_token&");

    //接收回傳內容 Json
    string StrReJson = "";

    using (WebClient WClient = new WebClient())
    {
        WClient.Headers.Add("content-type", "application/x-www-form-urlencoded");
        try
        {
            StrReJson = WClient.UploadString(StrUrl, "POST", StrParam.ToString());
        }
        catch
        {
            return "獲取Token失敗!";
        }
    }

    //解析JSON
    JObject Jobj = JsonConvert.DeserializeObject<JObject>(StrReJson);
    try
    {
        StrAccToken = Jobj["access_token"].ToString();
    }
    catch
    {
        return "解析回傳Token失敗!";
    }

    return "";
}


/// <summary>
/// 用 Access token 去得到 GMail
/// </summary>
/// <param name="AccToken">Access token</param>
/// <param name="GMail">GMail</param>
/// <returns>錯誤訊息</returns>

private string AccTokenChgGMail(string AccToken, ref string GMail)
{
    //API網址
    string StrUrl = "https://www.googleapis.com/oauth2/v2/userinfo";

    //接收回傳內容 Json
    string StrReJson = "";

    using (WebClient WClient = new WebClient())
    {
        WClient.Headers.Add("Authorization", "Bearer " + AccToken);
        try
        {
            StrReJson = WClient.DownloadString(StrUrl);
        }
        catch
        {
            return "獲取GMail失敗!";
        }
    }

    //解析JSON
    JObject Jobj = JsonConvert.DeserializeObject<JObject>(StrReJson);

    try
    {
        GMail = Jobj["email"].ToString();
    }
    catch
    {
        return "解析回傳GMail失敗!";
    }

    return "";



到這邊大致上已經完成了,主要是把原本由Authorize Code呼叫交換Access Token改成由Refresh Token去處理,等拿到Access Token後,就和上一篇一樣由Access Token去呼叫Google API來得到已授權過的資料。


沒有留言:

張貼留言