我正在尝试开发一个应用程序,使用Perl在Quickbooks Online中创建发票。我可以使用OAuth进行身份验证(使用Net :: OAuth :: Simple),我可以通过回调成功接收OAuth令牌和机密。但是,如果我的连接空闲45秒,下次我发出请求时,会收到错误“401 Unauthorized”。
如何让我的连接持续时间超过45秒?
#!/usr/bin/perl
use strict;
use warnings;
package QuickbooksSketch;
use English qw/-no_match_vars/;
use Carp qw/carp croak/;
use Readonly;
use base qw{Net::OAuth::Simple};
use URI;
Readonly my $APP_TOKEN => q{REDACTED};
Readonly my $CONSUMER_KEY => q{REDACTED};
Readonly my $CONSUMER_SECRET => q{REDACTED};
Readonly my $QBO_URLS => {
'request_token_url' => 'https://oauth.intuit.com/oauth/v1/get_request_token',
'access_token_url' => 'https://oauth.intuit.com/oauth/v1/get_access_token',
'authorization_url' => 'https://appcenter.intuit.com/Connect/Begin',
};
Readonly my $QUERY_URL_BASE => 'https://qb.sbfinance.intuit.com/v3/company';
Readonly my $PROTOCOL_VERSION => q{1.0a};
Readonly my $CALLBACK_URL => q{http://localhost/callback};
Readonly my $REALM_ID => 12345;
Readonly my $GOOD_URI => q{https://appcenter.intuit.com/api/v1/Account/AppMenu};
Readonly my $QUERY_URI => q{https://qb.sbfinance.intuit.com/v3/company/828655235/query?query=select * from Customer};
Readonly my $RECONNECT_URI => q{https://appcenter.intuit.com/api/v1/Connection/Reconnect};
sub new {
my ($class, $args) = @_;
my $self = $class->SUPER::new(
'tokens' => {
'consumer_key' => $CONSUMER_KEY,
'consumer_secret' => $CONSUMER_SECRET,
},
'urls' => $QBO_URLS,
);
$self->{'realm_id'} = $args->{'realm_id'};
return $self;
}
sub get_authorization_url {
my ($self, %params) = @_;
$params{'callback'} ||= qq{http://$CALLBACK_URL/};
return $self->SUPER::get_authorization_url(%params);
}
package main;
use English qw/-no_match_vars/;
use Carp qw/carp croak/;
use Getopt::Long;
use POSIX qw/strftime/;
use FindBin qw($Bin);
use File::Slurp qw(read_file);
use Readonly;
use Socket;
use IO::Handle;
use Data::Dumper;
sub main {
my $qb = QuickbooksSketch->new();
my ($access_token, $access_token_secret) = read_access_tokens($REALM_ID);
$qb->access_token($access_token);
$qb->access_token_secret($access_token_secret);
while (!$qb->authorized) {
authorize($qb);
}
my $response1 = $qb->make_restricted_request($GOOD_URI, 'GET');
if ($response1->content =~ /This app is no longer connected/) {
print qq{No longer connected, yadda yadda yadda\n};
}
# This works IFF the access tokens are less than 45 seconds old
my $response2;
$response2 = eval {
$qb->make_restricted_request($QUERY_URI, 'GET', 'query' => q{select * from Customer}, 'Headers' => ['Accept' => 'application/json']);
} or die qq{$EVAL_ERROR\n};
print $response2->content, qq{\n};
# This is giving me "Token Refresh Window Out of Bounds"
my $response3 = eval {
$qb->make_restricted_request($RECONNECT_URI, 'GET', 'Headers' => ['Accept' => 'application/json']);
} or die qq{Caught exception in reconnect URI: $EVAL_ERROR\n};
print $response3->content, qq{\n};
}
sub authorize {
my $qb = shift;
my ($read_sock, $write_sock);
socketpair($read_sock, $write_sock, AF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "socketpair: $OS_ERROR";
# callback sends data over socket
my $auth_url = $qb->get_authorization_url;
print STDERR qq/Authorization credentials not present or expired. Please reauthorize at $auth_url\n/;
my $auth_data = {};
while( my $message = <$read_sock> ) {
chomp $message;
last if ($message eq 'END');
my ($key, $val) = split /\s*:\s*/, $message, 2;
$auth_data->{$key} = $val;
}
shutdown $read_sock, 2;
shutdown $write_sock, 2;
my $verifier = $auth_data->{'oauth_verifier'};
if (!$verifier) {
die qq{OAuth authentication failed\n};
}
print qq{Set verifier to $verifier\n};
$qb->verifier($verifier);
my ($access_token, $access_token_secret) = $qb->request_access_token;
store_access_tokens($auth_data->{'realmId'}, $access_token, $access_token_secret);
$qb->access_token($access_token);
$qb->access_token_secret($access_token_secret);
# shut down handler
}