我尝试使用经过身份验证的服务器向我的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服务器和.aspx,所以我很高兴试图复制这些说明,但可能在某个地方出错!)。
如果有人可以帮助修复代码中的错误,或者使用SSL证书的客户端身份验证,那将非常感激!
谢谢, 杰克
答案 0 :(得分:0)
看一看 Windows Notifications Service: 401 Invalid Token when trying to create a Toast notification in PHP 无效-令牌时-试图对创建-A-吐司-N
请确保您在申请访问令牌时将应用的包SID 作为'client_id'参数发送,而不是应用的client_id。
这实在令人困惑,两者都可以从Microsoft的服务器获取access_token,但只有包裹SID请求的令牌在发送Toast通知时不会给你401错误。