OAuth2 + Custom Scheme跳轉回Windows App

最近要把 Cognito User Pool 提供的 OAuth 登入功能串接到 Windows App,一路上遇到不少問題,透過這篇文章做紀錄

範例程式碼點這裡


實驗紀錄

為什麼不用 AWS SDK 的 initiateAuth() 做登入功能?

雖然確實可以拿到 access token、id token,但無法自訂其中的 scope,所以讓這種 token 無法靈活運用。

OAuthDesktopApp 這份範例的問題在哪?

因為 Cognito 需要開發人員先註冊 Redirect URI(最高 100 組),
而這份程式碼是動態決定 port,並產生 Redirect URI (比如 http://localhost:1234/) ,
可想而知開發的過程會很痛苦。

為什麼不用 OAuth2 Implicit Flow 做登入功能?

接續上一篇回答

即使把 port 寫死,
登入成功後,瀏覽器會收到這樣的 HTTP request:

http://localhost:1234/#id_token=ID_TOKEN&access_token=ACCESS_TOKEN&token_type=bearer&expires_in=3600

接著瀏覽器會把 request 傳給 HttpListener,再把 request 存在 context 變數裡面
而你會發現你怎麼都無法拿到 token,
因為瀏覽器根本不會把 # 後面的東西傳給 HttpListener!!

為什麼使用 Custom Scheme 做跳轉是必要的?

不這麼做,勢必就要採用 localhost + port 的方案。

如果固定 port,則 port 被占用之後會無法處理跳轉;
如果是動態 port,則要想辦法註冊新的 Redirect URI 到 Cognito,這太瘋狂惹。
即使能把 port 控制 100 個數字之內,這樣的做法也不是最佳解。

如何為 Windows App 註冊 Custom Scheme?

參考 Registering an Application to a URI Scheme using .NET (custom protocol)

為什麼必須判斷是否為 first process?

因為瀏覽器根據 custom scheme 啟動 app的時候,會再啟動一次 app,造成第二個 process。
而真正收到 redirect 請求的其實是第二個 process。

因此 app 每次啟動都要判斷是自己不是 first process,
若否,就要把自己收到的 args 傳回去給 first process,這樣才能完成跳轉。

App 如何判斷自己為 first process?

以這份 gist 來說,他是透過 mutex 機制,能取得 mutex 的 process 必定為 first

Second process 如何傳送資料給 first process?

透過 Named pipe。
first process 會啟動 ServerStream,而 second process 會透過 ClientStream 傳送資料。

如何在跳轉後讓 MainWindow 跳出來?

以下程式擷取自這篇解答

///

Brings main window to foreground.

public void BringToForeground()
{
if (this.WindowState == WindowState.Minimized || this.Visibility == Visibility.Hidden)
{
this.Show();
this.WindowState = WindowState.Normal;
}

// According to some sources these steps gurantee that an app will be brought to foreground.
this.Activate();
this.Topmost = true;
this.Topmost = false;
this.Focus();
}

Simon Mourier這篇回答優點在哪、缺點在哪?

優點:

  • OAuthState、OAuthRequest、OAuthToken 封裝得非常漂亮
  • 透過 OAuthState,藉由登入與否改變 MainWindow 的畫面(如同 Vue.js)

缺點:

  • 使用 built-in web browser,一開啟 Cognito Hosted UI 就會發生一堆 JS error
  • 仍然使用 HttpListener + 動態 port 產生 Redirect URI

如何做到登出?

程式方面直接把 Token 設為 null 即可。

不過用來登入的瀏覽器因為會有 cookie,所以瀏覽器上也要登出,或者一開始就用無痕模式登入。
用無痕模式開啟登入畫面的程式如下:

// 在 edge 瀏覽器打開 Cognito 登入畫面
// (inPrivate 參數可以避免瀏覽器 cookie 記住前一位登入的工讀生帳號)
var authorizationRequestUri = “”;
System.Diagnostics.Process.Start(new ProcessStartInfo()
{
FileName = “msedge.exe”,
Arguments = string.Format(“–inPrivate –new-window –no-first-run \”{0}\””, authorizationRequestUri),
UseShellExecute = true
});

接著如果是使用 Authorization Code Flow,則也需要註銷 refresh token,access token,
具體的方式請參考 REVOCATION endpoint

Add a Comment

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *