맞춤 토큰 만들기

Firebase는 보안 JSON 웹 토큰(JWT)을 통한 사용자 또는 기기 인증을 허용하므로 인증의 전 과정을 철저히 관리할 수 있습니다. 서버에서 이러한 토큰을 생성하고 클라이언트 기기에 다시 전달한 후 signInWithCustomToken() 메소드를 통해 토큰을 사용하여 인증할 수 있습니다.

이렇게 하려면 사용자 이름과 비밀번호 등의 로그인 사용자 인증 정보를 수신하고 사용자 인증 정보가 올바를 경우 맞춤 JWT를 반환하는 서버 엔드포인트를 만들어야 합니다. 그러면 클라이언트 기기가 서버에서 반환된 맞춤 JWT를 사용하여 Firebase(iOS, Android, )에 인증할 수 있습니다. 인증된 ID는 Firebase 실시간 데이터베이스 및 Cloud Storage 등의 다른 Firebase 서비스에 액세스하는 데 사용됩니다. 또한 Firebase 실시간 데이터베이스 보안 규칙auth 객체 및 Cloud Storage 보안 규칙request.auth 객체에서 JWT의 내용을 확인할 수 있습니다.

Firebase Admin SDK로 맞춤 토큰을 만들 수도 있고, Firebase가 기본적으로 지원하는 않는 언어로 서버가 작성된 경우 타사 JWT 라이브러리를 사용할 수도 있습니다.

시작하기 전에

Firebase Admin SDK로 맞춤 토큰을 만들려면 서비스 계정이 있어야 합니다. 서비스 계정으로 Admin SDK를 초기화하는 자세한 방법은 Admin SDK 설정 안내를 참조하세요.

Firebase Admin SDK를 사용하여 맞춤 토큰 만들기

Firebase Admin SDK에는 맞춤 토큰을 만드는 메소드가 내장되어 있습니다. 가장 간단한 방법은 인증하는 사용자 또는 기기를 고유하게 식별하는 임의의 문자열인 uid를 제공하는 것입니다. 이러한 토큰은 1시간 후에 만료됩니다.

Node.js

var uid = "some-uid";

admin.auth().createCustomToken(uid)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log("Error creating custom token:", error);
  });

자바

String uid = "some-uid";

String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
// Send token back to client

Python

uid = 'some-uid'

custom_token = auth.create_custom_token(uid)

Go

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

token, err := client.CustomToken(ctx, "some-uid")
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

원한다면 맞춤 토큰에 포함할 추가 클레임을 지정할 수도 있습니다. 예를 들어 아래에서는 맞춤 토큰에 premiumAccount 필드를 추가했으며, 보안 규칙의 auth / request.auth 객체에서 이 필드를 확인할 수 있습니다.

Node.js

var uid = "some-uid";
var additionalClaims = {
  premiumAccount: true
};

admin.auth().createCustomToken(uid, additionalClaims)
  .then(function(customToken) {
    // Send token back to client
  })
  .catch(function(error) {
    console.log("Error creating custom token:", error);
  });

자바

String uid = "some-uid";
Map<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);

String customToken = FirebaseAuth.getInstance()
    .createCustomToken(uid, additionalClaims);
// Send token back to client

Python

uid = 'some-uid'
additional_claims = {
    'premiumAccount': True
}

custom_token = auth.create_custom_token(uid, additional_claims)

Go

client, err := app.Auth(context.Background())
if err != nil {
	log.Fatalf("error getting Auth client: %v\n", err)
}

claims := map[string]interface{}{
	"premiumAccount": true,
}

token, err := client.CustomTokenWithClaims(ctx, "some-uid", claims)
if err != nil {
	log.Fatalf("error minting custom token: %v\n", err)
}

log.Printf("Got custom token: %v\n", token)

클라이언트에서 맞춤 토큰으로 로그인

맞춤 토큰을 만들었으면 클라이언트 앱으로 보내야 합니다. 클라이언트 앱은 다음과 같이 signInWithCustomToken()을 호출하여 맞춤 토큰으로 인증을 진행합니다.

iOS

Objective-C
[[FIRAuth auth] signInWithCustomToken:customToken
                           completion:^(FIRAuthDataResult * _Nullable authResult,
                                        NSError * _Nullable error) {
  // ...
}];
Swift
Auth.auth().signIn(withCustomToken: customToken ?? "") { (user, error) in
  // ...
}

Android

mAuth.signInWithCustomToken(mCustomToken)
        .addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
            @Override
            public void onComplete(@NonNull Task<AuthResult> task) {
                if (task.isSuccessful()) {
                    // Sign in success, update UI with the signed-in user's information
                    Log.d(TAG, "signInWithCustomToken:success");
                    FirebaseUser user = mAuth.getCurrentUser();
                    updateUI(user);
                } else {
                    // If sign in fails, display a message to the user.
                    Log.w(TAG, "signInWithCustomToken:failure", task.getException());
                    Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
                            Toast.LENGTH_SHORT).show();
                    updateUI(null);
                }
            }
        });

Unity

