Back-End

3 dez, 2012

OAuth sem dor com PHP – PHP OAuth API – Parte 02

Publicidade

Package: PHP OAuth API

Na primeira parte deste artigo, vimos que o OAuth é um protocolo muito usado para acessar APIs de determinados sites em nome dos usuários desses sites. Apesar de ele ser relativamente fácil de explicar, não é fácil implementá-lo sem lidar com as dores de cabeça das múltiplas configurações do protocolo, as versões de protocolos diferentes, os detalhes de implementações específicas do local e o pior de tudo: ter de saber mais do que gostaria dos detalhes do protocolo.

Depois de começar com os fundamentos (porque ele é necessário, como funciona e as implementações de consumo PHP OAuth), hoje continuaremos com a parte prática – como utilizar a classe PHP OAuth.

Utilizando a classe PHP OAuth API na prática

1. Não me faça aprender o protocolo OAuth

Esta classe de cliente PHP OAuth foi construída especificamente com a finalidade de que você obtenha velocidade sem conhecer muito sobre o funcionamento do protocolo.

É sempre bom saber como o protocolo funciona internamente, mas se você não tem tempo nem paciência, você não precisa conhecê-lo de modo extensivo.

Existem duas versões principais do protocolo OAuth em uso: a 1.0a e a 2.0. Mas não se preocupe, a classe abstrai todas as diferenças entre elas, para que você não tem que escrever múltiplas seções de código dependendo da versão do protocolo suportado pelo site provedor.

Também há diferenças de implementação e configuração ao acessar sites específicos de provedor OAuth. Na maioria dos casos, essas diferenças serão transparentes para você. A classe é inteligente o suficiente para lidar com pelo menos algumas dessas diferenças, de modo que você não tenha que lidar com elas em seu aplicativo.

Tudo o que você precisa saber é que a classe faz principalmente duas coisas: a) interage com um site de provedor de OAuth para obter um token de acesso, b) chama a API do site de provedor para executar uma função da API utilizando um token de acesso obtido anteriormente.

2. Introdução ao caso de uso de mapping approach

Antes de explicar como usar a classe para fins relacionados ao OAuth, para aqueles que gostam de estudar como as coisas funcionam internamente, pode ser legal dar uma olhada na abordagem que usei nessa classe e em outras que encapsulam funcionalidades do que chamo de componentes de nível de aplicação.

Caso prefira aprender com exemplo de código, você pode pular essa parte para a etapa chamada “Obtendo o Token de Acesso”.

A abordagem é chamada de mapping de caso de uso. Quando você precisa implementar um sistema de software e quando esse sistema é grande o suficiente, normalmente você vai dividi-lo em sub-sistemas. Cada sistema ou sub-sistema implementa um conjunto de casos de uso.

Os casos de uso são situações individuais com que seus sistemas precisam lidar para atingir seus objetivos. Algumas pessoas dão outros nomes para os casos de uso, como telas ou páginas. Por exemplo, em um sistema, podemos ter casos de uso como: página de registro, página de login, opções do usuário, entrega de newsletter etc.

Para aqueles familiarizados com modelagem de desenvolvimento agile, os casos de uso são semelhantes às histórias de usuários. Eu prefiro pensar em termos de casos de uso, porque às vezes você precisa lidar com as interações entre o seu sistema e um agente que não é um usuário real, como um sistema externo que o seu sistema precisa para se comunicar com o uso de algumas APIs.

Enfim, para a implementação real de casos de uso, eu projetei um padrão para implementá-las como classes. Cada caso de uso mapeia para uma classe, por isso o nome mapping de caso de uso para essa abordagem.

A classe cliente de OAuth foi implementada como uma classe de caso de uso. Neste artigo, só vou descrever as funções públicas e as variáveis de classes de casos de uso, pois é tudo que você precisa saber para usar a classe cliente de OAuth.

Basicamente, uma classe de caso de uso possui quatro funções públicas e duas variáveis públicas. Podem existir outras funções públicas e variáveis específicas para o propósito do caso de uso. Por agora, vou explicar o papel das funções públicas e variáveis básicas.

Funções

Initialize() – É a primeira função você precisa chamar após a criação de um objeto de classe. Não é uma função do construtor. É uma função que inicializa o objeto e avalia se certas condições obrigatórias são válidas, como estabelecer uma conexão com o banco de dados.

Essas condições obrigatórias são chamadas de pré-condições. Se uma ou mais pré-condição não for cumprida, a função retorna falso, e uma variável de erro é definida para explicar o motivo da falha ao desenvolvedor.

