Cho phép gửi yêu cầu

Các yêu cầu được gửi đến FCM từ máy chủ ứng dụng hoặc môi trường đáng tin cậy của bạn phải được uỷ quyền. Hãy lưu ý những điểm khác biệt quan trọng sau đây giữa API HTTP cũ không dùng nữa và việc uỷ quyền API HTTP phiên bản 1:

  • API FCM HTTP phiên bản 1 uỷ quyền cho các yêu cầu bằng mã truy cập OAuth 2.0 có thời hạn ngắn. Để tạo mã thông báo này, bạn có thể sử dụng Thông tin xác thực mặc định của ứng dụng Google (trong môi trường máy chủ của Google) và/hoặc lấy thông tin xác thực bắt buộc theo cách thủ công từ tệp khoá riêng tư JSON được tạo cho tài khoản dịch vụ. Nếu bạn đang sử dụng Firebase Admin SDK để gửi tin nhắn, thư viện sẽ xử lý mã thông báo cho bạn.
  • Các giao thức cũ không dùng nữa chỉ có thể sử dụng các khoá API có thời gian tồn tại lâu dài lấy được từ bảng điều khiển Firebase.

Uỷ quyền gửi yêu cầu HTTP v1

Tuỳ thuộc vào thông tin chi tiết về môi trường máy chủ, hãy sử dụng kết hợp các chiến lược sau để uỷ quyền cho các yêu cầu máy chủ đến các dịch vụ Firebase:

  • Thông tin xác thực mặc định của ứng dụng trên Google (ADC)
  • Tệp JSON của tài khoản dịch vụ
  • Mã truy cập OAuth 2.0 có thời gian tồn tại ngắn, bắt nguồn từ một tài khoản dịch vụ

Nếu ứng dụng của bạn đang chạy trên Compute Engine, Google Kubernetes Engine, App Engine hoặc Cloud Functions (bao gồm cả Cloud Functions for Firebase), hãy sử dụng Thông tin xác thực mặc định của ứng dụng (ADC). ADC sử dụng tài khoản dịch vụ mặc định hiện có của bạn để lấy thông tin xác thực nhằm uỷ quyền cho các yêu cầu. Ngoài ra, ADC cho phép kiểm thử linh hoạt trên máy thông qua biến môi trường GOOGLE_APPLICATION_CREDENTIALS. Để tự động hoá tối đa quy trình uỷ quyền, hãy sử dụng ADC cùng với các thư viện máy chủ SDK quản trị.

Nếu ứng dụng của bạn đang chạy trên môi trường máy chủ không phải của Google, bạn cần tải tệp JSON của tài khoản dịch vụ xuống từ dự án Firebase. Miễn là bạn có quyền truy cập vào hệ thống tệp chứa tệp khoá riêng tư, bạn có thể sử dụng biến môi trường GOOGLE_APPLICATION_CREDENTIALS để uỷ quyền cho các yêu cầu bằng thông tin xác thực thu thập được theo cách thủ công. Nếu không có quyền truy cập vào tệp như vậy, bạn phải tham chiếu tệp tài khoản dịch vụ trong mã của mình. Bạn cần phải thực hiện việc này một cách cực kỳ cẩn thận do có nguy cơ lộ thông tin xác thực của bạn.

Cung cấp thông tin xác thực bằng ADC

Thông tin xác thực mặc định của ứng dụng Google (ADC) sẽ kiểm tra thông tin xác thực của bạn theo thứ tự sau:

  1. ADC kiểm tra xem biến môi trường GOOGLE_APPLICATION_CREDENTIALS có được đặt hay không. Nếu bạn đặt biến này, ADC sẽ sử dụng tệp tài khoản dịch vụ mà biến này trỏ đến.

  2. Nếu bạn không đặt biến môi trường, ADC sẽ sử dụng tài khoản dịch vụ mặc định mà Compute Engine, Google Kubernetes Engine, App Engine và Cloud Functions cung cấp cho các ứng dụng chạy trên các dịch vụ đó.

  3. Nếu ADC không thể sử dụng một trong hai thông tin xác thực trên, hệ thống sẽ gửi lỗi.

