Facebook登入-手動建立登入 OAuth 2
開放授權(OAuth)是一個開放標準,很多大公司提供的第三方驗證,不外乎都是這樣的流程,應該也是目前最廣泛被採用的第三方應用存取授權機制標準,Facebook當然也不例外有手動建立登入流程 。
這邊就不介紹OAuth,如果有興趣,我在參考的部分,放置了一篇微軟官方的介紹,另外也有不少Blog具有相當詳細的介紹,之後看有沒有機會也來寫一篇OAuth…(實現率不高,不喜歡太多文字的說明,且別人寫得非常完整了…)
實作
-
取得叫用「登入」對話方塊與設定重新導向網址
1
2
3
4
5
6
7
|
public IActionResult Index()
{
// 叫用「登入」對話方塊與設定重新導向網址
State = Guid.NewGuid();
ViewData["FacebookAuth"] = $"https://www.facebook.com/v8.0/dialog/oauth?client_id={_appId}&redirect_uri={RedirectUrl}&state={State}";
return View();
}
|
-
然後前台簡單建立一個連結按鈕
1
|
<a href="@ViewData["FacebookAuth"]" class="btn btn-primary" title="Log in your account">Facebook</a>
|
-
點了之後一樣會出現登入介面(記得Facebook要先登出,才會顯示登入畫面)
-
使用者輸入完後,會導回我們剛剛設定的回傳網址
這邊重點在於取得code
(預設) 或 token
,要取得哪項可以設置response_type
,須注意這兩者取得權杖的方式不同,code
是用使用代碼交換存取權杖,token
則是要驗證,我直接使用預設
-
傳送使用代碼交換存取權杖
重點就在於這個權杖,有了權杖後,我們就可以使用Facebook Graph API,取得用戶資料,能取得哪些用戶資料,與版本有關,所以建議API加上版本號,我這邊只取最基本的ID、Name、Email
-
使用Facebook Graph API取得用戶資料,資料部分參考有連結
接下來就是一般的登入流程,看是否寫進資料庫、判斷是否第一次登入等
完整程式碼
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
|
public class LoginController : Controller
{
// 這邊要改你申請的應用程式編號及密鑰
private readonly string _appId = "{應用程式編號}";
private readonly string _appSecret = "{應用程式密鑰}";
private readonly IHttpClientFactory _clientFactory;
public LoginController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
private string RedirectUrl => "https://" + HttpContext.Request.Host.ToString() + "/Login/SignInFacebook";
[TempData]
public Guid State { get; set; }
public IActionResult Index()
{
// 叫用「登入」對話方塊與設定重新導向網址
State = Guid.NewGuid();
ViewData["FacebookAuth"] = $"https://www.facebook.com/v8.0/dialog/oauth?client_id={_appId}&redirect_uri={RedirectUrl}&state={State}";
return View();
}
public async Task<IActionResult> SignInFacebook(string code, Guid state, string error, string error_description)
{
// 有錯誤訊息(未授權等)、State遺失、State不相同、沒有code...
if (!string.IsNullOrEmpty(error) || state == null || State != state || string.IsNullOrEmpty(code))
return RedirectToAction(nameof(Index));
// 使用代碼交換存取權杖
var url = $"https://graph.facebook.com/v8.0/oauth/access_token?" +
$"client_id={_appId}" +
$"&redirect_uri={RedirectUrl}" +
$"&client_secret={_appSecret}" +
$"&code={code}";
var client = _clientFactory.CreateClient();
var response = await client.GetAsync(url);
string responseContent;
if (response.IsSuccessStatusCode)
responseContent = await response.Content.ReadAsStringAsync();
else
return RedirectToAction(nameof(Index));
var facebookLoginResource = JsonConvert.DeserializeObject<FacebookLoginResource>(responseContent);
// 若需要取得用戶資料,則使用Facebook Graph API,並設置想取得的欄位,欄位請參考 用戶資料
url = $"https://graph.facebook.com/v8.0/me?fields=id,name,email" +
$"&access_token={facebookLoginResource.AccessToken}";
response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
responseContent = await response.Content.ReadAsStringAsync();
var user = JsonConvert.DeserializeObject<FacebookUser>(responseContent);
}
// 略..
return View();
}
}
public class FacebookLoginResource
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public string ExpiresIn { get; set; }
}
public class FacebookUser
{
[JsonProperty("id")]
public string Id { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("email")]
public string Email { get; set; }
}
|
參考
Facebook 手動建立登入範例
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/
Facebook Graph Api
https://developers.facebook.com/docs/graph-api/using-graph-api/
Facebook 可取得用戶資料
https://developers.facebook.com/docs/graph-api/reference/user
Microsoft OAuth 2.0 授權碼流程
https://docs.microsoft.com/zh-tw/azure/active-directory/develop/v2-oauth2-auth-code-flow
結論
單看OAuth流程圖可能會覺得這個很複雜,但實際上流程多數都是相同的,程式碼也不複雜。
使用手動建立登入的程式碼比較多,但可控部分也相對增加了,OAuth程式碼是通用的,可以將這套流程封裝成介面,如果還有其他登入方式,是採用OAuth驗證標準,只要實作介面,這樣即使沒有官方沒有提供插件,也沒關係,可以優雅的統一作法。