Thêm phần phụ thuộc

Trong tệp build.gradle của ứng dụng, hãy thêm các phần phụ thuộc sau cho Trình quản lý thông tin xác thực:

Kotlin

dependencies {
    implementation("androidx.credentials:credentials:1.7.0-alpha02")
    implementation("androidx.credentials:credentials-play-services-auth:1.7.0-alpha02")
}

Groovy

dependencies {
    implementation "androidx.credentials:credentials:1.7.0-alpha02"
    implementation "androidx.credentials:credentials-play-services-auth:1.7.0-alpha02"
}

Khởi chạy Trình quản lý thông tin xác thực

Sử dụng ngữ cảnh ứng dụng hoặc hoạt động để tạo đối tượng CredentialManager.

// Use your app or activity context to instantiate a client instance of
// CredentialManager.
private val credentialManager = CredentialManager.create(context)

Tạo yêu cầu về Thông tin xác thực kỹ thuật số

Để yêu cầu một email đã xác minh, hãy tạo một GetCredentialRequest chứa GetDigitalCredentialOption. Tuỳ chọn này yêu cầu một chuỗi requestJson được định dạng dưới dạng yêu cầu OpenID cho Bản trình bày có thể xác minh (OpenID4VP).

JSON yêu cầu OpenID4VP phải tuân theo một cấu trúc cụ thể. Các nhà cung cấp hiện tại hỗ trợ cấu trúc JSON có trình bao bọc "digital": {"requests": [...]} bên ngoài.

    val nonce = generateSecureRandomNonce()

    // This request follows the OpenID4VP spec
    val openId4vpRequest = """
{
  "requests": [
    {
      "protocol": "openid4vp-v1-unsigned",
      "data": {
        "response_type": "vp_token",
        "response_mode": "dc_api",
        "nonce": "$nonce",
        "dcql_query": {
          "credentials": [
            {
              "id": "user_info_query",
              "format": "dc+sd-jwt",
               "meta": { 
                  "vct_values": ["UserInfoCredential"] 
               },
              "claims": [ 
                {"path": ["email"]}, 
                {"path": ["name"]},  
                {"path": ["given_name"]},
                {"path": ["family_name"]},
                {"path": ["picture"]},
                {"path": ["hd"]},
                {"path": ["email_verified"]}
              ]
            }
          ]
        }
      }
    }
  ]
}
"""

    val getDigitalCredentialOption = GetDigitalCredentialOption(requestJson = openId4vpRequest)
    val request = GetCredentialRequest(listOf(getDigitalCredentialOption))

Tiếp theo, hãy gói JSON openId4vpRequest trong GetDigitalCredentialOption, tạo GetCredentialRequest và gọi getCredential().

Đưa ra yêu cầu cho người dùng

Cho người dùng xem yêu cầu bằng giao diện người dùng tích hợp sẵn của Trình quản lý thông tin xác thực.

try {
    // Requesting Digital Credential from user...
    val result = credentialManager.getCredential(activity, request)

    when (val credential = result.credential) {
        is DigitalCredential -> {
            val responseJsonString = credential.credentialJson

            // Successfully received digital credential response.

            // Next, parse this response and send it to your server.
            // ...
        }

        else -> {
            // handle Unexpected State() - Up to the developer
        }
    }
} catch (e: Exception) {
    // handle exceptions - Up to the developer
}

Phân tích cú pháp phản hồi trên ứng dụng

Sau khi nhận được phản hồi, bạn có thể phân tích sơ bộ trên máy khách. Điều này hữu ích cho việc cập nhật ngay giao diện người dùng, chẳng hạn như bằng cách cho thấy tên của người dùng.

Đoạn mã sau đây trích xuất JWT công bố có chọn lọc (SD-JWT) thô và sử dụng một trình trợ giúp để giải mã các khai báo của JWT này.

// 1. Parse the outer JSON wrapper to get the `vp_token`
val responseData = JSONObject(responseJsonString)
val vpToken = responseData.getJSONObject("vp_token")

// 2. Extract the raw SD-JWT string
val credentialId = vpToken.keys().next()
val rawSdJwt = vpToken.getJSONArray(credentialId).getString(0)