Ví dụ về mã SDK quản trị sau đây minh hoạ chiến lược này. Ví dụ này không chỉ định rõ thông tin xác thực ứng dụng. Tuy nhiên, ADC có thể tìm thông tin xác thực ngầm ẩn miễn là bạn đặt biến môi trường hoặc miễn là ứng dụng đang chạy trên Compute Engine, Google Kubernetes Engine, App Engine hoặc Cloud Functions.

Node.js

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

Java

FirebaseOptions options = FirebaseOptions.builder()
    .setCredentials(GoogleCredentials.getApplicationDefault())
    .setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
    .build();

FirebaseApp.initializeApp(options);

Python

default_app = firebase_admin.initialize_app()

Tiến hành

app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
	log.Fatalf("error initializing app: %v\n", err)
}

C#

FirebaseApp.Create(new AppOptions()
{
    Credential = GoogleCredential.GetApplicationDefault(),
});

Cung cấp thông tin xác thực theo cách thủ công

Các dự án Firebase hỗ trợ tài khoản dịch vụ của Google. Bạn có thể sử dụng tài khoản này để gọi API máy chủ Firebase từ máy chủ ứng dụng hoặc môi trường đáng tin cậy. Nếu đang phát triển mã cục bộ hoặc triển khai ứng dụng tại chỗ, bạn có thể sử dụng thông tin xác thực thu được thông qua tài khoản dịch vụ này để uỷ quyền cho các yêu cầu máy chủ.

Để xác thực tài khoản dịch vụ và uỷ quyền cho tài khoản đó truy cập vào các dịch vụ của Firebase, bạn phải tạo một tệp khoá riêng tư ở định dạng JSON.

Cách tạo tệp khoá riêng tư cho tài khoản dịch vụ:

  1. Trong bảng điều khiển Firebase, hãy mở Settings (Cài đặt) > Service Accounts (Tài khoản dịch vụ).

  2. Nhấp vào Tạo khoá riêng tư mới, rồi xác nhận bằng cách nhấp vào Tạo khoá.

  3. Lưu trữ an toàn tệp JSON chứa khoá.

Khi uỷ quyền thông qua tài khoản dịch vụ, bạn có hai lựa chọn để cung cấp thông tin xác thực cho ứng dụng của mình. Bạn có thể đặt biến môi trường GOOGLE_APPLICATION_CREDENTIALS hoặc truyền rõ ràng đường dẫn đến khoá tài khoản dịch vụ trong mã. Bạn nên chọn phương thức đầu tiên vì phương thức này an toàn hơn.

Cách đặt biến môi trường:

Đặt biến môi trường GOOGLE_APPLICATION_CREDENTIALS thành đường dẫn tệp của tệp JSON chứa khoá tài khoản dịch vụ. Biến này chỉ áp dụng cho phiên shell hiện tại, vì vậy, nếu bạn mở một phiên mới, hãy đặt lại biến.

Linux hoặc macOS

export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"

Windows

Với PowerShell:

$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"

Sau khi bạn hoàn tất các bước trên, Thông tin xác thực mặc định của ứng dụng (ADC) có thể xác định ngầm thông tin xác thực của bạn, cho phép bạn sử dụng thông tin xác thực tài khoản dịch vụ khi kiểm thử hoặc chạy trong môi trường không phải của Google.

Sử dụng thông tin xác thực để tạo mã truy cập

Trừ phi bạn đang sử dụng SDK quản trị để tự động xử lý việc uỷ quyền, bạn sẽ cần tạo mã thông báo truy cập và thêm mã đó để gửi yêu cầu.

Sử dụng thông tin xác thực Firebase cùng với Thư viện xác thực của Google cho ngôn ngữ bạn muốn để truy xuất mã truy cập OAuth 2.0 có thời hạn ngắn:

node.js

 function getAccessToken() {
  return new Promise(function(resolve, reject) {
    const key = require('../placeholders/service-account.json');
    const jwtClient = new google.auth.JWT(
      key.client_email,
      null,
      key.private_key,
      SCOPES,
      null
    );
    jwtClient.authorize(function(err, tokens) {
      if (err) {
        reject(err);
        return;
      }
      resolve(tokens.access_token);
    });
  });
}

