401授权错误Windows Phone 8通知

时间:2014-07-30 13:09:22

标签: php vb.net windows-phone-8 push-notification

我尝试使用经过身份验证的服务器向我的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证书的客户端身份验证,那将非常感激!

谢谢, 杰克

1 个答案:

答案 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错误。