개요
세부적인 권한을 통해 소비자는 각 앱과 공유할 계정 데이터를 더 세부적으로 관리할 수 있습니다. 세부적인 권한은 관리, 투명성, 보안을 강화하여 사용자와 개발자 모두에게 이점을 제공합니다. 이 가이드에서는 세부 권한을 처리하도록 애플리케이션을 성공적으로 업데이트하는 데 필요한 변경사항과 단계를 설명합니다.
세분화된 권한이란 무엇인가요?
이메일과 캘린더 범위 모두를 요청하는 생산성 앱을 개발한다고 가정해 보겠습니다. 사용자가 Gmail이 아닌 Google Calendar에만 애플리케이션을 사용하고 싶어할 수 있습니다. 세부적인 OAuth 권한을 사용하면 사용자가 Gmail이 아닌 Google Calendar 권한만 부여하도록 선택할 수 있습니다. 사용자가 특정 데이터에 대한 액세스 권한을 부여할 수 있도록 함으로써 데이터 노출을 최소화하고, 신뢰를 강화하며, 사용자가 디지털 생활을 개인 정보 보호 우선으로 관리할 수 있도록 지원합니다. 이러한 시나리오를 처리하도록 애플리케이션을 설계하는 것이 중요합니다.
로그인 외 범위가 두 개 이상 요청된 경우
로그인 및 비로그인 범위
로그인 범위와 비로그인 범위를 모두 요청하는 애플리케이션의 경우 사용자는 먼저 로그인 범위(email
, profile
, openid
)에 대한 동의 페이지를 보게 됩니다. 사용자가 기본 신원 정보 (이름, 이메일 주소, 프로필 사진)를 공유하는 데 동의하면 비로그인 범위에 대한 세부 권한 동의 화면이 표시됩니다. 이 경우 애플리케이션은 사용자가 부여한 범위를 확인해야 하며 사용자가 요청된 모든 범위를 부여한다고 가정할 수 없습니다. 다음 예시에서 웹 애플리케이션은 세 가지 로그인 범위와 Google Drive 비로그인 범위를 모두 요청합니다. 사용자가 로그인 범위에 동의하면 Google Drive 권한에 대한 세부 권한 동의 화면이 표시됩니다.

로그인하지 않은 범위가 두 개 이상
애플리케이션이 로그인 외 범위를 두 개 이상 요청하면 사용자에게 세부 권한 동의 화면이 표시됩니다. 사용자는 애플리케이션과 공유할 권한을 승인할 수 있습니다. 다음은 사용자의 Gmail 메시지 및 Google Calendar 데이터에 대한 액세스를 요청하는 세부 권한 동의 화면의 예입니다.