Trong ví dụ này, thư viện ứng dụng API của Google xác thực yêu cầu bằng mã thông báo web JSON (JWT). Để biết thêm thông tin, hãy xem bài viết Mã thông báo web JSON.

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = service_account.Credentials.from_service_account_file(
    'service-account.json', scopes=SCOPES)
  request = google.auth.transport.requests.Request()
  credentials.refresh(request)
  return credentials.token

Java

private static String getAccessToken() throws IOException {
  GoogleCredentials googleCredentials = GoogleCredentials
          .fromStream(new FileInputStream("service-account.json"))
          .createScoped(Arrays.asList(SCOPES));
  googleCredentials.refresh();
  return googleCredentials.getAccessToken().getTokenValue();
}

Sau khi mã truy cập của bạn hết hạn, phương thức làm mới mã thông báo sẽ được gọi tự động để truy xuất mã truy cập đã cập nhật.

Để uỷ quyền truy cập vào FCM, hãy yêu cầu phạm vi https://www.googleapis.com/auth/firebase.messaging.

Cách thêm mã truy cập vào tiêu đề yêu cầu HTTP:

Thêm mã thông báo làm giá trị của tiêu đề Authorization ở định dạng Authorization: Bearer <access_token>:

node.js

headers: {
  'Authorization': 'Bearer ' + accessToken
}

Python

headers = {
  'Authorization': 'Bearer ' + _get_access_token(),
  'Content-Type': 'application/json; UTF-8',
}

Java

URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getServiceAccountAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;

Uỷ quyền gửi yêu cầu theo giao thức cũ

Với giao thức HTTP cũ, mỗi yêu cầu phải chứa khoá máy chủ từ thẻ Gửi thông báo qua đám mây của ngăn Cài đặt trên bảng điều khiển Firebase. Đối với XMPP, bạn phải sử dụng cùng một khoá máy chủ để thiết lập kết nối.

Di chuyển khoá máy chủ cũ

Kể từ tháng 3 năm 2020, FCM đã ngừng tạo khoá máy chủ cũ. Các khoá máy chủ cũ hiện có sẽ tiếp tục hoạt động, nhưng bạn nên sử dụng phiên bản khoá mới hơn có nhãn Mã khoá máy chủ trong công cụ Firebase.

Nếu muốn xoá khoá máy chủ cũ hiện có, bạn có thể thực hiện việc này trong bảng điều khiển Google Cloud.

Uỷ quyền cho yêu cầu HTTP

Yêu cầu thông báo bao gồm hai phần: tiêu đề HTTP và nội dung HTTP. Tiêu đề HTTP phải chứa các tiêu đề sau:

  • Authorization: key=YOUR_SERVER_KEY
    Đảm bảo đây là khoá máy chủ, có giá trị trong thẻ Gửi thông báo qua đám mây của ngăn Cài đặt trên bảng điều khiển Firebase. FCM từ chối các khoá Android, nền tảng Apple và trình duyệt.
  • Content-Type: application/json cho JSON; application/x-www-form-urlencoded;charset=UTF-8 cho văn bản thuần tuý.
    Nếu bạn bỏ qua Content-Type, thì định dạng sẽ được giả định là văn bản thuần tuý.

Ví dụ:

Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA

{
  "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
  "data" : {
    ...
  },
}

Hãy xem phần Tạo yêu cầu gửi để biết toàn bộ thông tin chi tiết về cách tạo yêu cầu gửi. Tài liệu tham khảo về giao thức HTTP cũ cung cấp danh sách tất cả các tham số mà thông báo của bạn có thể chứa.

Kiểm tra tính hợp lệ của khoá máy chủ

Nếu bạn nhận được lỗi xác thực khi gửi thư, hãy kiểm tra tính hợp lệ của Khoá máy chủ. Ví dụ: trên Linux, hãy chạy lệnh sau:

api_key=YOUR_SERVER_KEY

curl --header "Authorization: key=$api_key" \
     --header Content-Type:"application/json" \
     https://fcm.googleapis.com/fcm/send \
     -d "{\"registration_ids\":[\"ABC\"]}"

Nếu bạn nhận được mã trạng thái HTTP 401, thì Khoá máy chủ của bạn không hợp lệ.

Uỷ quyền kết nối XMPP