Process() – É a função onde toda a ação acontece. A sua função é a de processar qualquer entrada e preparar a geração de qualquer saída. Em geral, a saída final não deve ser gerada aqui.

Ela deve ser chamada apenas depois de chamar a função Initialize(). Se por algum motivo o processamento falhar, esta função retorna falso, e uma variável de erro é definida.

Finalize() – Esta função foi feita para limpar quaisquer recursos alocados durante as chamadas Initialize e Process. Normalmente, é utilizada para assegurar que certas condições sejam satisfeitas no final do caso de uso. Essas condições são chamadas de pós-condições. Gerar entradas de log de todos os eventos que aconteceram durante o processamento é um exemplo de uma pós-condição.

Esta função não deve ser chamada se a função Initialize falhou. É preciso um parâmetro que é geralmente o valor de retorno da chamada para a função de Process. Mais uma vez, se por algum motivo a finalização falhar, esta função retorna falso, e uma variável de erro é definida.

Output() – Este é o lugar onde qualquer saída se o caso de uso deve ser emitido. A saída pode ser gerada a partir de informação produzida durante a chamada para a função Process. Quando necessário, as variáveis de classe privada podem ser usadas para compartilhar informações entre as chamadas Process e Output.

Dessa forma, você pode implementar a separação de preocupações. Nenhuma saída acontece durante o processamento, ou qualquer processamento ocorre durante a produção.

Normalmente, a função Output não retorna nada, porque a saída é exibida para o usuário, mas em alguns casos ela pode retornar uma string com os dados de saída reais, caso seja conveniente.

Variáveis

$error – Esta é a variável que armazena uma mensagem de erro se qualquer uma das funções Initialize, Process e Finalize falhar. A mensagem de erro não é para ser exibida para os usuário, se sim para permitir que o desenvolvedor saiba por que ele falhou.

$exit – Esta variável booleana pode ser definida pela classe de caso de uso para dizer se o script deve sair imediatamente, sem retornar nada. Quando esta variável for verdadeira, o script deve sair sem chamar a função Output. Normalmente, isso significa que a classe emitiu cabeçalhos especiais, como aqueles que redirecionam o navegador para outra página.

3. Obtendo o token de acesso

OAuth é um protocolo complexo que exige acesso à API do site de provedor e redireciona o navegador do usuário para frente e para trás entre sites consumidores e provedores. Essa interação requer a definição de vários parâmetros, como as URLs do site de provedor para acessar cada coisa.

Felizmente, essa classe fornece suporte built-in de alguns dos sites provedores mais populares. Você só precisa definir uma única variável chamada $server com o tipo de servidor que você deseja acessar. Dessa forma, a classe configura automaticamente diversas de suas variáveis, de modo que você não tem que fazê-lo manualmente.

A classe fornece suporte built-in para muitos sites provedores. Outros serão acrescentados no futuro. No entanto, se você precisar acessar um servidor OAuth que é suportado diretamente pela classe, você ainda pode usar a classe para acessá-lo. Você só precisa configurar algumas variáveis manualmente.

Configurar a classe de acesso a esses outros servidores está fora do escopo deste artigo. Leia a documentação da classe para saber o que você precisa fazer. Fique à vontade para fazer perguntas no fórum de suporte da classe, se você tiver qualquer dificuldade.

Então, o seu do script básico de autorização OAuth começa assim:

$client = new OAuth_client_class;
$client->server = 'Twitter';

A próxima coisa que você precisa fazer é configurar a identidade de seus aplicativos. Primeiro, você precisa ir ao site provedor e registrar um aplicativo. O registro fornecerá os valores para o identificador e de um segredo do mesmo. Por razões de segurança, você não deve compartilhar esse segredo com ninguém.

$client->client_id = 'Application identifier goes here';
$client->client_secret = 'Application secret goes here';

Os servidores OAuth 2.0 podem deixar que você solicite a permissão para acessar seções específicas da API do site provedor. Essas permissões devem ser configuradas usando a variável $scope. Para sites provedores OAuth de 1.0, elas são normalmente configuradas na página de opções do aplicativo.

Os valores das permissões para solicitar dependem do site provedor. Você precisa verificar a documentação da API do do site provedor para determinar os valores de permissão que o seu aplicativo precisa.

$client->scope = 'API permissions list goes here';

Durante o processo de autorização OAuth, o navegador do usuário é redirecionado para o site provedor. Em seguida, o browser é redirecionado para o site consumidor, após o usuário conceder acesso ao seu aplicativo. O site provedor precisa saber para qual página o usuário deve ser redirecionado.

