在 UWP 中,如果要进行 OAuth 授权,那很大概率是会用上 WebAuthenticationBroker 这个类的,例如微博授权这种。

在一般情况下来说,WebAuthenticationBroker 是足够用的了,但是,如果你是碰上 Github 授权的话,那么就会碰到这样的情况:

蹦出一大个警告,让人看上去相当不爽。归根的原因是 WebAuthenticationBroker 使用的是 IE 内核,这个我们可以通过 https://www.whatismybrowser.com/ 验证。

连 Edge 内核都不是,不给力啊,老湿。

那么有没有办法把 WebAuthenticationBroker 换成 Edge 内核呢?简单的办法是没有的了,但我们还有 WebView,WebView 是使用 Edge 内核的,可以通过 WebView 来手动实现我们自己的 WebAuthenticationBroker。

参考 WebAuthenticationBroker 类的 AuthenticateAsync,编写如下代码:

public static class MyWebAuthenticationBroker
{
public static Task<MyWebAuthenticationResult> AuthenticateAsync(Uri requestUri, Uri callbackUri)
{
throw new NotImplementedException();
}
}

WebAuthenticationBroker 的 AuthenticateAsync 这个方法有 3 个参数,但第一个参数并不是很常用,所以这里就只使用后面的两个参数了。另外因为 WebAuthenticationResult 没有公共构造函数,所以定义一个 MyWebAuthenticationResult 来代替。

public class MyWebAuthenticationResult
{
public string ResponseData { get; internal set; } public uint ResponseErrorDetail { get; internal set; } public WebAuthenticationStatus ResponseStatus { get; internal set; }
}

接下来就是如何实现的问题。这里我们可以使用一个 ContentDialog 套 WebView 的方式。

在项目添加一个内容对话框(这里我叫 AuthorizationDialog),并编写如下代码:

<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 代码:

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 之类的。

【UWP】手动实现 WebAuthenticationBroker的更多相关文章

  1. MVVM框架从WPF移植到UWP遇到的问题和解决方法

    MVVM框架从WPF移植到UWP遇到的问题和解决方法 0x00 起因 这几天开始学习UWP了,之前有WPF经验,所以总体感觉还可以,看了一些基础概念和主题,写了几个测试程序,突然想起来了前一段时间在W ...

  2. UWP开发必备:常用数据列表控件汇总比较

    今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...

  3. UWP开发之Template10实践二:拍照功能你合理使用了吗?(TempState临时目录问题)

    最近在忙Asp.Net MVC开发一直没空更新UWP这块,不过有时间的话还是需要将自己的经验和大家分享下,以求共同进步. 在上章[UWP开发之Template10实践:本地文件与照相机文件操作的MVV ...

  4. Win10 UWP开发系列——开源控件库:UWPCommunityToolkit

    在开发应用的过程中,不可避免的会使用第三方类库.之前用过一个WinRTXamlToolkit.UWP,现在微软官方发布了一个新的开源控件库—— UWPCommunityToolkit 项目代码托管在G ...

  5. 【开源】知乎日报UWP 更新

    说明 大概十天之前我更新了一次APP,后来又仔细看了一下Store里的评论,发现还有几个地方没有改过来.于是前天晚上抽时间改了一下,顺便完善了一下UI体验. 没有看前面文章的童鞋可以看一下下面的链接: ...

  6. 【完全开源】知乎日报UWP版:增加Live磁贴、Badge、以及Toast通知

    目录 说明 实现方法 APP生命期 后台任务 说明 之前网上有人建议增加磁贴(tile).徽章(badge)功能.利用周末的时间,将这两个功能添加上去了.如果将磁贴固定到开始屏幕,磁贴就会循环播放首页 ...

  7. Win10 UWP开发系列:使用VS2015 Update2+ionic开发第一个Cordova App

    安装VS2015 Update2的过程是非常曲折的.还好经过不懈的努力,终于折腾成功了. 如果开发Cordova项目的话,推荐大家用一下ionic这个框架,效果还不错.对于Cordova.PhoneG ...

  8. UWP中重用C/C++代码时踩过的一些坑

    标题中提到的UWP,主要是指用C#来写UWP的主工程,开发过程中可能需要调用C/C++实现的库. 为什么需要调用C/C++的库呢,举个例子,开源库OpenSSL实现了许多加密算法,稳定快速,我们想在应 ...

  9. Win10 UWP 开发系列:使用多语言工具包让应用支持多语言

    之前我在一篇blog中写过如何使用多语言工具包,见http://www.cnblogs.com/yanxiaodi/p/3800767.html 在WinEcos社区也发布过一篇详细的文章介绍多语言工 ...

随机推荐

  1. <记录> PHP读取命令行参数

    方法一:使用$argv or $argc参数接收 echo "接收到{$argc}个参数"; print_r($argv); [root@DELL113 lee]# /usr/lo ...

  2. 最小费用最大流 HDU1533

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1533 #include<bits/stdc++.h> #define fi first ...

  3. 原子性: Interlocked 类

    public class CounterNoLock:CountBase { private int _count; public int Count { get { return _count; } ...

  4. 商品批量删除(mybatis中集合的使用)

    <!-- 根据主键批量删除 --> <delete id="deleteByKeys"> DELETE FROM product WHERE id in & ...

  5. 记录----第一次使用BFS(广度搜索)学习经验总结

    学习经验记录与分享—— 最近在学习中接触到了一种解决最短路径的实用方法----BFS(广度搜索),在这里总结并分享一下第一次学习的经验. 首先第一个要了解的是"queue"(队列函 ...

  6. Django的rest_framework的视图之基于通用类编写视图源码解析

    我们上一篇博客讲解了如何使用mixins类实现rest_framework的视图,但是其中有很多的冗余的代码,我们这边在来优化一下 1.queryset的视图函数 首先看下对queryset操作的视图 ...

  7. 一个JAVA程序员经常访问的网站

    综合技术网站: CSDN            http://www.csdn.net/ 51CTO             http://www.51cto.com/ 开源中国社区   http:/ ...

  8. 【转】Cron表达式详解

    Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: (1) Seconds Minutes Hours DayofMonth Mo ...

  9. MySQL数据查询之单表查询

    单表查询 简单查询 - 创建表 DROP TABLE IF EXISTS `person`; CREATE TABLE `person` ( `id` ) NOT NULL AUTO_INCREMEN ...

  10. zeromq学习记录(三)使用ZMQ_PULL ZMQ_PUSH

    /************************************************************** 技术博客 http://www.cnblogs.com/itdef/   ...