Với XMPP, bạn có thể duy trì một kết nối hai chiều, không đồng bộ và ổn định với các máy chủ FCM. Bạn có thể dùng kết nối này để gửi và nhận thông báo giữa máy chủ và các thiết bị được kết nối với FCM của người dùng.

Bạn có thể sử dụng hầu hết các thư viện XMPP để quản lý kết nối lâu dài với FCM. Điểm cuối XMPP chạy tại fcm-xmpp.googleapis.com:5235. Khi kiểm thử chức năng với người dùng không phải là người dùng chính thức, bạn nên kết nối với máy chủ thử nghiệm tại fcm-xmpp.googleapis.com:5236 (lưu ý cổng khác).

Việc kiểm thử thường xuyên trên bản phát hành trước khi phát hành chính thức (một môi trường nhỏ hơn nơi các bản dựng FCM mới nhất chạy) sẽ giúp tách biệt người dùng thực với mã kiểm thử. Thiết bị kiểm thử và mã kiểm thử kết nối với fcm-xmpp.googleapis.com:5236 phải sử dụng một mã nhận dạng người gửi FCM khác để tránh mọi rủi ro khi gửi thông báo kiểm thử đến người dùng chính thức hoặc gửi thông báo ngược từ lưu lượng truy cập chính thức qua các kết nối kiểm thử.

Kết nối này có hai yêu cầu quan trọng:

  • Bạn phải bắt đầu một kết nối Bảo mật tầng truyền tải (TLS). Xin lưu ý rằng FCM hiện không hỗ trợ tiện ích STARTTLS.
  • FCM yêu cầu cơ chế xác thực SASL PLAIN bằng cách sử dụng <your_FCM_Sender_Id>@fcm.googleapis.com (FCM mã nhận dạng người gửi) và khoá máy chủ làm mật khẩu. Các giá trị này có trong thẻ Cloud Messaging (Thông báo qua đám mây) của ngăn Settings (Cài đặt) trong bảng điều khiển Firebase.

Nếu có bất kỳ lúc nào kết nối không thành công, bạn nên kết nối lại ngay lập tức. Bạn không cần phải lùi lại sau khi bị ngắt kết nối xảy ra sau khi xác thực. Đối với mỗi mã nhận dạng người gửi, FCM cho phép 2500 kết nối song song.

Các đoạn mã sau đây minh hoạ cách xác thực và uỷ quyền cho một kết nối XMPP với FCM.

Máy chủ XMPP

Máy chủ XMPP yêu cầu kết nối với FCM

<stream:stream to="fcm.googleapis.com"
        version="1.0" xmlns="jabber:client"
        xmlns:stream="http://etherx.jabber.org/streams">

FCM

FCM mở kết nối và yêu cầu một cơ chế xác thực, bao gồm cả phương thức PLAIN.

<stream:features>
  <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl">
    <mechanism>X-OAUTH2</mechanism>
    <mechanism>X-GOOGLE-TOKEN</mechanism>
    <mechanism>PLAIN</mechanism>
  </mechanisms>
</stream:features>

Máy chủ XMPP

Máy chủ XMPP phải phản hồi bằng phương thức xác thực PLAIN, cung cấp khoá máy chủ từ thẻ Gửi thông báo qua đám mây của ngăn Cài đặt trong bảng điều khiển Firebase.

<auth mechanism="PLAIN"
xmlns="urn:ietf:params:xml:ns:xmpp-sasl">MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb
mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==</auth>

FCM

<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>

Máy chủ XMPP

<stream:stream to="fcm.googleapis.com"
        version="1.0" xmlns="jabber:client"
        xmlns:stream="http://etherx.jabber.org/streams">

FCM

<stream:features>
  <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/>
  <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/>
</stream:features>

Máy chủ XMPP

<iq type="set">
  <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"></bind>
</iq>

FCM

<iq type="result">
  <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind">
    <jid>SENDER_ID@fcm.googleapis.com/RESOURCE</jid>
  </bind>
</iq>

Lưu ý: FCM không sử dụng tài nguyên đã liên kết trong khi định tuyến thông báo.

Hãy xem phần Tạo yêu cầu gửi để biết toàn bộ thông tin chi tiết về cách tạo yêu cầu gửi. Tài liệu tham khảo về giao thức XMPP cũ cung cấp danh sách tất cả các tham số mà thông báo của bạn có thể chứa.