로그인 범위 (email
, profile
, openid
)만 요청하는 애플리케이션에는 세부 권한 동의 화면이 적용되지 않습니다. 사용자는 전체 로그인 요청을 승인하거나 거부합니다. 즉, 애플리케이션이 로그인 범위 (1개, 2개 또는 3개 모두)만 요청하는 경우 세분화된 권한 동의 화면이 적용되지 않습니다.
로그인 외 범위 하나만 요청하는 애플리케이션에는 세분화된 권한 동의 화면이 적용되지 않습니다. 즉, 사용자는 전체 요청을 승인하거나 거부하며 동의 화면에는 체크박스가 없습니다. 다음 표에는 세부 권한 동의 화면이 표시되는 시기가 요약되어 있습니다.
로그인 범위 수 | 로그인하지 않는 범위 수 | 세분화된 권한 동의 화면 |
---|---|---|
1-3 | 0 | 해당 사항 없음 |
1-3 | 1+ | 적용 가능 |
0 | 1 | 해당 사항 없음 |
0 | 2+ | 적용 가능 |
애플리케이션이 영향을 받는지 확인
권한 요청에 Google OAuth 2.0 승인 엔드포인트가 사용되는 애플리케이션 내의 모든 섹션을 철저히 검토합니다. 사용자에게 표시되는 세부 권한 동의 화면을 활성화할 때 여러 범위를 요청하는 항목에 주의하세요. 이러한 경우 사용자가 일부 범위만 승인하는 사례를 코드가 처리할 수 있는지 확인하세요.
애플리케이션에서 여러 범위를 사용하는지 확인하는 방법
앱 코드 또는 아웃바운드 네트워크 호출을 검사하여 앱에서 실행하는 Google OAuth 2.0 승인 요청으로 인해 세부 권한 동의 화면이 표시되는지 확인합니다.
애플리케이션 코드 검사
Google OAuth 승인 엔드포인트를 호출하여 사용자에게 권한을 요청하는 애플리케이션 코드 섹션을 검토합니다. Google API 클라이언트 라이브러리 중 하나를 사용하는 경우 클라이언트 초기화 단계에서 애플리케이션이 요청하는 범위를 확인할 수 있는 경우가 많습니다. 다음 섹션에 몇 가지 예가 나와 있습니다. 다음 예에 표시된 안내를 참고하여 애플리케이션이 영향을 받는지 확인하려면 애플리케이션에서 Google OAuth 2.0을 처리하는 데 사용하는 SDK의 문서를 참고해야 합니다.
Google ID 서비스
다음 Google ID 서비스 JavaScript 라이브러리 코드 스니펫은 로그인 외 범위가 여러 개 있는 TokenClient
를 초기화합니다. 웹 앱이 사용자에게 승인을 요청하면 세분화된 권한 동의 화면이 표시됩니다.
const client = google.accounts.oauth2.initTokenClient({ client_id: 'YOUR_CLIENT_ID', scope: 'https://www.googleapis.com/auth/calendar.readonly \ https://www.googleapis.com/auth/contacts.readonly', callback: (response) => { ... }, });
Python
다음 코드 스니펫은 google-auth-oauthlib.flow
모듈을 사용하여 승인 요청을 구성합니다. scope
매개변수에는 로그인하지 않는 범위가 두 개 포함됩니다. 웹 애플리케이션이 사용자에게 승인을 요청하면 세분화된 권한 동의 화면이 표시됩니다.
import google.oauth2.credentials import google_auth_oauthlib.flow # Use the client_secret.json file to identify the application requesting # authorization. The client ID (from that file) and access scopes are required. flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file( 'client_secret.json', scopes=['https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/contacts.readonly'])
Node.js
다음 코드 스니펫은 google.auth.OAuth2
객체를 만듭니다. 이 객체는 승인 요청의 매개변수를 정의하며, 이 매개변수의 scope
매개변수에는 로그인하지 않는 범위가 두 개 포함됩니다. 세분화된 권한 동의 화면은 웹 앱이 사용자에게 승인을 요청할 때 표시됩니다.
const {google} = require('googleapis'); /** * To use OAuth2 authentication, we need access to a CLIENT_ID, CLIENT_SECRET, AND REDIRECT_URI * from the client_secret.json file. To get these credentials for your application, visit * https://console.cloud.google.com/apis/credentials. */ const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for read-only Calendar and Contacts. const scopes = [ 'https://www.googleapis.com/auth/calendar.readonly', 'https://www.googleapis.com/auth/contacts.readonly'] ]; // Generate a url that asks permissions const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', /** Pass in the scopes array defined above. * Alternatively, if only one scope is needed, you can pass a scope URL as a string */ scope: scopes, // Enable incremental authorization. Recommended as best practices. include_granted_scopes: true });
나가는 네트워크 호출 검사
- 웹 애플리케이션 - Chrome에서 네트워크 활동 검사
- Android - 네트워크 검사기로 네트워크 트래픽 검사
-
Chrome 앱
- Chrome 확장 프로그램 페이지로 이동합니다.
- 확장 프로그램 페이지의 오른쪽 상단에 있는 개발자 모드 체크박스를 선택합니다.
- 모니터링할 확장 프로그램을 선택합니다.
- 확장 프로그램 페이지의 뷰 검사 섹션에서 백그라운드 페이지 링크를 클릭합니다.
- 개발자 도구 팝업이 열리면 네트워크 탭에서 네트워크 트래픽을 모니터링할 수 있습니다.
- iOS - Instruments로 HTTP 트래픽 분석
- 유니버설 Windows 플랫폼 (UWP) - Visual Studio에서 네트워크 트래픽 검사
- 데스크톱 앱 - 앱이 개발된 운영체제에서 사용할 수 있는 네트워크 캡처 도구를 사용합니다.
네트워크 호출을 검사하는 동안 Google OAuth 승인 엔드포인트로 전송된 요청을 찾아 scope
매개변수를 검사합니다.
이러한 값은 세부 권한 동의 화면이 표시되도록 합니다.
scope
매개변수에는 로그인 범위와 비로그인 범위가 포함됩니다.다음 샘플 요청에는 사용자의 Google Drive 파일의 메타데이터를 보기 위한 3개의 로그인 범위와 1개의 비로그인 범위가 포함되어 있습니다.
https://accounts.google.com/o/oauth2/v2/auth? access_type=offline& scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile%20openid%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly& include_granted_scopes=true& response_type=code& redirect_uri=YOUR_REDIRECT_URL& client_id=YOUR_CLIENT_ID
scope
매개변수에 로그인 이외의 범위가 두 개 이상 포함되어 있습니다.다음 샘플 요청에는 사용자의 Google Drive 메타데이터를 보고 특정 Google Drive 파일을 관리하는 두 개의 로그인하지 않는 범위가 포함되어 있습니다.
https://accounts.google.com/o/oauth2/v2/auth? access_type=offline& scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.file& include_granted_scopes=true& response_type=code& redirect_uri=YOUR_REDIRECT_URL& client_id=YOUR_CLIENT_ID
세부 권한 처리를 위한 권장사항
세부 권한을 처리하기 위해 애플리케이션을 업데이트해야 한다고 판단하는 경우 여러 범위의 동의를 적절하게 처리하도록 코드에 필요한 업데이트를 해야 합니다. 모든 애플리케이션은 다음 권장사항을 준수해야 합니다.
- Google API 서비스: 사용자 데이터 정책을 검토하고 이를 준수해야 합니다.
- 작업에 필요한 특정 범위를 요청합니다. 필요한 범위만 요청하는 Google OAuth 2.0 정책을 준수해야 합니다. 앱의 핵심 기능에 필수적이지 않은 한 로그인 시 여러 범위를 요청하지 않는 것이 좋습니다. 특히 애플리케이션의 기능에 익숙하지 않은 신규 사용자의 경우 여러 범위를 함께 번들로 묶으면 이러한 권한의 필요성을 이해하기 어려울 수 있습니다. 이로 인해 알람이 발생하고 사용자가 애플리케이션과 더 이상 상호작용하지 않을 수 있습니다.
- 승인 요청을 요청하기 전에 사용자에게 근거를 제공합니다. 애플리케이션에 요청된 권한이 필요한 이유, 사용자 데이터로 무엇을 할 것인지, 사용자가 요청을 승인하면 어떤 이점이 있는지 명확하게 설명합니다. Google의 연구에 따르면 이러한 설명은 사용자 신뢰도와 참여도를 높이는 것으로 나타났습니다.
- 애플리케이션에서 여러 액세스 토큰을 관리하지 않도록 범위를 요청할 때는 언제든지 점진적 승인을 사용하세요.
- 사용자가 부여한 범위를 확인합니다. 한 번에 여러 범위를 요청할 때 사용자가 앱에서 요청하는 모든 범위를 부여하지 않을 수 있습니다. 앱은 항상 사용자가 부여한 범위를 확인하고 관련 기능을 사용 중지하여 범위 거부를 처리해야 합니다. 여러 범위에 대한 동의 처리에 관한 Google OAuth 2.0 정책을 따르고, 범위가 필요한 특정 기능을 사용하겠다는 의사를 명확하게 표시한 경우에만 사용자에게 동의를 다시 요청하세요.
세부 권한을 처리하도록 애플리케이션 업데이트
Android 애플리케이션
Google OAuth 2.0과 상호작용하는 데 사용하는 SDK의 문서를 참고하여 권장사항에 따라 세부적인 권한을 처리하도록 애플리케이션을 업데이트해야 합니다.
Google OAuth 2.0과 상호작용하기 위해 Play 서비스의 auth.api.signin SDK를 사용하는 경우 requestPermissions
함수를 사용하여 필요한 최소 범위 집합을 요청하고 hasPermissions
함수를 사용하여 세부 권한을 요청할 때 사용자가 부여한 범위를 확인할 수 있습니다.
Chrome 확장 프로그램 애플리케이션
권장사항에 따라 Google OAuth 2.0을 사용하려면 Chrome ID API를 사용해야 합니다.
다음 예는 세부 권한을 올바르게 처리하는 방법을 보여줍니다.
manifest.json
예시 매니페스트 파일은 Chrome 확장 프로그램 애플리케이션에 대해 로그인하지 않는 범위 두 개를 선언합니다.
{ "name": "Example Chrome extension application", ... "permissions": [ "identity" ], "oauth2" : { "client_id": "YOUR_CLIENT_ID", "scopes":["https://www.googleapis.com/auth/calendar.readonly", "https://www.googleapis.com/auth/contacts.readonly"] } }
잘못된 접근 방식
전부 또는 전무
사용자가 버튼을 클릭하여 승인 프로세스를 시작합니다. 이 코드 스니펫은 사용자에게 manifest.json
파일에 지정된 두 범위에 대한 '전체 또는 없음' 동의 화면이 표시된다고 가정합니다. 사용자가 부여한 범위를 확인하지 않습니다.
oauth.js
... document.querySelector('button').addEventListener('click', function () { chrome.identity.getAuthToken({ interactive: true }, function (token) { if (token === undefined) { // User didn't authorize both scopes. // Updating the UX and application accordingly ... } else { // User authorized both or one of the scopes. // It neglects to check which scopes users granted and assumes users granted all scopes. // Calling the APIs, etc. ... } }); });
올바른 접근 방식
가장 작은 범위
필요한 최소 범위 집합 선택
애플리케이션은 필요한 최소한의 범위만 요청해야 합니다. 애플리케이션이 작업을 완료하는 데 필요한 경우 한 번에 하나의 범위를 요청하는 것이 좋습니다.
이 예에서는 manifest.json
파일에 선언된 두 범위가 모두 필요한 최소 범위 집합이라고 가정합니다. oauth.js
파일은 Chrome ID API를 사용하여 Google과의 승인 프로세스를 시작합니다. 사용자가 애플리케이션에 권한을 부여하는 방식을 더 세밀하게 제어할 수 있도록
세부 권한을 사용 설정해야 합니다. 사용자가 승인한 범위를 확인하여 애플리케이션이 사용자의 응답을 적절하게 처리해야 합니다.
oauth.js
... document.querySelector('button').addEventListener('click', function () { chrome.identity.getAuthToken({ interactive: true, enableGranularPermissions: true }, function (token, grantedScopes) { if (token === undefined) { // User didn't authorize any scope. // Updating the UX and application accordingly ... } else { // User authorized the request. Now, check which scopes were granted. if (grantedScopes.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. ... } else { // User didn't authorize Calendar read permission. // Update UX and application accordingly ... } if (grantedScopes.includes('https://www.googleapis.com/auth/contacts.readonly')) { // User authorized Contacts read permission. // Calling the APIs, etc. ... } else { // User didn't authorize Contacts read permission. // Update UX and application accordingly ... } } }); });
iOS, iPadOS, macOS 애플리케이션
Google OAuth 2.0과 상호작용하는 데 사용하는 SDK의 문서를 참고하여 권장사항에 따라 세부적인 권한을 처리하도록 애플리케이션을 업데이트해야 합니다.
Google Sign-In for iOS and macOS 라이브러리를 사용하여 Google OAuth 2.0과 상호작용하는 경우 세부 권한 처리에 관한 문서를 검토해야 합니다.
웹 애플리케이션
Google OAuth 2.0과 상호작용하는 데 사용하는 SDK의 문서를 참고하여 권장사항에 따라 세부적인 권한을 처리하도록 애플리케이션을 업데이트해야 합니다.
서버 측 (오프라인) 액세스
- 서버를 설정하고 승인 코드를 수신할 공개적으로 액세스 가능한 엔드포인트를 정의합니다.
- Google Cloud 콘솔의 Clients page 에서 공개 엔드포인트의 리디렉션 URI 를 구성합니다.
다음 코드 스니펫은 로그인하지 않은 범위 2개를 요청하는 NodeJS 예를 보여줍니다. 사용자에게 상세 권한 동의 화면이 표시됩니다.
잘못된 접근 방식
전부 또는 전무
사용자가 승인 URL로 리디렉션됩니다. 이 코드 스니펫은 사용자에게 scopes
배열에 지정된 두 범위에 대한 '전체 또는 없음' 동의 화면이 표시된다고 가정합니다. 사용자가 부여한 범위를 확인하지 않습니다.
main.js
... const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes - Google Calendar and Contacts const scopes = [ 'https://www.googleapis.com/auth/contacts.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; // Generate a url that asks permissions for the Google Calendar and Contacts scopes const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', // Pass in the scopes array defined above scope: scopes, // Enable incremental authorization. Recommended as best practices. include_granted_scopes: true }); async function main() { const server = http.createServer(async function (req, res) { // Example on redirecting user to Google OAuth 2.0 server. if (req.url == '/') { res.writeHead(301, { "Location": authorizationUrl }); } // Receive the callback from Google OAuth 2.0 server. if (req.url.startsWith('/oauth2callback')) { // Handle the Google OAuth 2.0 server response let q = url.parse(req.url, true).query; if (q.error) { // User didn't authorize both scopes. // Updating the UX and application accordingly ... } else { // User authorized both or one of the scopes. // It neglects to check which scopes users granted and assumes users granted all scopes. // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); // Calling the APIs, etc. ... } } res.end(); }).listen(80); }
올바른 접근 방식
가장 작은 범위
필요한 최소 범위 집합 선택
애플리케이션은 필요한 최소한의 범위만 요청해야 합니다. 애플리케이션이 작업을 완료하는 데 필요한 경우 한 번에 하나의 범위를 요청하는 것이 좋습니다. 애플리케이션이 범위를 요청할 때는 여러 액세스 토큰을 관리하지 않도록 점진적 승인을 사용해야 합니다.
애플리케이션에서 여러 개의 로그인 외 범위를 요청해야 하는 경우 요청할 때 항상 점진적 승인을 사용하고 사용자가 부여한 범위를 확인해야 합니다.
이 예에서는 앱이 제대로 작동하려면 명시된 두 범위가 모두 필요하다고 가정합니다. 사용자가 애플리케이션에 권한을 부여하는 방식을 더 세밀하게 제어할 수 있도록 세부 권한을 사용 설정해야 합니다. 애플리케이션은 사용자가 승인한 범위를 확인하여 사용자로부터의 응답을 적절하게 처리해야 합니다.
main.js
... const oauth2Client = new google.auth.OAuth2( YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REDIRECT_URL ); // Access scopes for two non-Sign-In scopes - Google Calendar and Contacts const scopes = [ 'https://www.googleapis.com/auth/contacts.readonly', 'https://www.googleapis.com/auth/calendar.readonly' ]; // Generate a url that asks permissions for the Google Calendar and Contacts scopes const authorizationUrl = oauth2Client.generateAuthUrl({ // 'online' (default) or 'offline' (gets refresh_token) access_type: 'offline', // Pass in the scopes array defined above scope: scopes, // Enable incremental authorization. Recommended as best practices. include_granted_scopes: true, // Set to true to enable more granular permissions for Google OAuth 2.0 client IDs created before 2019. // No effect for newer Google OAuth 2.0 client IDs, since more granular permissions is always enabled for them. enable_granular_consent: true }); async function main() { const server = http.createServer(async function (req, res) { // Redirect users to Google OAuth 2.0 server. if (req.url == '/') { res.writeHead(301, { "Location": authorizationUrl }); } // Receive the callback from Google OAuth 2.0 server. if (req.url.startsWith('/oauth2callback')) { // Handle the Google OAuth 2.0 server response let q = url.parse(req.url, true).query; if (q.error) { // User didn't authorize both scopes. // Updating the UX and application accordingly ... } else { // Get access and refresh tokens (if access_type is offline) let { tokens } = await oauth2Client.getToken(q.code); oauth2Client.setCredentials(tokens); // User authorized the request. Now, check which scopes were granted. if (tokens.scope.includes('https://www.googleapis.com/auth/calendar.readonly')) { // User authorized Calendar read permission. // Calling the APIs, etc. ... } else { // User didn't authorize Calendar read permission. // Calling the APIs, etc. ... } // Check which scopes user granted the permission to application if (tokens.scope.includes('https://www.googleapis.com/auth/contacts.readonly')) { // User authorized Contacts read permission. // Calling the APIs, etc. ... } else { // User didn't authorize Contacts read permission. // Update UX and application accordingly ... } } } res.end(); }).listen(80); }
서버 기반 애플리케이션에서 Google API에 액세스하는 방법은 서버 측 웹 앱 가이드를 참고하세요.
클라이언트 측 전용 액세스
- Google ID 서비스 JavaScript 라이브러리를 사용하여 Google OAuth 2.0과 상호작용하는 애플리케이션의 경우 세부적인 권한 처리에 관한 이 문서를 검토해야 합니다.
- JavaScript를 사용하여 Google OAuth 2.0 승인 엔드포인트에 직접 호출하는 애플리케이션의 경우 세부적인 권한 처리에 관한 이 문서를 검토해야 합니다.
세부 권한 처리에 관한 업데이트된 애플리케이션 테스트
- 사용자가 권한 요청에 응답할 수 있는 모든 사례와 애플리케이션의 예상 동작을 간략하게 설명합니다. 예를 들어 사용자가 요청된 세 가지 범위 중 두 가지만 승인하는 경우 애플리케이션은 이에 따라 동작해야 합니다.
-
세부 권한이 사용 설정된 애플리케이션을 테스트합니다. 세부적인 권한을 사용 설정하는 방법에는 두 가지가 있습니다.
- 애플리케이션의 OAuth 2.0 동의 화면에서 애플리케이션에 세부 권한이 이미 사용 설정되어 있는지 확인합니다. 또한 테스트 목적으로 Google Cloud 콘솔을 통해 새 웹, Android 또는 iOS Google OAuth 2.0 클라이언트 ID를 만들 수도 있습니다. 이러한 클라이언트 ID에는 항상 세부 권한이 사용 설정되어 있기 때문입니다.
-
Google OAuth
승인 엔드포인트를 호출할 때
enable_granular_consent
매개변수를true
로 설정합니다. 일부 SDK는 이 매개변수를 명시적으로 지원합니다. 다른 경우에는 문서를 확인하여 이 매개변수와 값을 수동으로 추가하는 방법을 알아보세요. 구현에서 매개변수 추가를 지원하지 않는 경우 앞의 항목에 설명된 대로 테스트 목적으로만 Google Cloud 콘솔을 통해 새 웹, Android 또는 iOS Google OAuth 2.0 클라이언트 ID를 만들 수 있습니다.
- 업데이트된 애플리케이션을 테스트할 때는 Workspace 계정 대신 개인 Google 계정 (@gmail.com)을 사용하세요. 이는 도메인 전체 권한 위임이 있거나 신뢰할 수 있음으로 표시된 Workspace Enterprise 앱은 현재 세부 권한 변경사항의 영향을 받지 않기 때문입니다. 따라서 조직의 Workspace 계정으로 테스트하면 의도한 대로 새로운 세부 동의 화면이 표시되지 않을 수 있습니다.