// 3. Use your parser to get the verified claims
// Server-side validation/parsing is highly recommended.

// Assumes a local parser like the one in our SdJwtParser.kt sample
val claims = SdJwtParser.parse(rawSdJwt)
Log.d("TAG", "Parsed Claims: ${claims.toString(2)}")

// 4. Create your VerifiedUserInfo object with REAL data
val userInfo = VerifiedUserInfo(
    email = claims.getString("email"),
    displayName = claims.optString("name", claims.getString("email"))
)

Xử lý phản hồi

Credential Manager API sẽ trả về một phản hồi DigitalCredential.

Sau đây là ví dụ về responseJsonString thô và các xác nhận quyền sở hữu sau khi phân tích cú pháp SD-JWT bên trong, trong đó bạn cũng nhận được siêu dữ liệu bổ sung cùng với email đã xác minh:

/*
// Example of the raw JSON response from credential.credentialJson:
{
  "vp_token": {
    // This key matches the 'id' you set in your dcql_query
    "user_info_query": [
      // The SD-JWT string (Issuer JWT ~ Disclosures ~ Key Binding JWT)
      "eyJhbGciOiJ...~WyI...IiwgImVtYWlsIiwgInVzZXJAZXhhbXBsZS5jb20iXQ~...~eyJhbGciOiJ..."
    ]
  }
}

// Example of the parsed and verified claims from the SD-JWT on your server:
{
  "cnf": {
    "jwk": {..}
  },
  "exp": 1775688222,
  "iat": 1775083422,
  "iss": "https://verifiablecredentials-pa.googleapis.com",
  "vct": "UserInfoCredential",
  "email": "jane.doe.246745@gmail.com",
  "email_verified": true,
  "given_name": "Jane",
  "family_name": "Doe",
  "name": "Jane Doe",
  "picture": "http://example.com/janedoe/me.jpg",
  "hd": ""
}
 */

Xác thực phía máy chủ để tạo tài khoản

Để xác minh, ứng dụng của bạn phải gửi toàn bộ responseJsonString đến máy chủ của bạn để xác thực bằng mật mã trước khi tạo tài khoản hoặc đăng nhập cho người dùng.

Quy trình xác thực trên máy chủ phải đạt được những điều sau:

  • Xác minh tổ chức phát hành: Đảm bảo trường iss (tổ chức phát hành) khớp với https://verifiablecredentials-pa.googleapis.com.
  • Xác minh chữ ký: Kiểm tra chữ ký của SD-JWT bằng các khoá công khai (JWK) có tại https://verifiablecredentials-pa.googleapis.com/.well-known/vc-public-jwks.

Để đảm bảo an toàn tuyệt đối, hãy nhớ xác thực nonce để ngăn chặn các cuộc tấn công phát lại.

try {
    // Send the raw credential response and the original nonce to your server.
    // Your server must validate the response. createAccountWithVerifiedCredentials
    // is a custom implementation per each RP for server side verification and account creation.
    val serverResponse = createAccountWithVerifiedCredentials(responseJsonString, nonce)

    // Server returns the new account info (e.g., email, name)
    val claims = JSONObject(serverResponse.json)

    val userInfo = VerifiedUserInfo(
        email = claims.getString("email"),
        displayName = claims.optString("name", claims.getString("email"))
    )

    // handle response - Up to the developer
} catch (e: Exception) {
    // handle exceptions - Up to the developer
}

Bước tiếp theo không bắt buộc nhưng bạn nên thực hiện ngay sau khi cấp tài khoản là tạo khoá truy cập cho tài khoản đó. Điều này mang đến cho người dùng một phương thức đăng nhập an toàn và không cần mật khẩu. Quy trình này giống hệt với quy trình đăng ký khoá truy cập tiêu chuẩn.

Để quy trình này hoạt động trên WebView, nhà phát triển nên triển khai cầu nối JavaScript (JS Bridge) để hỗ trợ việc chuyển giao. Cầu nối này cho phép WebView báo hiệu cho ứng dụng gốc, sau đó ứng dụng này có thể thực hiện lệnh gọi thực tế đến Credential Manager API.