Próbuję użyć mojego konta serwisowego do współpracy z API arkuszy Google w aplikacji My .NET 5. Zacząłem od Przykład "QuickStart" i działa dobrze. Ale muszę umieścić moją aplikację wewnątrz kontenera dokującego, więc autoryzacja z "QuickStart", który korzysta z przeglądarki, nie pasuje do mnie. Postanowiłem spróbować autoryzować z kontem usługi Google. Znalazłem To rozwiązanie ale kiedy próbuję wykonać dowolną żądanie rzucić błąd 'Error:"invalid_grant", Description:"Invalid JWT Signature.", Uri:""'

Oto mój kod konfiguracji poświadczeń:

using System.IO;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Sheets.v4;

namespace GoogleSheetsParser.Helpers
{
    public class GoogleSheetsServiceSettings
    {
        private static readonly string[] Scopes = { SheetsService.Scope.Spreadsheets };

        public static ServiceAccountCredential Credential { get; private set; }

        public static void Setup()
        {
            var serviceAccountEmail = "my@seviceaccount.iam.gserviceaccount.com";
            using Stream stream = new FileStream("credentials.json", FileMode.Open, FileAccess.Read, FileShare.Read);
            var credential = (ServiceAccountCredential)
                GoogleCredential.FromStream(stream).UnderlyingCredential;

            var initializer = new ServiceAccountCredential.Initializer(credential.Id)
            {
                User = serviceAccountEmail,
                Key = credential.Key,
                Scopes = Scopes
            };
            Credential = new ServiceAccountCredential(initializer);
        }
    }
}    

Oto moje startup.cs

namespace GoogleSheetsParser
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllers();
            services.AddSingleton(Configuration);

            GoogleSheetsServiceSettings.Setup();
            var sheetsService = new SheetsService(new BaseClientService.Initializer
            {
                ApplicationName = Configuration.GetValue<string>("ApplicationName"),
                HttpClientInitializer = GoogleSheetsServiceSettings.Credential
            });
            
            services.AddSingleton(sheetsService);
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

Oto wykorzystanie skonfigurowanych arkuszy Serwis:

using Microsoft.AspNetCore.Mvc;
using Google.Apis.Sheets.v4;
using GoogleSheetsParser.Dto;

namespace GoogleSheetsParser.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class SheetsController : ControllerBase
    {
        private SheetsService SheetsService { get; }

        public SheetsController(SheetsService sheetsService)
        {
            SheetsService = sheetsService;
        }

        [HttpGet]
        public JsonResult GetSheets([FromQuery] GetSheetsRequestDto dto)
        { 
            var spreadsheet = SheetsService.Spreadsheets.Get(dto.SpreadsheetId).Execute();
        }
    }
}

Testowanie go na mojej lokalnej maszynie w projekcie Visual Studio.

Czego mi brakuje?

2
Shadr 20 kwiecień 2021, 17:39

1 odpowiedź

Najlepsza odpowiedź

Jest to nieco niejasne dla mnie, dlaczego w ogóle używa JWT tutaj, ale na pewno można uniknąć trwającego tak niskim poziomie, używając GoogleCredential.CreateWithUser i GoogleCredential.CreateScoped. Oto kod, który piszę w twoim Setup:

using System.IO;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Sheets.v4;

namespace GoogleSheetsParser.Helpers
{
    public class GoogleSheetsServiceSettings
    {
        public static GoogleCredential Credential { get; private set; }

        public static void Setup() =>
            Credential = GoogleCredential.FromFile("credentials.json")
                .CreateScoped(SheetsService.Scope.Spreadsheets)
                .CreateWithUser("my@seviceaccount.iam.gserviceaccount.com");
    }
}

Nie jest jasne, dlaczego Ustaw użytkownika na inne konto serwisowe - zwykle używasz CreateWithUser, aby podszywać się do użytkownika z kontem serwisowym. Jeśli chcesz działać jako konto serwisowe, wygeneruj plik JSON z poświadczeniami dla tego konta usług i nie przejmuj się podszywaniem się.

1
Jon Skeet 21 kwiecień 2021, 10:40