I am doing a service automatic generate file and upload it to google drive using Spring boot and java 8. This is an external service of another bigger service.
I can't found any instruction about create credential using service account key for Google drive API so I wrote this code myself base on this instruction: https://cloud.google.com/docs/authentication/production. The code basically perform a simple GET request to get all file and folder in my Google drive. It run but got the exception
Here are the code
package com.example.demo.controller;
import com.example.demo.dto.FileItemDTO;
import com.example.demo.service.GoogleDriveService;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@RestController
public class GoogleDriveController {
@Value("${google.service.account.key}")
private static Resource serviceAccountKey;
@Value("${external.address}")
private String externalAddress;
private final GoogleDriveService googleDriveService;
private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
private static JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE_METADATA_READONLY);
private static final String TOKENS_DIRECTORY_PATH = "tokens";
@Autowired
public GoogleDriveController(GoogleDriveService googleDriveService) throws IOException {
this.googleDriveService = googleDriveService;
}
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
// Load client secrets.
java.io.File file = new java.io.File("path-to-credential-file");
InputStream inputStream = new FileInputStream(file);
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream));
// Build flow and trigger user authorization request.
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
.setAccessType("offline")
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8868).build();
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
@GetMapping(value = {"/static-page/get"})
public @ResponseBody
List<FileItemDTO> getStaticPage() throws Exception {
String pageToken = null;
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Drive drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)).build();
List<FileItemDTO> responseList = new ArrayList<>();
FileList fileList = drive.files().list().setFields("files(id,name,thumbnailLink)").execute();
for (File file : fileList.getFiles()) {
FileItemDTO item = new FileItemDTO();
item.setId(file.getId());
item.setName(file.getName());
item.setThumbnailLink(file.getThumbnailLink());
responseList.add(item);
}
return responseList;
}
}
The service account got the owner role. Can somebody please help me about this exception?
As I understand the service account key with owner role have the highest permission.
Edit: After follow @DalmTo answer, I have delete getCredential() method and the code to create Drive object become like this and every thing work fine now:
// file 1 is the JSON credential file
// GoogleCredential have been deprecated so instead I use HttpRequestInitializer
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(ServiceAccountCredentials.fromStream(new FileInputStream(file1))
.createScoped(DriveScopes.all()));
Drive drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
.setApplicationName(ApplicationName).build();