Nhiều người dùng vẫn quản lý thông tin xác thực của riêng họ khi thiết lập thiết bị Android mới. Quy trình thủ công này có thể khó khăn và thường dẫn đến trải nghiệm người dùng không tốt. Block Store API (API Cửa hàng chặn), một thư viện do các dịch vụ của Google Play cung cấp, tìm cách giải quyết vấn đề này bằng cách cung cấp một phương thức giúp các ứng dụng lưu thông tin xác thực của người dùng mà không gặp phải rủi ro phức tạp hoặc rủi ro bảo mật liên quan đến việc lưu mật khẩu người dùng.
API Cửa hàng chặn cho phép ứng dụng của bạn lưu trữ dữ liệu mà sau này có thể truy xuất để xác thực lại người dùng trên thiết bị mới. Điều này giúp mang lại trải nghiệm liền mạch hơn cho người dùng vì họ không cần phải xem màn hình đăng nhập trong lần đầu tiên chạy ứng dụng trên thiết bị mới.
Sau đây là các lợi ích khi sử dụng tính năng Block Store:
- Giải pháp lưu trữ thông tin xác thực được mã hoá dành cho nhà phát triển. Thông tin xác thực sẽ được mã hoá hai đầu khi có thể.
- Lưu mã thông báo thay cho tên người dùng và mật khẩu.
- Loại bỏ rào cản khi đăng nhập.
- Giúp người dùng tránh được gánh nặng phải quản lý các mật khẩu phức tạp.
- Google xác minh danh tính của người dùng.
Trước khi bắt đầu
Để chuẩn bị cho ứng dụng của bạn, hãy hoàn tất các bước trong những phần sau.
Định cấu hình ứng dụng
Trong tệp build.gradle
cấp dự án, hãy thêm kho lưu trữ Maven của Google vào cả hai mục buildscript
và allprojects
:
buildscript {
repositories {
google()
mavenCentral()
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
Thêm phần phụ thuộc Dịch vụ Google Play dành cho API Block Store vào tệp bản dựng Gradle của mô-đun, thường là app/build.gradle
:
dependencies {
implementation 'com.google.android.gms:play-services-auth-blockstore:16.2.0'
}
Cách thức hoạt động
Block Store cho phép nhà phát triển lưu và khôi phục các mảng lên đến 16 byte. Điều này cho phép bạn lưu thông tin quan trọng liên quan đến phiên người dùng hiện tại và giúp bạn lưu thông tin này theo cách linh hoạt. Dữ liệu này có thể được mã hoá hai đầu và cơ sở hạ tầng hỗ trợ Cửa hàng chặn được xây dựng trên cơ sở hạ tầng Sao lưu và khôi phục.
Hướng dẫn này sẽ đề cập đến trường hợp sử dụng lưu mã thông báo của người dùng vào Block Store. Các bước sau đây phác thảo cách hoạt động của một ứng dụng sử dụng Cửa hàng chặn:
- Trong quy trình xác thực của ứng dụng hoặc bất cứ lúc nào sau đó, bạn có thể lưu trữ mã xác thực của người dùng vào Block Store để truy xuất sau.
- Mã thông báo sẽ được lưu trữ trên thiết bị và cũng có thể được sao lưu vào đám mây, được mã hoá hai đầu khi có thể.
- Dữ liệu được chuyển khi người dùng bắt đầu quy trình khôi phục trên một thiết bị mới.
- Nếu người dùng khôi phục ứng dụng của bạn trong quy trình khôi phục, thì ứng dụng có thể truy xuất mã thông báo đã lưu từ Cửa hàng chặn trên thiết bị mới.
Lưu mã thông báo
Khi người dùng đăng nhập vào ứng dụng của bạn, bạn có thể lưu mã xác thực mà bạn tạo cho người dùng đó vào Chặn Store. Bạn có thể lưu trữ mã thông báo này bằng một giá trị cặp khoá duy nhất có tối đa 4 kb cho mỗi mục nhập.
Để lưu trữ mã thông báo, hãy gọi setBytes()
và setKey()
trên thực thể của StoreBytesData.Builder
để lưu trữ thông tin xác thực của người dùng vào thiết bị nguồn. Sau khi bạn lưu mã thông báo bằng Block Store, mã thông báo sẽ được mã hoá và lưu trữ cục bộ trên thiết bị.
Mẫu sau đây cho biết cách lưu mã thông báo xác thực vào thiết bị cục bộ:
Java
BlockstoreClient client = Blockstore.getClient(this); byte[] bytes1 = new byte[] { 1, 2, 3, 4 }; // Store one data block. String key1 = "com.example.app.key1"; StoreBytesData storeRequest1 = StoreBytesData.Builder() .setBytes(bytes1) // Call this method to set the key value pair the data should be associated with. .setKeys(Arrays.asList(key1)) .build(); client.storeBytes(storeRequest1) .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes")) .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));
Kotlin
val client = Blockstore.getClient(this) val bytes1 = byteArrayOf(1, 2, 3, 4) // Store one data block. val key1 = "com.example.app.key1" val storeRequest1 = StoreBytesData.Builder() .setBytes(bytes1) // Call this method to set the key value with which the data should be associated with. .setKeys(Arrays.asList(key1)) .build() client.storeBytes(storeRequest1) .addOnSuccessListener { result: Int -> Log.d(TAG, "Stored $result bytes") } .addOnFailureListener { e -> Log.e(TAG, "Failed to store bytes", e) }
Sử dụng mã thông báo mặc định
Dữ liệu được lưu bằng StoreBytes mà không có khoá sẽ sử dụng khoá mặc định BlockstoreClient.DEFAULT_ sạc_DATA_KEY.
Java
BlockstoreClient client = Blockstore.getClient(this); // The default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY. byte[] bytes = new byte[] { 9, 10 }; StoreBytesData storeRequest = StoreBytesData.Builder() .setBytes(bytes) .build(); client.storeBytes(storeRequest) .addOnSuccessListener(result -> Log.d(TAG, "stored " + result + " bytes")) .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));
Kotlin
val client = Blockstore.getClient(this); // the default key BlockstoreClient.DEFAULT_BYTES_DATA_KEY. val bytes = byteArrayOf(1, 2, 3, 4) val storeRequest = StoreBytesData.Builder() .setBytes(bytes) .build(); client.storeBytes(storeRequest) .addOnSuccessListener { result: Int -> Log.d(TAG, "stored $result bytes") } .addOnFailureListener { e -> Log.e(TAG, "Failed to store bytes", e) }
Truy xuất mã thông báo
Sau đó, khi người dùng thực hiện quy trình khôi phục trên một thiết bị mới, trước tiên, Dịch vụ Google Play sẽ xác minh người dùng đó rồi truy xuất dữ liệu của bạn trên Block Store. Người dùng đã đồng ý khôi phục dữ liệu ứng dụng của bạn trong
quy trình khôi phục. Vì vậy, bạn không cần phải có sự đồng ý bổ sung. Khi người dùng mở ứng dụng, bạn có thể yêu cầu mã thông báo từ Block Store bằng cách gọi retrieveBytes()
.
Sau đó, mã thông báo đã truy xuất có thể được dùng để duy trì trạng thái đăng nhập của người dùng trên thiết bị mới.
Mẫu sau đây cho biết cách truy xuất nhiều mã thông báo dựa trên các khoá cụ thể.
Java
BlockstoreClient client = Blockstore.getClient(this); // Retrieve data associated with certain keys. String key1 = "com.example.app.key1"; String key2 = "com.example.app.key2"; String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to retrieve data stored without a key ListrequestedKeys = Arrays.asList(key1, key2, key3); // Add keys to array RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder() .setKeys(requestedKeys) .build(); client.retrieveBytes(retrieveRequest) .addOnSuccessListener( result -> { Map blockstoreDataMap = result.getBlockstoreDataMap(); for (Map.Entry entry : blockstoreDataMap.entrySet()) { Log.d(TAG, String.format( "Retrieved bytes %s associated with key %s.", new String(entry.getValue().getBytes()), entry.getKey())); } }) .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));
Kotlin
val client = Blockstore.getClient(this) // Retrieve data associated with certain keys. val key1 = "com.example.app.key1" val key2 = "com.example.app.key2" val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array val retrieveRequest = RetrieveBytesRequest.Builder() .setKeys(requestedKeys) .build() client.retrieveBytes(retrieveRequest) .addOnSuccessListener { result: RetrieveBytesResponse -> val blockstoreDataMap = result.blockstoreDataMap for ((key, value) in blockstoreDataMap) { Log.d(ContentValues.TAG, String.format( "Retrieved bytes %s associated with key %s.", String(value.bytes), key)) } } .addOnFailureListener { e: Exception? -> Log.e(ContentValues.TAG, "Failed to store bytes", e) }
Đang truy xuất tất cả mã thông báo.
Dưới đây là ví dụ về cách truy xuất toàn bộ mã thông báo đã lưu vào BlockStore.
Java
BlockstoreClient client = Blockstore.getClient(this) // Retrieve all data. RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder() .setRetrieveAll(true) .build(); client.retrieveBytes(retrieveRequest) .addOnSuccessListener( result -> { MapblockstoreDataMap = result.getBlockstoreDataMap(); for (Map.Entry entry : blockstoreDataMap.entrySet()) { Log.d(TAG, String.format( "Retrieved bytes %s associated with key %s.", new String(entry.getValue().getBytes()), entry.getKey())); } }) .addOnFailureListener(e -> Log.e(TAG, "Failed to store bytes", e));
Kotlin
val client = Blockstore.getClient(this) val retrieveRequest = RetrieveBytesRequest.Builder() .setRetrieveAll(true) .build() client.retrieveBytes(retrieveRequest) .addOnSuccessListener { result: RetrieveBytesResponse -> val blockstoreDataMap = result.blockstoreDataMap for ((key, value) in blockstoreDataMap) { Log.d(ContentValues.TAG, String.format( "Retrieved bytes %s associated with key %s.", String(value.bytes), key)) } } .addOnFailureListener { e: Exception? -> Log.e(ContentValues.TAG, "Failed to store bytes", e) }
Dưới đây là ví dụ về cách truy xuất khoá mặc định.
Java
BlockStoreClient client = Blockstore.getClient(this); RetrieveBytesRequest retrieveRequest = new RetrieveBytesRequest.Builder() .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY)) .build(); client.retrieveBytes(retrieveRequest);
Kotlin
val client = Blockstore.getClient(this) val retrieveRequest = RetrieveBytesRequest.Builder() .setKeys(Arrays.asList(BlockstoreClient.DEFAULT_BYTES_DATA_KEY)) .build() client.retrieveBytes(retrieveRequest)
Xoá mã thông báo
Bạn có thể phải xoá mã thông báo khỏi BlockStore vì những lý do sau:
- Người dùng sẽ trải qua quy trình đăng xuất.
- Mã thông báo đã bị thu hồi hoặc không hợp lệ.
Tương tự như việc truy xuất mã thông báo, bạn có thể chỉ định những mã thông báo cần xoá bằng cách thiết lập một mảng khoá sẽ yêu cầu xoá.
Dưới đây là ví dụ về cách xoá một số khoá nhất định.
Java
BlockstoreClient client = Blockstore.getClient(this); // Delete data associated with certain keys. String key1 = "com.example.app.key1"; String key2 = "com.example.app.key2"; String key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY; // Used to delete data stored without key ListrequestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array DeleteBytesRequest deleteRequest = new DeleteBytesRequest.Builder() .setKeys(requestedKeys) .build(); client.deleteBytes(deleteRequest)
Kotlin
val client = Blockstore.getClient(this) // Retrieve data associated with certain keys. val key1 = "com.example.app.key1" val key2 = "com.example.app.key2" val key3 = BlockstoreClient.DEFAULT_BYTES_DATA_KEY // Used to retrieve data stored without a key val requestedKeys = Arrays.asList(key1, key2, key3) // Add keys to array val retrieveRequest = DeleteBytesRequest.Builder() .setKeys(requestedKeys) .build() client.deleteBytes(retrieveRequest)
Xoá tất cả mã thông báo
Ví dụ dưới đây sẽ xoá tất cả các mã thông báo hiện đã được lưu vào BlockStore:
Java
// Delete all data. DeleteBytesRequest deleteAllRequest = new DeleteBytesRequest.Builder() .setDeleteAll(true) .build(); client.deleteBytes(deleteAllRequest) .addOnSuccessListener(result -> Log.d(TAG, "Any data found and deleted? " + result));
Kotlin
val deleteAllRequest = DeleteBytesRequest.Builder() .setDeleteAll(true) .build() client.deleteBytes(deleteAllRequest) .addOnSuccessListener { result: Boolean -> Log.d(TAG, "Any data found and deleted? $result") }
Mã hoá hai đầu
Để có thể sử dụng phương thức mã hoá hai đầu, thiết bị phải chạy Android 9 trở lên và người dùng phải đặt phương thức khoá màn hình (mã PIN, hình mở khoá hoặc mật khẩu) cho thiết bị. Bạn có thể xác minh xem tính năng mã hoá có trên thiết bị hay không bằng cách gọi isEndToEndEncryptionAvailable()
.
Mẫu sau đây cho biết cách xác minh xem tính năng mã hoá có hoạt động trong quá trình sao lưu trên đám mây hay không:
client.isEndToEndEncryptionAvailable()
.addOnSuccessListener { result ->
Log.d(TAG, "Will Block Store cloud backup be end-to-end encrypted? $result")
}
Bật tính năng sao lưu trên đám mây
Để bật tính năng sao lưu trên đám mây, hãy thêm phương thức setShouldBackupToCloud()
vào đối tượng StoreBytesData
. Block Store sẽ định kỳ sao lưu vào đám mây các byte được lưu trữ khi
setShouldBackupToCloud()
được đặt là true (đúng).
Mẫu sau đây cho biết cách bật tính năng sao lưu trên đám mây chỉ khi tính năng sao lưu trên đám mây được mã hoá hai đầu:
val client = Blockstore.getClient(this)
val storeBytesDataBuilder = StoreBytesData.Builder()
.setBytes(/* BYTE_ARRAY */)
client.isEndToEndEncryptionAvailable()
.addOnSuccessListener { isE2EEAvailable ->
if (isE2EEAvailable) {
storeBytesDataBuilder.setShouldBackupToCloud(true)
Log.d(TAG, "E2EE is available, enable backing up bytes to the cloud.")
client.storeBytes(storeBytesDataBuilder.build())
.addOnSuccessListener { result ->
Log.d(TAG, "stored: ${result.getBytesStored()}")
}.addOnFailureListener { e ->
Log.e(TAG, “Failed to store bytes”, e)
}
} else {
Log.d(TAG, "E2EE is not available, only store bytes for D2D restore.")
}
}
Cách kiểm tra
Hãy sử dụng các phương thức sau trong quá trình phát triển để kiểm thử quy trình khôi phục.
Gỡ cài đặt/cài đặt lại trên cùng một thiết bị
Nếu người dùng bật Dịch vụ sao lưu (có thể kiểm tra trong phần Cài đặt > Google > Sao lưu), thì dữ liệu của Cửa hàng chặn sẽ được duy trì trong quá trình gỡ cài đặt/cài đặt lại ứng dụng.
Bạn có thể làm theo các bước sau để kiểm tra:
- Tích hợp API BlockStore vào ứng dụng kiểm thử.
- Dùng ứng dụng kiểm thử để gọi API BlockStore để lưu trữ dữ liệu.
- Gỡ cài đặt ứng dụng thử nghiệm rồi cài đặt lại ứng dụng đó trên cùng thiết bị.
- Dùng ứng dụng kiểm thử để gọi API BlockStore nhằm truy xuất dữ liệu của bạn.
- Xác minh rằng các byte được truy xuất giống với các byte được lưu trữ trước khi gỡ cài đặt.
Từ thiết bị đến thiết bị khác
Trong hầu hết các trường hợp, bạn cần phải đặt lại thiết bị đích về trạng thái ban đầu. Sau đó, bạn có thể chuyển đến quy trình khôi phục cho thiết bị Android qua Wi-Fi hoặc Khôi phục cáp của Google (đối với các thiết bị được hỗ trợ).
Khôi phục trên đám mây
- Tích hợp API Blockstore vào ứng dụng kiểm thử. Bạn cần gửi ứng dụng kiểm thử đến Cửa hàng Play.
- Trên thiết bị nguồn, hãy sử dụng ứng dụng kiểm thử để gọi API Blockstore để lưu trữ dữ liệu của bạn, với shouldBackUpToCloud được đặt thành true.
- Đối với các thiết bị chạy Android O trở lên, bạn có thể kích hoạt tính năng sao lưu trên đám mây của Block Store theo cách thủ công: chuyển đến phần Cài đặt > Google > Sao lưu, nhấp vào nút "Sao lưu ngay".
- Để xác minh rằng tính năng sao lưu trên đám mây của Block Store đã thành công, bạn có thể:
- Sau khi sao lưu xong, hãy tìm các dòng nhật ký có thẻ “CloudSyncBpTkSvc”.
- Bạn sẽ thấy các dòng như sau: “......, CloudSyncBpTkSvc: kết quả đồng bộ hóa: THÀNH CÔNG, ..., kích thước đã tải lên: XXX byte ...”
- Sau khi sao lưu trên đám mây ở Block Store, bạn sẽ có khoảng thời gian "để nguội" là 5 phút. Trong vòng 5 phút đó, việc nhấp vào nút "Sao lưu ngay" sẽ không kích hoạt thêm một bản sao lưu trên đám mây khác của Block Store.
- Để xác minh rằng tính năng sao lưu trên đám mây của Block Store đã thành công, bạn có thể:
- Đặt lại thiết bị mục tiêu về trạng thái ban đầu và thực hiện quy trình khôi phục trên đám mây. Chọn để khôi phục ứng dụng kiểm thử trong quy trình khôi phục. Để biết thêm thông tin về các quy trình khôi phục đám mây, hãy xem bài viết Các quy trình khôi phục đám mây được hỗ trợ.
- Trên thiết bị mục tiêu, hãy sử dụng ứng dụng kiểm thử để gọi API Blockstore để truy xuất dữ liệu của bạn.
- Xác minh rằng các byte được truy xuất giống với các byte được lưu trữ trong thiết bị nguồn.
Yêu cầu về thiết bị
Mã hoá hai đầu
- Tính năng mã hoá hai đầu được hỗ trợ trên các thiết bị chạy Android 9 (API 29) trở lên.
- Thiết bị phải đặt phương thức khoá màn hình bằng mã PIN, hình mở khoá hoặc mật khẩu dùng cho tính năng mã hoá hai đầu để được bật và mã hoá chính xác dữ liệu của người dùng.
Quy trình khôi phục thiết bị sang thiết bị
Bạn phải có một thiết bị nguồn và một thiết bị mục tiêu để khôi phục từ thiết bị đó. Đây sẽ là hai thiết bị sẽ truyền dữ liệu.
Các thiết bị nguồn phải chạy Android 6 (API 23) trở lên để được sao lưu.
Nhắm mục tiêu các thiết bị chạy Android 9 (API 29) trở lên để có thể khôi phục.
Bạn có thể xem thêm thông tin về quy trình khôi phục từ thiết bị này sang thiết bị tại đây.
Quy trình sao lưu và khôi phục trên đám mây
Bạn cần có một thiết bị nguồn và một thiết bị đích để sao lưu và khôi phục trên đám mây.
Các thiết bị nguồn phải chạy Android 6 (API 23) trở lên để được sao lưu.
Thiết bị Target được hỗ trợ tuỳ theo nhà cung cấp. Các thiết bị Pixel có thể sử dụng tính năng này trên Android 9 (API 29) và tất cả các thiết bị khác phải chạy Android 12 (API 31) trở lên.