Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Google API e OAuth2

Boa tarde, Segundo o meu desenvolvimento com o Framework ASP.NET Core MVC, andei tendo dificulades em criar as credencias do meu sistema para interagir com as varias diferentes APIs que necessitam de Autenticacao para acessar diversos dados.

Originalmente, meu sistema tinha uma classe dedicada para chamadas de Google API, onde tinha o seguinte codigo:

public static class FormScript
{
  public static string GenerateForm(Lecture lecture)
    {
      // Generate Google AuthO2 Credentials
      UserCredential credential;
      using (var stream = new FileStream("<Arquivo JSON com Credenciais Google>", FileMode.Open, FileAccess.Read))
      {
        credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
        GoogleClientSecrets.Load(stream).Secrets,
        new[] { ScriptService.Scope.Drive, ScriptService.Scope.Forms },
        "Apps Script", CancellationToken.None);
      }

      // Create Google Apps Script API service.
      string scriptId = "<ID do Arquivo Google Apps Script>";
      var service = new ScriptService(new BaseClientService.Initializer()
      {
        ApplicationName = "<Nome do Aplicativo>",
        HttpClientInitializer = credential
      });

      // Create an execution request object.
      ExecutionRequest request = new ExecutionRequest();
      request.Function = "<Metodo Para Ser Chamado em Google Apps Script>";
      .... // logica para adicionar parametros do request.Parameters 
      ScriptsResource.RunRequest runReq = service.Scripts.Run(request, scriptId);

      // Make the API request.
      Operation op = runReq.Execute();

      if (op.Error != null)
      {
        // The API executed, but the script returned an error.
    ...
      }
      else
      {
        // The result provided by the API needs to be cast into
        // the correct type, based upon what types the Apps
        // Script function returns. Here, the function returns
        // an Apps Script Object with String keys and values.
        // It is most convenient to cast the return value as a JSON
        // JObject (folderSet).
        string formAddress = (string) op.Response["result"];
        ... Verificacao do resultado do Script ...
        return formAddress;
      }
    }
  }
}

O que funcionou por um bom tempo, mas quando comecei implementar um segundo metodo para obter dados de uma planilha em Google Sheets, o meu sistema comecou a ter problemas de authenticacao com o Google.

Sempre que o meu sistema faz uma chamada para qualquer metodo Google API, recebo uma pagina de erro da Google dizendo que o meu Redirect URI eh invalido. Na hora de criacao da minhas credenciais, Google precisa de no minimo um URL de retorno para o meu sistema. Esse URL somente consiste de http://localhost:5500/authenticate, so que o meu sistema dinamicamente gera uma nova porta para retorno com um numero entre portas 4000 a 60000. O que eh impossivel de prever ou adicionar os 56mil casos diferentes no console da Google.

Nao sabendo o que mudou para quebrar minha logica original de authenticacao, tentei buscar varios tipos de solucoes: tentar fixar minha porta de redirecionamento para um valor fixo, outros tipos de credenciais, modificacoes no Startup.cs e Program.cs para adicionar credenciais para o sistema, etc.

Honestamente, nao sei o que mais fazer ja que eu nao encontro exemplos de como implementar credenciais que nao utilizem o Sign-In de Usuarios, ou que seja sobre a versao ASP.NET Core 2 (que completamente modificou a usagem de OAuth2 tres vezes).

Alguem me poderia dar sugestoes ou implementacoes proprias de OAuth2 in .NET? Mesmo que seja um link para um Guide interessante ja poderia ajudar (apesar de que eu ja praticamente tudo que eu encontrei).

Grato,

Lucas

6 respostas

Opa, Lucas. Como você tá?

A sua aplicação usa os recursos do Google da sua própria conta/qualquer conta já conhecida, ou usa os recursos da conta Google do usuário que usa seu sistema?

Oi Guilherme, eu estou bem, e vc? No momento eu tenho a minha conta pessoal no Google, onde criei um projeto dentro do sistema deles. Devido ao fato que a aplicacao acessa um Google Script App associado a minha conta, eu criei as minhas Credenciais de Web App, que permite que o meu projeto tenha interacao com meus documentos Google. E ja que planejo utilizar Google Sheets para coletar dados, precisarei do acesso para meus arquivos no Drive.

Eu inicialmente tentei utilizar uma chave de Sistema (Account Service Key), so que tem limitacoes no que preciso fazer.

Aguardo o seu retorno

Obrigado, Lucas

Lucas, peço desculpas pelo atraso. Você conseguiu resolver o problema?

Sobre sua tentativa, quais são as limitações que você está enfrentando? Enquanto isso vou criar uma prova de conceito aqui do meu lado para tentar reproduzir isto.

Para utilizar o Account Service Key (ASK) em OAuth2, o sistema somente necessita de uma chave API, gerada dentro de um Google Project. Somente que este tipo de autenticacao tem limites de acesso. Por exemplo:

Google Apps Scripts (Publicado na Web) Java -> Google API -> Google Apps Script

Sistema faz um pedido para um Google Apps Scripts, para rodar o script que utiliza API's Publicas do Google (por exemplo, Youtube), o ASK seria suficiente para fazer uma chamada ao meu Script.

Mas, se a logica de acesso eh a seguinte, Java -> Google API -> Google Apps Script -> Google Drive -> Gerar Google Forms e Java -> Google API -> Google Sheets -> Google Drive

O meu Script vai precisar fazer acesso a coisas nao publicas, precisando de Read/Write access ao Google Drive do Usuario . O ASK nao tem essas permissoes, somente Read access of coisas publicas Google. Por isso eu preciso OAuth2 Credentials, com mais permissoes de acesso que o ASK.

solução!

Luke, encontrei este bug reportado em 2015 sobre a limitação de invocar um App Script a partir de uma API (como a do C#, por exemplo) quando há uso de recursos de um usuário.

O Google adicionou uma notificação na documentação sobre isso: "The Apps Script API does not work with service accounts.".

Então para criar um Google Form, por exemplo, seria necessário usar uma API para a linguagem que você deseja utilizar - mas, até o momento não existe uma API para isto

Entao neste caso, tem alguma outra alternativa ou workaround? O mais estranho eh que estava funcionando anteriormente, com varios Forms criados dentro da minha conta Google.