설치된 앱을 사용자 계정으로 인증
이 가이드에서는 앱이 사용자 머신에 설치될 때 BigQuery API에 액세스하기 위해 사용자 계정을 사용하여 인증하는 방법을 설명합니다.
앱이 최종 사용자가 사용할 수 있는 BigQuery 테이블에만 액세스하도록 하기위해 사용자 인증 정보를 사용하여 인증합니다. 사용자 인증 정보는 앱의 프로젝트가 아니라 최종 사용자의 Google Cloud 프로젝트에 대해서만 쿼리를 실행할 수 있습니다. 따라서 앱이 아닌 쿼리를 기준으로 사용자에게 비용이 청구됩니다.
시작하기 전에
- 설치된 앱을 나타내는 Google Cloud 프로젝트를 만듭니다.
- BigQuery 클라이언트 라이브러리를 설치합니다.
-
인증 라이브러리를 설치합니다.
Java
Maven을 사용하는 경우 pom 파일에 다음 종속 항목을 포함합니다.
<dependency> <groupId>com.google.oauth-client</groupId> <artifactId>google-oauth-client-java6</artifactId> <version>1.31.0</version> </dependency> <dependency> <groupId>com.google.oauth-client</groupId> <artifactId>google-oauth-client-jetty</artifactId> <version>1.31.0</version> </dependency>
Python
Google Auth용 oauthlib 통합을 설치합니다.
pip install --upgrade google-auth-oauthlib
Node.js
Google Auth용 oauthlib 통합을 설치합니다.
npm install google-auth-library
npm install readline-promise
클라이언트 사용자 인증 정보 설정
다음 버튼을 사용하여 프로젝트를 선택하고 필요한 사용자 인증 정보를 만듭니다.사용자 인증 정보 수동 생성
- Google Cloud 콘솔에서 사용자 인증 정보 페이지로 이동합니다.
- OAuth 동의 화면에서 필수 입력란을 작성합니다.
- 사용자 인증 정보 페이지에서 사용자 인증 정보 만들기 버튼을 클릭합니다.
OAuth 클라이언트 ID를 선택합니다.
- 앱 유형으로 데스크톱을 선택한 후 만들기를 클릭합니다.
-
JSON 다운로드 버튼을 클릭하여 사용자 인증 정보를 다운로드합니다.
사용자 인증 정보 파일을
client_secrets.json
에 저장합니다. 이 파일을 앱과 함께 배포해야 합니다.
API 인증 및 호출
- 클라이언트 사용자 인증 정보를 사용하여 OAuth 2.0 흐름을 수행합니다.
Java
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.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.google.api.gax.paging.Page; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.UserCredentials; import com.google.cloud.bigquery.BigQuery; import com.google.cloud.bigquery.BigQueryException; import com.google.cloud.bigquery.BigQueryOptions; import com.google.cloud.bigquery.Dataset; import com.google.common.collect.ImmutableList; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.List; // Sample to authenticate by using a user credential public class AuthUserFlow { private static final File DATA_STORE_DIR = new File(AuthUserFlow.class.getResource("/").getPath(), "credentials"); private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); // i.e redirect_uri http://localhost:61984/Callback private static final int LOCAL_RECEIVER_PORT = 61984; public static void runAuthUserFlow() { // TODO(developer): Replace these variables before running the sample. /** * Download your OAuth2 configuration from the Google Developers Console API Credentials page. * https://console.cloud.google.com/apis/credentials */ Path credentialsPath = Paths.get("path/to/your/client_secret.json"); List<String> scopes = ImmutableList.of("https://www.googleapis.com/auth/bigquery"); authUserFlow(credentialsPath, scopes); } public static void authUserFlow(Path credentialsPath, List<String> selectedScopes) { // Reading credentials file try (InputStream inputStream = Files.newInputStream(credentialsPath)) { // Load client_secret.json file GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)); String clientId = clientSecrets.getDetails().getClientId(); String clientSecret = clientSecrets.getDetails().getClientSecret(); // Generate the url that will be used for the consent dialog. GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, clientSecrets, selectedScopes) .setDataStoreFactory(new FileDataStoreFactory(DATA_STORE_DIR)) .setAccessType("offline") .setApprovalPrompt("auto") .build(); // Exchange an authorization code for refresh token LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(LOCAL_RECEIVER_PORT).build(); Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); // OAuth2 Credentials representing a user's identity and consent GoogleCredentials credentials = UserCredentials.newBuilder() .setClientId(clientId) .setClientSecret(clientSecret) .setRefreshToken(credential.getRefreshToken()) .build(); // Initialize client that will be used to send requests. This client only needs to be created // once, and can be reused for multiple requests. BigQuery bigquery = BigQueryOptions.newBuilder().setCredentials(credentials).build().getService(); Page<Dataset> datasets = bigquery.listDatasets(BigQuery.DatasetListOption.pageSize(100)); if (datasets == null) { System.out.println("Dataset does not contain any models"); return; } datasets .iterateAll() .forEach( dataset -> System.out.printf("Success! Dataset ID: %s ", dataset.getDatasetId())); } catch (BigQueryException | IOException | GeneralSecurityException ex) { System.out.println("Project does not contain any datasets \n" + ex.toString()); } } }
Python
from google_auth_oauthlib import flow # A local server is used as the callback URL in the auth flow. appflow = flow.InstalledAppFlow.from_client_secrets_file( "client_secrets.json", scopes=["https://www.googleapis.com/auth/bigquery"] ) # This launches a local server to be used as the callback URL in the desktop # app auth flow. If you are accessing the application remotely, such as over # SSH or a remote Jupyter notebook, this flow will not work. Use the # `gcloud auth application-default login --no-browser` command or workload # identity federation to get authentication tokens, instead. # appflow.run_local_server() credentials = appflow.credentials
Node.js
const {OAuth2Client} = require('google-auth-library'); const readline = require('readline-promise').default; function startRl() { const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); return rl; } /** * Download your OAuth2 configuration from the Google * Developers Console API Credentials page. * https://console.cloud.google.com/apis/credentials */ const keys = require('./oauth2.keys.json'); /** * Create a new OAuth2Client, and go through the OAuth2 content * workflow. Return the full client to the callback. */ async function getRedirectUrl() { const rl = main.startRl(); // Create an oAuth client to authorize the API call. Secrets are kept in a `keys.json` file, // which should be downloaded from the Google Developers Console. const oAuth2Client = new OAuth2Client( keys.installed.client_id, keys.installed.client_secret, keys.installed.redirect_uris[0] ); // Generate the url that will be used for the consent dialog. const authorizeUrl = oAuth2Client.generateAuthUrl({ access_type: 'offline', scope: 'https://www.googleapis.com/auth/bigquery', prompt: 'consent', }); console.info( `Please visit this URL to authorize this application: ${authorizeUrl}` ); const code = await rl.questionAsync('Enter the authorization code: '); const tokens = await main.exchangeCode(code); rl.close(); return tokens; } // Exchange an authorization code for an access token async function exchangeCode(code) { const oAuth2Client = new OAuth2Client( keys.installed.client_id, keys.installed.client_secret, keys.installed.redirect_uris[0] ); const r = await oAuth2Client.getToken(code); console.info(r.tokens); return r.tokens; } async function authFlow(projectId = 'project_id') { /** * TODO(developer): * Save Project ID as environment variable PROJECT_ID="project_id" * Uncomment the following line before running the sample. */ // projectId = process.env.PROJECT_ID; const tokens = await main.getRedirectUrl(); const credentials = { type: 'authorized_user', client_id: keys.installed.client_id, client_secret: keys.installed.client_secret, refresh_token: tokens.refresh_token, }; return { projectId, credentials, }; }
- 인증된 사용자 인증 정보를 사용하여 BigQuery API에 연결합니다.
Java
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.json.JsonFactory; import com.google.api.client.json.jackson2.JacksonFactory; import com.google.api.client.util.store.FileDataStoreFactory; import com.google.auth.oauth2.GoogleCredentials; import com.google.auth.oauth2.UserCredentials; import com.google.cloud.bigquery.BigQuery; import com.google.cloud.bigquery.BigQueryException; import com.google.cloud.bigquery.BigQueryOptions; import com.google.cloud.bigquery.QueryJobConfiguration; import com.google.cloud.bigquery.TableResult; import com.google.common.collect.ImmutableList; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.GeneralSecurityException; import java.util.List; // Sample to query by using a user credential public class AuthUserQuery { private static final File DATA_STORE_DIR = new File(AuthUserQuery.class.getResource("/").getPath(), "credentials"); private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance(); // i.e redirect_uri http://localhost:61984/Callback private static final int LOCAL_RECEIVER_PORT = 61984; public static void runAuthUserQuery() { // TODO(developer): Replace these variables before running the sample. /** * Download your OAuth2 configuration from the Google Developers Console API Credentials page. * https://console.cloud.google.com/apis/credentials */ Path credentialsPath = Paths.get("path/to/your/client_secret.json"); List<String> scopes = ImmutableList.of("https://www.googleapis.com/auth/bigquery"); String query = "SELECT name, SUM(number) as total" + " FROM `bigquery-public-data.usa_names.usa_1910_current`" + " WHERE name = 'William'" + " GROUP BY name;"; authUserQuery(credentialsPath, scopes, query); } public static void authUserQuery( Path credentialsPath, List<String> selectedScopes, String query) { // Reading credentials file try (InputStream inputStream = Files.newInputStream(credentialsPath)) { // Load client_secret.json file GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream)); String clientId = clientSecrets.getDetails().getClientId(); String clientSecret = clientSecrets.getDetails().getClientSecret(); // Generate the url that will be used for the consent dialog. GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder( GoogleNetHttpTransport.newTrustedTransport(), JSON_FACTORY, clientSecrets, selectedScopes) .setDataStoreFactory(new FileDataStoreFactory(DATA_STORE_DIR)) .setAccessType("offline") .setApprovalPrompt("auto") .build(); // Exchange an authorization code for refresh token LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(LOCAL_RECEIVER_PORT).build(); Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user"); // OAuth2 Credentials representing a user's identity and consent GoogleCredentials credentials = UserCredentials.newBuilder() .setClientId(clientId) .setClientSecret(clientSecret) .setRefreshToken(credential.getRefreshToken()) .build(); // Initialize client that will be used to send requests. This client only needs to be created // once, and can be reused for multiple requests. BigQuery bigquery = BigQueryOptions.newBuilder().setCredentials(credentials).build().getService(); QueryJobConfiguration queryConfig = QueryJobConfiguration.newBuilder(query).build(); TableResult results = bigquery.query(queryConfig); results .iterateAll() .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString()))); System.out.println("Query performed successfully."); } catch (BigQueryException | IOException | GeneralSecurityException | InterruptedException ex) { System.out.println("Query not performed \n" + ex.toString()); } } }
Python
from google.cloud import bigquery # TODO: Uncomment the line below to set the `project` variable. # project = 'user-project-id' # # The `project` variable defines the project to be billed for query # processing. The user must have the bigquery.jobs.create permission on # this project to run a query. See: # https://cloud.google.com/bigquery/docs/access-control#permissions client = bigquery.Client(project=project, credentials=credentials) query_string = """SELECT name, SUM(number) as total FROM `bigquery-public-data.usa_names.usa_1910_current` WHERE name = 'William' GROUP BY name; """ results = client.query_and_wait(query_string) # Print the results. for row in results: # Wait for the job to complete. print("{}: {}".format(row["name"], row["total"]))
Node.js
async function query() { const {BigQuery} = require('@google-cloud/bigquery'); const credentials = await main.authFlow(); const bigquery = new BigQuery(credentials); // Queries the U.S. given names dataset for the state of Texas. const query = `SELECT name, SUM(number) as total FROM \`bigquery-public-data.usa_names.usa_1910_current\` WHERE name = 'William' GROUP BY name;`; // For all options, see https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query const options = { query: query, }; // Run the query as a job const [job] = await bigquery.createQueryJob(options); console.log(`Job ${job.id} started.`); // Wait for the query to finish const [rows] = await job.getQueryResults(); // Print the results console.log('Rows:'); rows.forEach(row => console.log(row)); return rows; } const main = { query, authFlow, exchangeCode, getRedirectUrl, startRl, }; module.exports = { main, }; if (module === require.main) { query().catch(console.error); }
샘플 코드를 실행하면 클라이언트 보안 비밀과 연결된 프로젝트의 액세스를 요청하는 브라우저가 시작됩니다. 샘플이 BigQuery 범위를 요청했으므로, 결과 사용자 인증 정보를 통해 사용자의 BigQuery 리소스에 액세스할 수 있습니다.