401 授权错误 Windows Phone 8 通知
Posted
技术标签:
【中文标题】401 授权错误 Windows Phone 8 通知【英文标题】:401 Authorisation Error Windows Phone 8 Notifications 【发布时间】:2014-07-30 13:09:22 【问题描述】:我正在尝试使用经过身份验证的服务器向我的 Windows Phone 8 应用发送通知,但每当尝试发送通知时我都会收到 401 错误。
我一直按照 MSDN 页面上的说明进行操作,即 http://msdn.microsoft.com/library/windows/apps/ff941099(v=vs.105).aspx 上面写着 The Key-Usage value of the TLS certificate must be set to include client authentication.
我不知道这是什么意思,但在线搜索也没有给我任何线索。
这可能是不正确的,也可能是我的代码,如下所示。
VB.NET 代码:
Private Async Sub ApplicationBarPin_Click(sender As Object, e As EventArgs)
' Holds the push channel that is created or found.
Dim pushChannel As HttpNotificationChannel
' The name of our push channel.
Dim channelName As String = "WindowsPhoneTrainTileNotification"
' Try to find the push channel.
pushChannel = HttpNotificationChannel.Find(channelName)
' If the channel was not found, then create a new connection to the push service.
If pushChannel Is Nothing Then
pushChannel = New HttpNotificationChannel(channelName, "redsquirrelsoftware.co.uk")
uri_timer = New DispatcherTimer
uri_timer.Interval = TimeSpan.FromSeconds(5)
AddHandler uri_timer.Tick, AddressOf UriTimerTick
uri_timer.Start()
' Register for all the events before attempting to open the channel.
AddHandler pushChannel.ChannelUriUpdated, AddressOf PushChannel_TileChannelUriUpdated
AddHandler pushChannel.ErrorOccurred, AddressOf PushChannel_TileErrorOccurred
pushChannel.Open()
pushChannel.BindToShellTile()
Else
' The channel was already open, so just register for all the events.
AddHandler pushChannel.ChannelUriUpdated, AddressOf PushChannel_TileChannelUriUpdated
AddHandler pushChannel.ErrorOccurred, AddressOf PushChannel_TileErrorOccurred
Dim form As New MultipartFormDataContent()
form.Add(New StringContent(Statics.getUserID), "userId")
form.Add(New StringContent(pushChannel.ChannelUri.ToString()), "uri")
form.Add(New StringContent(Statics.CurrentScheduleId), "scheduleId")
Dim httpClient As HttpClient = New HttpClient()
Dim response As HttpResponseMessage = Await httpClient.PostAsync("http://redsquirrelsoftware.co.uk/trains/push/WPTileSubscribe.php", form)
End If
ShellTile.Create(New Uri("/Route.xaml?scheduleId=" & scheduleId, UriKind.Relative), secondaryTile, True) 'Create SecondaryTile and pass querystring to navigation url.
Catch ex As Exception
End Try
End If
End Sub
Private Async Sub PushChannel_TileChannelUriUpdated(sender As Object, e As NotificationChannelUriEventArgs)
Dim form As New MultipartFormDataContent()
form.Add(New StringContent(Statics.getUserID), "userId")
form.Add(New StringContent(e.ChannelUri.ToString()), "uri")
form.Add(New StringContent(Statics.CurrentScheduleId), "scheduleId")
Dim httpClient As HttpClient = New HttpClient()
Dim response As HttpResponseMessage = Await httpClient.PostAsync("http://redsquirrelsoftware.co.uk/trains/push/WPTileSubscribe.php", form)
End Sub
Private Sub PushChannel_TileErrorOccurred(sender As Object, e As NotificationChannelErrorEventArgs)
MessageBox.Show("Error creating live tile, please try again")
End Sub
Private Async Sub UriTimerTick(sender As Object, e As EventArgs)
Try
If pushChannel.ChannelUri IsNot Nothing Then
Dim form As New MultipartFormDataContent()
form.Add(New StringContent(Statics.getUserID), "userId")
form.Add(New StringContent(pushChannel.ChannelUri.ToString()), "uri")
form.Add(New StringContent(Statics.CurrentScheduleId), "scheduleId")
Dim httpClient As HttpClient = New HttpClient()
Dim response As HttpResponseMessage = Await httpClient.PostAsync("http://redsquirrelsoftware.co.uk/trains/push/WPTileSubscribe.php", form)
uri_timer.Stop()
End If
Catch ex As Exception
End Try
End Sub
按预期工作,并且 URI 存储在我的数据库中(以 HTTPS 开头,并且 URI 中也不包含throttledthirdparty,表明此代码有效)。
train_movements.php:
<?php
include 'WindowsPhoneTilePush.php';
$WPN = new WPN($packageSID, $clientSecret);
$xml_data = $WPN->build_tile_xml($sched_id, strtoupper($loc), "$eventTypeStr $dt (". strtolower($variation_status) . ")");
$WPNResponse = $WPN->post_tile($uri, $xml_data);
if($WPNResponse->error == true)
$my_file = $logFile;
$handle = fopen($my_file, 'a') or die('Cannot open file: '.$my_file);
$data = $WPNResponse->httpCode . ":" . $WPNResponse->message . "\n";
fwrite($handle, $data);
?>
WindowsPhoneTilePush.php:(改编自here)
<?php
class WPNTypesEnum
const Toast = 'wns/toast';
const Badge = 'wns/badge';
const Tile = 'wns/tile';
const Raw = 'wns/raw';
class WPNResponse
public $message = '';
public $error = false;
public $httpCode = '';
function __construct($message, $httpCode, $error = false)
$this->message = $message;
$this->httpCode = $httpCode;
$this->error = $error;
class WPN
private $access_token = '';
private $sid = '';
private $secret = '';
function __construct($sid, $secret)
$this->sid = $sid;
$this->secret = $secret;
private function get_access_token()
if($this->access_token != '')
return;
$str = "grant_type=client_credentials&client_id=$this->sid&client_secret=$this->secret&scope=notify.windows.com";
$url = "https://login.live.com/accesstoken.srf";
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_POSTFIELDS, "$str");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
$output = json_decode($output);
if(isset($output->error))
throw new Exception($output->error_description);
$this->access_token = $output->access_token;
public function build_tile_xml($tile_nav_uri, $wide2, $wide3)
$msg = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" .
"<wp:Notification xmlns:wp=\"WPNotification\" Version=\"2.0\">" .
"<wp:Tile Id=\"/Route.xaml?scheduleId=$tile_nav_uri\" Template=\"IconicTile\">" .
//"<wp:SmallIconImage>$image_url_small</wp:SmallIconImage>" .
//"<wp:IconImage>$image_url_large</wp:IconImage>" .
//"<wp:WideContent1>$wide1</wp:WideContent1>" .
"<wp:WideContent2>$wide2</wp:WideContent2>" .
"<wp:WideContent3>$wide3</wp:WideContent3>" .
//"<wp:Count>$count</wp:Count>" .
//"<wp:Title>$title</wp:Title>" .
//"<wp:BackgroundColor>#00FFFFFF</wp:BackgroundColor>" .
"</wp:Tile>" .
"</wp:Notification>";
return $msg;
public function post_tile($uri, $xml_data, $type = WPNTypesEnum::Tile, $tileTag = '', $count = 0)
if($this->access_token == '')
$this->get_access_token();
$headers = array('Content-Type: text/xml', "Content-Length: " . strlen($xml_data), "X-WNS-Type: $type", "Authorization: Bearer $this->access_token");
if($tileTag != '')
array_push($headers, "X-WNS-Tag: $tileTag");
$ch = curl_init($uri);
# Tiles: http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh868263.aspx
# http://msdn.microsoft.com/en-us/library/windows/apps/hh465435.aspx
curl_setopt($ch, CURLOPT_CAPATH, "/var/www/clients/client1/web1/ssl/");
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POSTFIELDS, "$xml_data");
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
$response = curl_getinfo( $ch );
curl_close($ch);
$code = $response['http_code'];
if($code == 200)
return new WPNResponse('Successfully sent message', $code);
else if($code == 401)
$my_file = '/var/log/WPNotify.txt';
$handle = fopen($my_file, 'a') or die('Cannot open file: '.$my_file);
$data = date("d-M-y H:i:s:") . "401 Authorisation Error:" . $this->access_token . "\n";
fwrite($handle, $data);
if($count == 10)
exit;
$this->access_token = '';
return $this->post_tile($uri, $xml_data, $type, $tileTag, $count++);
else if($code == 410 || $code == 404)
return new WPNResponse('Expired or invalid URI', $code, true);
else
return new WPNResponse('Unknown error while sending message', $code, true);
?>
我的代码中可能有错误,或者可能是我没有正确设置后端内容(大多数 MSDN 文档都针对 Windows Server 和 .aspx,所以我尝试复制这些说明,但可能在某个地方出错了!)。
如果有人可以帮助修复代码中的错误,或者通过 SSL 证书的客户端身份验证,我们将不胜感激!
谢谢, 杰克
【问题讨论】:
Look up HTTP Error 401,它相当不言自明,甚至可能与您希望我们涉足的大量代码无关。 @RiggsFolly 我知道什么是 401 错误,在过去 3 天试图解决这个问题无济于事之后,我希望这里的人能够对这种情况有所了解。我意识到那里有很多代码,但如果我在没有任何代码的情况下提出问题,我保证第一条评论会是“发布你的代码” 【参考方案1】:看看 Windows Notifications Service: 401 Invalid Token when trying to create a Toast notification in PHP 尝试创建 toast-n 时的无效令牌
确保在请求访问令牌时将应用的 package SID 作为“client_id”参数而不是应用的 client_id 发送。
这真的很令人困惑,两者都能够从微软的服务器获取 access_token,但是在发送 toast 通知时,只有向你请求的包 SID 的令牌不会给你 401 错误。
【讨论】:
以上是关于401 授权错误 Windows Phone 8 通知的主要内容,如果未能解决你的问题,请参考以下文章
401 - 在 IE7 中未经授权,仅使用 Windows 身份验证。