IAP(Identity-Aware Proxy)로 외부 ID를 사용하려면 앱에 로그인 페이지가 필요합니다. IAP는 사용자를 보안 리소스에 액세스하기 전에 이 페이지로 리디렉션하여 인증합니다.
이 문서에서는 오픈소스 자바스크립트 라이브러리인 FirebaseUI를 사용하여 인증 페이지를 빌드하는 방법을 보여줍니다. FirebaseUI는 상용구 코드를 줄일 수 있는 맞춤설정 가능한 요소를 제공하고, 다양한 ID 공급업체를 통해 사용자 로그인 과정을 처리합니다.
더 빠른 시작을 위해 IAP가 UI를 호스팅하도록 합니다. 이렇게 하면 코드를 추가로 작성하지 않고도 외부 ID를 사용해 볼 수 있습니다. 고급 시나리오의 경우 자체 로그인 페이지를 처음부터 빌드할 수도 있습니다. 이 옵션은 더 복잡하지만 인증 흐름 및 사용자 환경을 완전히 제어할 수 있습니다.
시작하기 전에
외부 ID를 사용설정하고 설정 중에 자체 UI 제공 옵션을 선택합니다.
라이브러리 설치
gcip-iap
, firebase
, firebaseui
라이브러리를 설치합니다. gcip-iap
모듈은 앱, IAP, Identity Platform 간의 통신을 추상화합니다. firebase
및 firebaseui
라이브러리는 인증 UI의 구성 요소를 제공합니다.
npm install firebase --save
npm install firebaseui --save
npm install gcip-iap --save
CDN을 사용하여 gcip-iap
모듈을 사용할 수 없습니다.
그런 다음 소스 파일에서 모듈을 import
할 수 있습니다. SDK 버전에 맞는 가져오기를 사용합니다.
gcip-iap v0.1.4 이하
// Import firebase modules.
import * as firebase from "firebase/app";
import "firebase/auth";
// Import firebaseui module.
import * as firebaseui from 'firebaseui'
// Import gcip-iap module.
import * as ciap from 'gcip-iap';
gcip-iap v1.0.0 이상
버전 v1.0.0부터는 gcip-iap
에 firebase
v9 이상의 피어 종속 항목이 필요합니다.
gcip-iap
v1.0.0 이상으로 마이그레이션하는 경우 다음 작업을 완료합니다.
package.json
파일의firebase
및firebaseui
버전을 각각 v9.6.0 이상 및 v6.0.0 이상으로 업데이트합니다.- 다음과 같이
firebase
import 문을 업데이트합니다.
// Import firebase modules.
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
// Import firebaseui module.
import * as firebaseui from 'firebaseui'
// Import gcip-iap module.
추가 코드 변경은 필요하지 않습니다.
현지화된 버전의 라이브러리 사용을 포함한 추가 설치 옵션은 GitHub에서 안내를 참조하세요.
애플리케이션 구성
FirebaseUI는 인증에 사용할 테넌트 및 공급업체를 지정하는 구성 객체를 사용합니다. 전체 구성은 매우 길 수 있으며 다음과 같이 표시될 수 있습니다.
// The project configuration.
const configs = {
// Configuration for project identified by API key API_KEY1.
API_KEY1: {
authDomain: 'project-id1.firebaseapp.com',
// Decide whether to ask user for identifier to figure out
// what tenant to select or whether to present all the tenants to select from.
displayMode: 'optionFirst', // Or identifierFirst
// The terms of service URL and privacy policy URL for the page
// where the user select tenant or enter email for tenant/provider
// matching.
tosUrl: 'http://localhost/tos',
privacyPolicyUrl: 'http://localhost/privacypolicy',
callbacks: {
// The callback to trigger when the selection tenant page
// or enter email for tenant matching page is shown.
selectTenantUiShown: () => {
// Show title and additional display info.
},
// The callback to trigger when the sign-in page
// is shown.
signInUiShown: (tenantId) => {
// Show tenant title and additional display info.
},
beforeSignInSuccess: (user) => {
// Do additional processing on user before sign-in is
// complete.
return Promise.resolve(user);
}
},
tenants: {
// Tenant configuration for tenant ID tenantId1.
tenantId1: {
// Full label, display name, button color and icon URL of the
// tenant selection button. Only needed if you are
// using the option first option.
fullLabel: 'ACME Portal',
displayName: 'ACME',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// Sign-in providers enabled for tenantId1.
signInOptions: [
// Microsoft sign-in.
{
provider: 'microsoft.com',
providerName: 'Microsoft',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
loginHintKey: 'login_hint'
},
// Email/password sign-in.
{
provider: 'password',
// Do not require display name on sign up.
requireDisplayName: false,
disableSignUp: {
// Disable user from signing up with email providers.
status: true,
adminEmail: 'admin@example.com',
helpLink: 'https://www.example.com/trouble_signing_in'
}
},
// SAML provider. (multiple SAML providers can be passed)
{
provider: 'saml.my-provider1',
providerName: 'SAML provider',
fullLabel: 'Employee Login',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/saml.png'
},
],
// If there is only one sign-in provider eligible for the user,
// whether to show the provider selection page.
immediateFederatedRedirect: true,
signInFlow: 'redirect', // Or popup
// The terms of service URL and privacy policy URL for the sign-in page
// specific to each tenant.
tosUrl: 'http://localhost/tenant1/tos',
privacyPolicyUrl: 'http://localhost/tenant1/privacypolicy'
},
// Tenant configuration for tenant ID tenantId2.
tenantId2: {
fullLabel: 'OCP Portal',
displayName: 'OCP',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// Tenant2 supports a SAML, OIDC and Email/password sign-in.
signInOptions: [
// Email/password sign-in.
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
// Do not require display name on sign up.
requireDisplayName: false
},
// SAML provider. (multiple SAML providers can be passed)
{
provider: 'saml.my-provider2',
providerName: 'SAML provider',
fullLabel: 'Contractor Portal',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/saml.png'
},
// OIDC provider. (multiple OIDC providers can be passed)
{
provider: 'oidc.my-provider1',
providerName: 'OIDC provider',
buttonColor: '#4666FF',
iconUrl: 'https://www.example.com/photos/my_idp/oidc.png'
},
],
},
// Tenant configuration for tenant ID tenantId3.
tenantId3: {
fullLabel: 'Tenant3 Portal',
displayName: 'Tenant3',
buttonColor: '#007bff',
iconUrl: '<icon-url-of-sign-in-button>',
// Tenant3 supports a Google and Email/password sign-in.
signInOptions: [
// Email/password sign-in.
{
provider: firebase.auth.EmailAuthProvider.PROVIDER_ID,
// Do not require display name on sign up.
requireDisplayName: false
},
// Google provider.
{
provider: 'google.com',
scopes: ['scope1', 'scope2', 'https://example.com/scope3'],
loginHintKey: 'login_hint',
customParameters: {
prompt: 'consent',
},
},
],
// Sets the adminRestrictedOperation configuration for providers
// including federated, email/password, email link and phone number.
adminRestrictedOperation: {
status: true,
adminEmail: 'admin@example.com',
helpLink: 'https://www.example.com/trouble_signing_in'
}
},
},
},
};
다음 섹션에서는 IAP 관련 필드를 구성하는 방법을 안내합니다. 다른 필드를 설정하는 예는 위의 코드 스니펫 또는 GitHub의 FirebaseUI 문서를 참조하세요.
API 키 설정
일반적인 구성은 프로젝트의 API 키로 시작합니다.
// The project configuration.
const configs = {
// Configuration for API_KEY.
API_KEY: {
// Config goes here
}
}
대부분의 경우 단일 API 키만 지정하면 됩니다. 그러나 여러 프로젝트에서 단일 인증 URL을 사용하려는 경우 여러 API 키를 포함할 수 있습니다.
const configs = {
API_KEY1: {
// Config goes here
},
API_KEY2: {
// Config goes here
},
}
인증 도메인 가져오기
제휴 로그인을 용이하게 하려면 authdomain
필드를 프로비저닝된 도메인으로 설정합니다. Google Cloud 콘솔의 Identity Platform 페이지에서 이 필드를 가져올 수 있습니다.
테넌트 ID 지정
구성에는 사용자가 인증할 수 있는 테넌트 및 공급업체 목록이 필요합니다.
각 테넌트는 해당 ID로 식별됩니다. 프로젝트 수준의 인증(테넌트 없음)을 사용하는 경우 특수 _
식별자를 API 키로 대신 사용하세요. 예를 들면 다음과 같습니다.
const configs = {
// Configuration for project identified by API key API_KEY1.
API_KEY1: {
tenants: {
// Project-level IdPs flow.
_: {
// Tenant config goes here
},
// Single tenant flow.
1036546636501: {
// Tenant config goes here
}
}
}
}
*
연산자를 사용하여 와일드 카드 테넌트 구성을 지정할 수도 있습니다.
일치하는 ID가 없으면 이 테넌트가 대체로 사용됩니다.
테넌트 공급업체 구성
각 테넌트는 signInOptions
필드에 지정되는 자체 공급업체가 있습니다.
tenantId1: {
signInOptions: [
// Options go here
]
}
공급업체 구성 방법에 대해서는 FirebaseUI 설명서에서 로그인 공급업체 구성을 참조하세요.
FirebaseUI 설명서에 요약된 단계 외에도 선택한 테넌트 선택 모드에 따라 IAP와 관련된 몇 가지 필드가 있습니다. 이 필드에 대한 자세한 내용은 다음 섹션을 참조하세요.
테넌트 선정 모드 선택
사용자는 옵션 우선 모드 또는 식별자 우선 모드의 두 가지 방법으로 테넌트를 선택할 수 있습니다.
옵션 모드에서 사용자는 목록에서 테넌트를 선택하여 시작한 다음 사용자 이름과 비밀번호를 입력합니다. 식별자 모드에서는 사용자가 이메일을 먼저 입력합니다. 그러면 시스템에서 이메일 도메인과 일치하는 ID 공급업체가 있는 첫 번째 테넌트를 자동으로 선택합니다.
옵션 모드를 사용하려면 displayMode
를 optionFirst
로 설정하세요. 그런 다음 displayName
, buttonColor
, iconUrl
을 포함하여 각 테넌트 버튼에 대한 구성 정보를 제공해야 합니다. 선택사항인 fullLabel
를 제공하여 표시 이름만 표시하는 대신 전체 버튼 라벨을 재정의할 수도 있습니다.
다음은 옵션 모드를 사용하도록 구성된 테넌트의 예시입니다.
tenantId1: {
fullLabel: 'ACME Portal',
displayName: 'ACME',
buttonColor: '#2F2F2F',
iconUrl: '<icon-url-of-sign-in-button>',
// ...
식별자 모드를 사용하려면 각 로그인 옵션이 지원하는 도메인을 나타내는 hd
필드를 지정해야 합니다. 이는 정규식(예: /@example\.com$/
) 또는 도메인 문자열(예: example.com
).
아래 코드는 식별자 모드를 사용하도록 구성된 테넌트를 보여줍니다.
tenantId1: {
signInOptions: [
// Email/password sign-in.
{
hd: 'acme.com', // using regex: /@acme\.com$/
// ...
},
즉각적인 리디렉션 사용 설정
앱이 단일 ID 공급업체만 지원하는 경우 immediateFederatedRedirect
를 true
로 설정하면 로그인 UI를 건너뛰고 사용자를 공급업체로 직접 리디렉션합니다.
콜백 설정
구성 객체에는 인증 흐름 중에 다양한 지점에서 호출되는 콜백 집합이 포함됩니다. 이렇게 하면 UI를 추가로 맞춤설정할 수 있습니다. 다음 후크를 사용할 수 있습니다.
selectTenantUiShown() |
테넌트를 선택하기 위한 UI가 표시될 때 트리거됩니다. 맞춤설정된 제목 또는 테마로 UI를 수정하려는 경우 이를 사용하세요. |
signInUiShown(tenantId) |
테넌트가 선택되고 사용자가 사용자 인증 정보를 입력할 수 있는 UI가 표시될 때 트리거됩니다. 맞춤설정된 제목 또는 테마로 UI를 수정하려는 경우 이를 사용하세요. |
beforeSignInSuccess(user) |
로그인이 완료되기 전에 트리거됩니다. IAP 리소스로 다시 리디렉션하기 전에 로그인한 사용자를 수정할 수 있습니다. |
다음 예시 코드는 이러한 콜백을 구현하는 방법을 보여줍니다.
callbacks: {
selectTenantUiShown: () => {
// Show info of the IAP resource.
showUiTitle(
'Select your employer to access your Health Benefits');
},
signInUiShown: (tenantId) => {
// Show tenant title and additional display info.
const tenantName = getTenantNameFromId(tenantId);
showUiTitle(`Sign in to access your ${tenantName} Health Benefits`);
},
beforeSignInSuccess: (user) => {
// Do additional processing on user before sign-in is
// complete.
// For example update the user profile.
return user.updateProfile({
photoURL: 'https://example.com/profile/1234/photo.png',
}).then(function() {
// To reflect updated photoURL in the ID token, force token
// refresh.
return user.getIdToken(true);
}).then(function() {
return user;
});
}
}
라이브러리 초기화
구성 객체를 만든 후에는 다음 단계에 따라 인증 페이지에서 라이브러리를 초기화합니다.
UI를 렌더링할 HTML 컨테이너를 만듭니다.
<!DOCTYPE html> <html> <head>...</head> <body> <!-- The surrounding HTML is left untouched by FirebaseUI. Your app may use that space for branding, controls and other customizations.--> <h1>Welcome to My Awesome App</h1> <div id="firebaseui-auth-container"></div> </body> </html>
HTML 컨테이너에서 렌더링할
FirebaseUiHandler
인스턴스를 만들고 만든config
요소를 전달합니다.const configs = { // ... } const handler = new firebaseui.auth.FirebaseUiHandler( '#firebaseui-auth-container', configs);
새
Authentication
인스턴스를 만들고 핸들러를 전달한 후start()
를 호출합니다.const ciapInstance = new ciap.Authentication(handler); ciapInstance.start();
애플리케이션을 배포하고 인증 페이지로 이동하세요. 테넌트 및 공급업체가 포함된 로그인 UI가 나타납니다.
다음 단계
- 프로그래매틱 방식으로 Google 이외의 리소스에 액세스하는 방법에 대해 알아보세요.
- 세션 관리에 대해 알아보세요.
- 외부 ID가 IAP와 어떻게 작동하는지에 대해 자세히 알아보세요.