在 UWP 中,若是要進行 OAuth 受權,那很大機率是會用上 WebAuthenticationBroker 這個類的,例如微博受權這種。web
在通常狀況下來講,WebAuthenticationBroker 是足夠用的了,可是,若是你是碰上 Github 受權的話,那麼就會碰到這樣的狀況:express
蹦出一大個警告,讓人看上去至關不爽。歸根的緣由是 WebAuthenticationBroker 使用的是 IE 內核,這個咱們能夠經過 https://www.whatismybrowser.com/ 驗證。c#
連 Edge 內核都不是,不給力啊,老溼。windows
那麼有沒有辦法把 WebAuthenticationBroker 換成 Edge 內核呢?簡單的辦法是沒有的了,但咱們還有 WebView,WebView 是使用 Edge 內核的,能夠經過 WebView 來手動實現咱們本身的 WebAuthenticationBroker。api
參考 WebAuthenticationBroker 類的 AuthenticateAsync,編寫以下代碼:async
public static class MyWebAuthenticationBroker { public static Task<MyWebAuthenticationResult> AuthenticateAsync(Uri requestUri, Uri callbackUri) { throw new NotImplementedException(); } }
WebAuthenticationBroker 的 AuthenticateAsync 這個方法有 3 個參數,但第一個參數並非很經常使用,因此這裏就只使用後面的兩個參數了。另外由於 WebAuthenticationResult 沒有公共構造函數,因此定義一個 MyWebAuthenticationResult 來代替。ide
public class MyWebAuthenticationResult { public string ResponseData { get; internal set; } public uint ResponseErrorDetail { get; internal set; } public WebAuthenticationStatus ResponseStatus { get; internal set; } }
接下來就是如何實現的問題。這裏咱們可使用一個 ContentDialog 套 WebView 的方式。函數
在項目添加一個內容對話框(這裏我叫 AuthorizationDialog),並編寫以下代碼:ui
<ContentDialog x:Class="WebAuthenticationBrokerDemo.AuthorizationDialog" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="正在鏈接到服務" CloseButtonText="取消" FullSizeDesired="True" mc:Ignorable="d"> <ContentDialog.Resources> <ResourceDictionary> <x:Double x:Key="ContentDialogMinWidth">800</x:Double> </ResourceDictionary> </ContentDialog.Resources> <Grid> <WebView x:Name="WebView" NavigationFailed="WebView_NavigationFailed" NavigationStarting="WebView_NavigationStarting" /> </Grid> </ContentDialog>
設置 FullSizeDesired 使高度佔滿窗口,資源字典中覆蓋默認的對話框寬度。WebView 則訂閱 Starting 和 Failed 事件。編寫後臺 cs 代碼:spa
public sealed partial class AuthorizationDialog { private readonly Uri _callbackUri; public AuthorizationDialog(Uri requestUri, Uri callbackUri) { if (requestUri == null) { throw new ArgumentNullException(nameof(requestUri)); } if (callbackUri == null) { throw new ArgumentNullException(nameof(callbackUri)); } _callbackUri = callbackUri; InitializeComponent(); WebView.Source = requestUri; } public Uri ResponseUri { get; private set; } public WebAuthenticationStatus Result { get; private set; } = WebAuthenticationStatus.UserCancel; public WebErrorStatus WebErrorStatus { get; private set; } private bool CheckUri(Uri uri) { if (uri.Host == _callbackUri.Host) { Result = WebAuthenticationStatus.Success; ResponseUri = uri; return true; } return false; } private void WebView_NavigationFailed(object sender, WebViewNavigationFailedEventArgs e) { if (CheckUri(e.Uri)) { Hide(); return; } Result = WebAuthenticationStatus.ErrorHttp; ResponseUri = e.Uri; WebErrorStatus = e.WebErrorStatus; Hide(); } private void WebView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) { if (CheckUri(args.Uri)) { Hide(); } } }
能夠經過 Hide 方法來關閉對話框。須要注意的是 Failed 的時候須要先檢查一次,由於可能 callback 的地址是沒法訪問的。
接下來能夠補完一開始的 AuthenticateAsync 方法了。
public static class MyWebAuthenticationBroker { public static async Task<MyWebAuthenticationResult> AuthenticateAsync(Uri requestUri, Uri callbackUri) { var authorizationDialog = new AuthorizationDialog(requestUri, callbackUri); await authorizationDialog.ShowAsync(); if (authorizationDialog.Result == WebAuthenticationStatus.UserCancel) { return new MyWebAuthenticationResult { ResponseStatus = WebAuthenticationStatus.UserCancel }; } else if (authorizationDialog.Result == WebAuthenticationStatus.Success) { return new MyWebAuthenticationResult { ResponseStatus = WebAuthenticationStatus.Success, ResponseData = authorizationDialog.ResponseUri.OriginalString }; } else { return new MyWebAuthenticationResult { ResponseStatus = WebAuthenticationStatus.ErrorHttp, ResponseData = authorizationDialog.ResponseUri.OriginalString, ResponseErrorDetail = (uint)authorizationDialog.WebErrorStatus }; } } }
那麼如今咱們再去連 Github 之類的受權就不會有警告了,由於內核已經換成了 Edge。
並且由於是使用 WebView,因此還能再進行一些定製化的操做,例如執行 JavaScript,獲取 Cookie 之類的。