Normalmente, você pode configurar a URL da página para redirecionar o navegador do usuário para seu site consumidor usando a variável $redirect_uri. Alguns servidores exigem que essa URL esteja sob um domínio público válido. Assim, domínios privados podem não ser aceitos.

$client->redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].
dirname(strtok($_SERVER['REQUEST_URI'],'?')).
'/change_this_to_the_name_of_this_script.php';

Agora você está pronto para iniciar o processo OAuth.

if(($success = $client->Initialize()))
{
  if(($success = $client->Process()))
  {

Depois de chamar a função Process, o processo de autorização OAuth pode ou não ter sido concluído. Caso tenha sido, a variável $access_token é definida como uma string não vazia.

Talvez você queira armazenar o valor do token de acesso em algum lugar para utilização posterior. Normalmente, aplicativos armazenam o token em um banco de dados para que eles possam usá-lo para chamar a API do site provedor depois, eventualmente quando o usuário não estiver presente.

Para sites provedores de OAuth 1.0a, existe um token com valor secreto adicional que você também precisa manter. Ele é armazenado na variável $access_token_secret.

if(strlen($client->access_token))
{
// Do something useful with the access token
}

Se houvesse um erro ao recuperar o token de acesso, a variável $authorization_error seria definida como a mensagem de erro.

 elseif(strlen($client->authorization_error))
 {
   $client->error = $client->authorization_error;
   $success = false;
 }
}

No final, sempre chame a função Finalize, independentemente de o processo de autorização ter sido concluído com sucesso ou não.

 $success = $client->Finalize($success);
}

Então, você precisa verificar a variável $exit para determinar se o seu script precisa sair imediatamente para que o processo OAuth possa funcionar corretamente.

if($client->exit)
 exit;

Se o processo foi concluído com sucesso, é legal que você mostre uma mensagem útil para o usuário.

if($client->access_token)
{
 echo '<h1>API access was authorized successfully!</h1>';
}

Seria legal também se você apresentasse mensagens úteis para o usuário, caso o processo tiver falhado por algum motivo.

if($client->authorization_error)
{
 echo '<h1>It was not possible to obtain API access',
      ' authorization!</h1>,
      '<p>Please <a href="?">try again</a>.</p>';
}

4. Chamando o fornecedor do site API

Depois de ter obtido o token de acesso, você pode chamar a API do site de provedor imediatamente, usando a função CallAPI logo após retornar da função Process e antes de chamar a função Finalize.

Alguns sites provedores também permitem o acesso a suas APIs em nome do usuário, mesmo quando o usuário não está presente. Você só precisa utilizar a função CallAPI passando os valores de $access_token e $access_token_secret obtidos anteriormente.

$client->access_token = 'Access token here';
$client->access_token_secret = 'Access token secret here';
$url =
  'https://api.twitter.com/1.1/account/verify_credentials.json';
$method = 'GET';
$parameters = array();
$options = array();
$success = $client->CallAPI($url, $method, $parameters, $options,
  $response)))

Os parâmetros $url e $method da chamada da API são definidos na documentação da API do site provedor. O parâmetro $options é um array com opções eventuais que você pode precisar definir para configurar a forma como a chamada da API é processada. Verifique essa documentação de classe para obter mais detalhes sobre essas opções.

O parâmetro $response retorna os resultados da chamada da API. Se os resultados forem formulário de URL codificada ou JSON codificado, o valor CallAPI decodifica a resposta para você.

Se a chamada API falhou devido a algum problema relacionado com os parâmetros ou com o token de acesso, a variável $access_token_error é definida como a mensagem de erro que você precisa verificar.

Conclusão

Apesar da complexidade do protocolo OAuth e suas diferentes implementações, essa classe tenta abstrair, tanto quanto possível, todos os detalhes para que os aplicativos exijam apenas uma quantidade mínima de código para obter autorização para chamar as APIs do site de provedor.

Em parte, essa simplificação do processo foi conseguida pela adição de suporte built-in para alguns OAuth mais populares baseados em servidores de APIs. Não é possível adicionar suporte built-in para todas as APIs existentes. No entanto, a classe continuará evoluindo para cobrir o máximo possível de APIs.

Outra parte da presente simplificação está relacionada ao fato de que a classe é auto-contida. Isso significa que você só precisa carregar essa classe para usar todas as funcionalidades fornecidas. A dependência externa está apenas em uma classe HTTP para enviar solicitações HTTP para o servidor web do provedor. Não existem outras classes que você precisa para usar toda a funcionalidade de cliente OAuth.

***

Texto original disponível em http://www.phpclasses.org/blog/package/7700/post/1-Painless-OAuth-with-PHP.html