auth.SignInWithCustomTokenAsync(custom_token).ContinueWith(task => {
  if (task.IsCanceled) {
    Debug.LogError("SignInWithCustomTokenAsync was canceled.");
    return;
  }
  if (task.IsFaulted) {
    Debug.LogError("SignInWithCustomTokenAsync encountered an error: " + task.Exception);
    return;
  }

  Firebase.Auth.FirebaseUser newUser = task.Result;
  Debug.LogFormat("User signed in successfully: {0} ({1})",
      newUser.DisplayName, newUser.UserId);
});

C++

firebase::Future<firebase::auth::User*> result =
    auth->SignInWithCustomToken(custom_token);

firebase.auth().signInWithCustomToken(token).catch(function(error) {
  // Handle Errors here.
  var errorCode = error.code;
  var errorMessage = error.message;
  // ...
});

인증에 성공하면 사용자가 맞춤 토큰에 포함된 uid에 지정된 계정으로 클라이언트 앱에 로그인하게 됩니다. 지금까지 없었던 계정이라면 해당 사용자의 레코드가 생성됩니다.

다른 로그인 메소드(예: signInWithEmailAndPassword()signInWithCredential())와 동일한 방식으로 Firebase 실시간 데이터베이스 보안 규칙auth 객체 및 Cloud Storage 보안 규칙request.auth 객체에 사용자의 uid가 채워집니다. 이 경우 uid는 맞춤 토큰을 생성할 때 지정한 항목입니다.

데이터베이스 규칙

{
  "rules": {
    "adminContent": {
      ".read": "auth.uid === 'some-uid'"
    }
  }
}

저장소 규칙

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /adminContent/{filename} {
      allow read, write: if request.auth.uid == "some-uid";
    }
  }
}

맞춤 토큰에 추가 클레임이 포함된 경우 규칙의 auth.token(Firebase 실시간 데이터베이스) 또는 request.auth.token(Cloud Storage) 객체에서 이러한 클레임을 참조할 수 있습니다.

데이터베이스 규칙

{
  "rules": {
    "premiumContent": {
      ".read": "auth.token.premiumAccount === true"
    }
  }
}

저장소 규칙

service firebase.storage {
  match /b/<your-firebase-storage-bucket>/o {
    match /premiumContent/{filename} {
      allow read, write: if request.auth.token.premiumAccount == true;
    }
  }
}

타사 JWT 라이브러리로 맞춤 토큰 만들기

백엔드가 공식 Firebase Admin SDK가 없는 언어로 작성되었더라도 맞춤 토큰을 직접 만들 수 있습니다. 우선 해당 언어의 타사 JWT 라이브러리를 검색합니다. 그런 다음 이 JWT 라이브러리를 사용하여 다음과 같은 클레임을 포함하는 JWT를 발행합니다.

맞춤 토큰 클레임
alg 알고리즘 "RS256"
iss 발급자 프로젝트의 서비스 계정 이메일 주소
sub 제목 프로젝트의 서비스 계정 이메일 주소
aud 잠재고객 "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat 발급 시간 UNIX 기점을 기준으로 하는 현재 시간(초)
exp 만료 시간 UNIX 기점을 기준으로 하는 토큰 만료 시간(초). iat보다 최대 3600초까지 길어질 수 있습니다.
참고: 이 항목은 맞춤 토큰 자체의 만료 시간만 제어합니다. signInWithCustomToken()으로 사용자가 로그인한 후에는 세션이 무효화되거나 사용자가 로그아웃할 때까지 기기에서 로그인 상태가 유지됩니다.
uid 로그인한 사용자의 고유 식별자(1~36자의 길이의 문자열)
claims(선택사항) 보안 규칙의 auth / request.auth 변수에 포함할 선택적인 맞춤 클레임

다음은 Firebase Admin SDK가 지원되지 않는 몇 가지 언어에서 맞춤 토큰을 만드는 방법을 구현한 예입니다.

PHP

php-jwt 사용:

// Requires: composer require firebase/php-jwt
use Firebase\JWT\JWT;

// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";

function create_custom_token($uid, $is_premium_account) {
  global $service_account_email, $private_key;

  $now_seconds = time();
  $payload = array(
    "iss" => $service_account_email,
    "sub" => $service_account_email,
    "aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
    "iat" => $now_seconds,
    "exp" => $now_seconds+(60*60),  // Maximum expiration time is one hour
    "uid" => $uid,
    "claims" => array(
      "premium_account" => $is_premium_account
    )
  );
  return JWT::encode($payload, $private_key, "RS256");
}

Ruby

ruby-jwt 사용:

require "jwt"

# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."

def create_custom_token(uid, is_premium_account)
  now_seconds = Time.now.to_i
  payload = {:iss => $service_account_email,
             :sub => $service_account_email,
             :aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
             :iat => now_seconds,
             :exp => now_seconds+(60*60), # Maximum expiration time is one hour
             :uid => uid,
             :claims => {:premium_account => is_premium_account}}
  JWT.encode payload, $private_key, "RS256"
end

맞춤 토큰을 생성한 후에는 이 토큰을 Firebase 인증에 사용할 수 있도록 클라이언트 앱으로 전송합니다. 그 방법은 위 코드 샘플을 참조하세요.

다음에 대한 의견 보내기...

도움이 필요하시나요? 지원 페이지를 방문하세요.