[程式碼範例分享] 使用Google OAuth API取得使用者資料(2023) | C#與ASP.NET
這篇只單純分享程式碼範例
所以不會有GCP設定教學
此篇適用於任何C#專案
例如ASP.NET WebForm, MVC, WebAPI等等
中間有使用到BCrypt.NET、Newtonsoft.Json
所以要先安裝Nuget套件
public class GoogleOAuth
{
private const string GoogleAuthUrl = "https://accounts.google.com/o/oauth2/v2/auth";
private const string GoogleTokenUrl = "https://oauth2.googleapis.com/token";
private const string GoogleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
private string _clientId; //Client ID
private string _clientSecret; //Client Secret
private string _redirectUrl; //選擇Google帳號後要導回的網址,通常是用來處理登入資料
private string _stateSecret; //State的Secret,防止CSRF
private string[] _scopes;
public GoogleOAuth(string clientId, string clientSecret, string redirectUrl, string stateSecret)
{
this._clientId = clientId;
this._clientSecret = clientSecret;
this._redirectUrl = redirectUrl;
this._stateSecret = stateSecret;
this._scopes = new string[]
{
"https://www.googleapis.com/auth/userinfo.profile",
"https://www.googleapis.com/auth/userinfo.email"
};
}
/// <summary>
/// 取得使用者驗證請求URL
/// </summary>
public string GetAuthUrl()
{
NameValueCollection colle = HttpUtility.ParseQueryString("");
colle.Add("client_id", this._clientId);
colle.Add("response_type", "code");
colle.Add("redirect_uri", this._redirectUrl);
colle.Add("state", this.GenerateHashState());
colle.Add("scope", string.Join(' ', this._scopes));
return $"{GoogleAuthUrl}?{colle.ToString()}";
}
/// <summary>
/// 從使用者驗證的帳號Code取得存取Token
/// </summary>
public TokenData GetAccessToken(string authCode)
{
NameValueCollection colle = HttpUtility.ParseQueryString("");
colle.Add("code", authCode);
colle.Add("client_id", this._clientId);
colle.Add("client_secret", this._clientSecret);
colle.Add("grant_type", "authorization_code");
colle.Add("redirect_uri", this._redirectUrl);
string json = HttpRequest(
GoogleTokenUrl,
"POST",
out bool isSuccess,
colle.ToString(),
null
);
return isSuccess ? JsonConvert.DeserializeObject<TokenData>(json) : null;
}
/// <summary>
/// 取得使用者資訊
/// </summary>
public UserInfo GetUserInfo(TokenData data)
{
string json = HttpRequest(
GoogleUserInfoUrl,
"GET",
out bool isSuccess,
null,
data.AccessToken
);
return isSuccess ? JsonConvert.DeserializeObject<UserInfo>(json) : null;
}
/// <summary>
/// State驗證
/// </summary>
public bool StateVerify(string stateHash)
{
return Crypt.BCrypt.Verify(this._stateSecret, stateHash);
}
private string GenerateHashState()
{
return Crypt.BCrypt.HashPassword(this._stateSecret);
}
private string HttpRequest(
string url,
string method,
out bool isSuccess,
string body = null,
string bearer = null
)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.Method = method;
req.ContentType = "application/x-www-form-urlencoded";
if (bearer != null)
{
req.Headers.Add("Authorization", $"Bearer {bearer}");
}
if (body != null)
{
using (Stream stream = req.GetRequestStream())
{
byte[] bytes = Encoding.UTF8.GetBytes(body);
stream.Write(bytes, 0, bytes.Length);
}
}
string content = "";
try
{
WebResponse res = req.GetResponse();
using (Stream stream = res.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream))
{
content = reader.ReadToEnd();
}
}
isSuccess = true;
}
catch (WebException ex)
{
WebResponse res = ex.Response;
using (Stream stream = res.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream))
{
//to do something...
}
}
isSuccess = false;
}
return content;
}
public class TokenData
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("expires_in")]
public int ExpiresIn { get; set; }
[JsonProperty("scope")]
public string Scope { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("id_token")]
public string IdToken { get; set; }
}
public class UserInfo
{
[JsonProperty("sub")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
}
}
使用範例
GoogleOAuth google = new GoogleOAuth("id", "secret", "redirect", "state");
//取得要驗證登入的Google網址,直接向前端重定向(Redirect)即可
google.GetAuthUrl();
//驗證State是否正確
bool isSuccess = google.StateVerify(state);
//使用Code交換AccessToken
GoogleOAuth.TokenData token = google.GetAccessToken(code);
//使用AccessToken交換使用者資料
GoogleOAuth.UserInfo userInfo = google.GetUserInfo(token);
//登入驗證關卡 & 資料庫存取...
留言