Mã thông báo web JSON là một tiêu chuẩn ngành thường được dùng để truyền thông tin một cách an toàn dưới dạng đối tượng JSON. Khi sử dụng Google Wallet API, bạn mã hoá các thông tin của Đối tượng thẻ và vé mà bạn muốn dùng để tạo một phiên bản thẻ và vé ở định dạng JWT (phát âm là "jot"), sau đó gửi JWT đó theo yêu cầu đến API Google Wallet.
Các JWT được bảo mật bằng cách ký các khoá này bằng một mã bí mật dùng chung trước khi chúng được gửi đến API Google Wallet. Nếu bạn đang sử dụng API REST của Google Wallet, thì bí mật ký là khoá tài khoản dịch vụ Google Cloud của bạn. Nếu bạn đang sử dụng SDK Android của Google Wallet, thì bí mật ký là vân tay số SHA-1 cho ứng dụng Android của bạn.
Mã hoá thẻ/vé trong JWT
Khi GenericObject
được tạo, hãy gói lớp này bằng một JWT chưa ký có thuộc tính payload.GenericObjects
, như minh hoạ trong đoạn mã sau:
JSON
{
"iss": "OWNER_EMAIL_ADDRESS",
"aud": "google",
"typ": "savetowallet",
"iat": "UNIX_TIME",
"origins": [],
"payload": {
"genericObjects": [ NEW_OBJECT ]
}
}
Để biết thêm thông tin về định dạng dự kiến của JWT, hãy xem tài liệu tham khảo về JWT.
Ký giấy JWT
Các JWT được bảo mật bằng cách ký các khoá này bằng một mã bí mật dùng chung trước khi chúng được gửi đến API Google Wallet. Nếu bạn đang sử dụng API REST của Google Wallet, thì bí mật ký là khoá tài khoản dịch vụ Google Cloud của bạn. Nếu bạn đang sử dụng SDK Android của Google Wallet, thì bí mật ký là vân tay số SHA-1 cho ứng dụng Android của bạn.
Web, email và SMS
Bạn phải ký JWT bằng khoá tài khoản dịch vụ liên kết với tài khoản dịch vụ Google Cloud mà bạn đã uỷ quyền trong Google Wallet Business Console. API Google Wallet sẽ xác thực những thông báo xác nhận quyền sở hữu này bằng cách xác minh chữ ký JWT.
Việc ký JWT sẽ tạo một mã thông báo mà sau đó có thể được sử dụng để tạo 'Thêm vào Google Wallet' đường liên kết có thể dùng để cấp thẻ và vé cho người dùng:
Java
Để bắt đầu quá trình tích hợp trong Java, hãy tham khảo mã mẫu trên GitHub.
/** * Generate a signed JWT that creates a new pass class and object. * * <p>When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the * pass class and object defined in the JWT are created. This allows you to create multiple pass * classes and objects in one API call when the user saves the pass to their wallet. * * @param issuerId The issuer ID being used for this request. * @param classSuffix Developer-defined unique ID for this pass class. * @param objectSuffix Developer-defined unique ID for the pass object. * @return An "Add to Google Wallet" link. */ public String createJWTNewObjects(String issuerId, String classSuffix, String objectSuffix) { // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericclass GenericClass newClass = new GenericClass().setId(String.format("%s.%s", issuerId, classSuffix)); // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericobject GenericObject newObject = new GenericObject() .setId(String.format("%s.%s", issuerId, objectSuffix)) .setClassId(String.format("%s.%s", issuerId, classSuffix)) .setState("ACTIVE") .setHeroImage( new Image() .setSourceUri( new ImageUri() .setUri( "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg")) .setContentDescription( new LocalizedString() .setDefaultValue( new TranslatedString() .setLanguage("en-US") .setValue("Hero image description")))) .setTextModulesData( List.of( new TextModuleData() .setHeader("Text module header") .setBody("Text module body") .setId("TEXT_MODULE_ID"))) .setLinksModuleData( new LinksModuleData() .setUris( Arrays.asList( new Uri() .setUri("http://maps.google.com/") .setDescription("Link module URI description") .setId("LINK_MODULE_URI_ID"), new Uri() .setUri("tel:6505555555") .setDescription("Link module tel description") .setId("LINK_MODULE_TEL_ID")))) .setImageModulesData( List.of( new ImageModuleData() .setMainImage( new Image() .setSourceUri( new ImageUri() .setUri( "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg")) .setContentDescription( new LocalizedString() .setDefaultValue( new TranslatedString() .setLanguage("en-US") .setValue("Image module description")))) .setId("IMAGE_MODULE_ID"))) .setBarcode(new Barcode().setType("QR_CODE").setValue("QR code value")) .setCardTitle( new LocalizedString() .setDefaultValue( new TranslatedString().setLanguage("en-US").setValue("Generic card title"))) .setHeader( new LocalizedString() .setDefaultValue( new TranslatedString().setLanguage("en-US").setValue("Generic header"))) .setHexBackgroundColor("#4285f4") .setLogo( new Image() .setSourceUri( new ImageUri() .setUri( "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg")) .setContentDescription( new LocalizedString() .setDefaultValue( new TranslatedString() .setLanguage("en-US") .setValue("Generic card logo")))); // Create the JWT as a HashMap object HashMap<String, Object> claims = new HashMap<String, Object>(); claims.put("iss", ((ServiceAccountCredentials) credentials).getClientEmail()); claims.put("aud", "google"); claims.put("origins", List.of("www.example.com")); claims.put("typ", "savetowallet"); // Create the Google Wallet payload and add to the JWT HashMap<String, Object> payload = new HashMap<String, Object>(); payload.put("genericClasses", List.of(newClass)); payload.put("genericObjects", List.of(newObject)); claims.put("payload", payload); // The service account credentials are used to sign the JWT Algorithm algorithm = Algorithm.RSA256( null, (RSAPrivateKey) ((ServiceAccountCredentials) credentials).getPrivateKey()); String token = JWT.create().withPayload(claims).sign(algorithm); System.out.println("Add to Google Wallet link"); System.out.printf("https://pay.google.com/gp/v/save/%s%n", token); return String.format("https://pay.google.com/gp/v/save/%s", token); }
PHP
Để bắt đầu quá trình tích hợp trong PHP, hãy tham khảo mã mẫu trên GitHub.
/** * Generate a signed JWT that creates a new pass class and object. * * When the user opens the "Add to Google Wallet" URL and saves the pass to * their wallet, the pass class and object defined in the JWT are * created. This allows you to create multiple pass classes and objects in * one API call when the user saves the pass to their wallet. * * @param string $issuerId The issuer ID being used for this request. * @param string $classSuffix Developer-defined unique ID for the pass class. * @param string $objectSuffix Developer-defined unique ID for the pass object. * * @return string An "Add to Google Wallet" link. */ public function createJwtNewObjects(string $issuerId, string $classSuffix, string $objectSuffix) { // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericclass $newClass = new GenericClass([ 'id' => "{$issuerId}.{$classSuffix}", ]); // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericobject $newObject = new GenericObject([ 'id' => "{$issuerId}.{$objectSuffix}", 'classId' => "{$issuerId}.{$classSuffix}", 'state' => 'ACTIVE', 'heroImage' => new Image([ 'sourceUri' => new ImageUri([ 'uri' => 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg' ]), 'contentDescription' => new LocalizedString([ 'defaultValue' => new TranslatedString([ 'language' => 'en-US', 'value' => 'Hero image description' ]) ]) ]), 'textModulesData' => [ new TextModuleData([ 'header' => 'Text module header', 'body' => 'Text module body', 'id' => 'TEXT_MODULE_ID' ]) ], 'linksModuleData' => new LinksModuleData([ 'uris' => [ new Uri([ 'uri' => 'http://maps.google.com/', 'description' => 'Link module URI description', 'id' => 'LINK_MODULE_URI_ID' ]), new Uri([ 'uri' => 'tel:6505555555', 'description' => 'Link module tel description', 'id' => 'LINK_MODULE_TEL_ID' ]) ] ]), 'imageModulesData' => [ new ImageModuleData([ 'mainImage' => new Image([ 'sourceUri' => new ImageUri([ 'uri' => 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg' ]), 'contentDescription' => new LocalizedString([ 'defaultValue' => new TranslatedString([ 'language' => 'en-US', 'value' => 'Image module description' ]) ]) ]), 'id' => 'IMAGE_MODULE_ID' ]) ], 'barcode' => new Barcode([ 'type' => 'QR_CODE', 'value' => 'QR code value' ]), 'cardTitle' => new LocalizedString([ 'defaultValue' => new TranslatedString([ 'language' => 'en-US', 'value' => 'Generic card title' ]) ]), 'header' => new LocalizedString([ 'defaultValue' => new TranslatedString([ 'language' => 'en-US', 'value' => 'Generic header' ]) ]), 'hexBackgroundColor' => '#4285f4', 'logo' => new Image([ 'sourceUri' => new ImageUri([ 'uri' => 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg' ]), 'contentDescription' => new LocalizedString([ 'defaultValue' => new TranslatedString([ 'language' => 'en-US', 'value' => 'Generic card logo' ]) ]) ]) ]); // The service account credentials are used to sign the JWT $serviceAccount = json_decode(file_get_contents($this->keyFilePath), true); // Create the JWT as an array of key/value pairs $claims = [ 'iss' => $serviceAccount['client_email'], 'aud' => 'google', 'origins' => ['www.example.com'], 'typ' => 'savetowallet', 'payload' => [ 'genericClasses' => [ $newClass ], 'genericObjects' => [ $newObject ] ] ]; $token = JWT::encode( $claims, $serviceAccount['private_key'], 'RS256' ); print "Add to Google Wallet link\n"; print "https://pay.google.com/gp/v/save/{$token}"; return "https://pay.google.com/gp/v/save/{$token}"; }
Python
Để bắt đầu quá trình tích hợp bằng Python, hãy tham khảo mã mẫu trên GitHub.
def create_jwt_new_objects(self, issuer_id: str, class_suffix: str, object_suffix: str) -> str: """Generate a signed JWT that creates a new pass class and object. When the user opens the "Add to Google Wallet" URL and saves the pass to their wallet, the pass class and object defined in the JWT are created. This allows you to create multiple pass classes and objects in one API call when the user saves the pass to their wallet. Args: issuer_id (str): The issuer ID being used for this request. class_suffix (str): Developer-defined unique ID for the pass class. object_suffix (str): Developer-defined unique ID for the pass object. Returns: An "Add to Google Wallet" link. """ # See link below for more information on required properties # https://developers.google.com/wallet/generic/rest/v1/genericclass new_class = {'id': f'{issuer_id}.{class_suffix}'} # See link below for more information on required properties # https://developers.google.com/wallet/generic/rest/v1/genericobject new_object = { 'id': f'{issuer_id}.{object_suffix}', 'classId': f'{issuer_id}.{class_suffix}', 'state': 'ACTIVE', 'heroImage': { 'sourceUri': { 'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Hero image description' } } }, 'textModulesData': [{ 'header': 'Text module header', 'body': 'Text module body', 'id': 'TEXT_MODULE_ID' }], 'linksModuleData': { 'uris': [{ 'uri': 'http://maps.google.com/', 'description': 'Link module URI description', 'id': 'LINK_MODULE_URI_ID' }, { 'uri': 'tel:6505555555', 'description': 'Link module tel description', 'id': 'LINK_MODULE_TEL_ID' }] }, 'imageModulesData': [{ 'mainImage': { 'sourceUri': { 'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Image module description' } } }, 'id': 'IMAGE_MODULE_ID' }], 'barcode': { 'type': 'QR_CODE', 'value': 'QR code' }, 'cardTitle': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic card title' } }, 'header': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic header' } }, 'hexBackgroundColor': '#4285f4', 'logo': { 'sourceUri': { 'uri': 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic card logo' } } } } # Create the JWT claims claims = { 'iss': self.credentials.service_account_email, 'aud': 'google', 'origins': ['www.example.com'], 'typ': 'savetowallet', 'payload': { # The listed classes and objects will be created 'genericClasses': [new_class], 'genericObjects': [new_object] } } # The service account credentials are used to sign the JWT signer = crypt.RSASigner.from_service_account_file(self.key_file_path) token = jwt.encode(signer, claims).decode('utf-8') print('Add to Google Wallet link') print(f'https://pay.google.com/gp/v/save/{token}') return f'https://pay.google.com/gp/v/save/{token}'
C#
Để bắt đầu tích hợp trong C#, hãy tham khảo mã mẫu trên GitHub.
/// <summary> /// Generate a signed JWT that creates a new pass class and object. /// <para /> /// When the user opens the "Add to Google Wallet" URL and saves the pass to /// their wallet, the pass class and object defined in the JWT are created. /// This allows you to create multiple pass classes and objects in one API /// call when the user saves the pass to their wallet. /// <para /> /// The Google Wallet C# library uses Newtonsoft.Json.JsonPropertyAttribute /// to specify the property names when converting objects to JSON. The /// Newtonsoft.Json.JsonConvert.SerializeObject method will automatically /// serialize the object with the right property names. /// </summary> /// <param name="issuerId">The issuer ID being used for this request.</param> /// <param name="classSuffix">Developer-defined unique ID for this pass class.</param> /// <param name="objectSuffix">Developer-defined unique ID for the pass object.</param> /// <returns>An "Add to Google Wallet" link.</returns> public string CreateJWTNewObjects(string issuerId, string classSuffix, string objectSuffix) { // Ignore null values when serializing to/from JSON JsonSerializerSettings excludeNulls = new JsonSerializerSettings() { NullValueHandling = NullValueHandling.Ignore }; // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericclass GenericClass newClass = new GenericClass { Id = $"{issuerId}.{classSuffix}" }; // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericobject GenericObject newObject = new GenericObject { Id = $"{issuerId}.{objectSuffix}", ClassId = $"{issuerId}.{classSuffix}", State = "ACTIVE", HeroImage = new Image { SourceUri = new ImageUri { Uri = "https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg" }, ContentDescription = new LocalizedString { DefaultValue = new TranslatedString { Language = "en-US", Value = "Hero image description" } } }, TextModulesData = new List<TextModuleData> { new TextModuleData { Header = "Text module header", Body = "Text module body", Id = "TEXT_MODULE_ID" } }, LinksModuleData = new LinksModuleData { Uris = new List<Google.Apis.Walletobjects.v1.Data.Uri> { new Google.Apis.Walletobjects.v1.Data.Uri { UriValue = "http://maps.google.com/", Description = "Link module URI description", Id = "LINK_MODULE_URI_ID" }, new Google.Apis.Walletobjects.v1.Data.Uri { UriValue = "tel:6505555555", Description = "Link module tel description", Id = "LINK_MODULE_TEL_ID" } } }, ImageModulesData = new List<ImageModuleData> { new ImageModuleData { MainImage = new Image { SourceUri = new ImageUri { Uri = "http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg" }, ContentDescription = new LocalizedString { DefaultValue = new TranslatedString { Language = "en-US", Value = "Image module description" } } }, Id = "IMAGE_MODULE_ID" } }, Barcode = new Barcode { Type = "QR_CODE", Value = "QR code" }, CardTitle = new LocalizedString { DefaultValue = new TranslatedString { Language = "en-US", Value = "Generic card title" } }, Header = new LocalizedString { DefaultValue = new TranslatedString { Language = "en-US", Value = "Generic header" } }, HexBackgroundColor = "#4285f4", Logo = new Image { SourceUri = new ImageUri { Uri = "https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg" }, ContentDescription = new LocalizedString { DefaultValue = new TranslatedString { Language = "en-US", Value = "Generic card logo" } }, } }; // Create JSON representations of the class and object JObject serializedClass = JObject.Parse( JsonConvert.SerializeObject(newClass, excludeNulls)); JObject serializedObject = JObject.Parse( JsonConvert.SerializeObject(newObject, excludeNulls)); // Create the JWT as a JSON object JObject jwtPayload = JObject.Parse(JsonConvert.SerializeObject(new { iss = credentials.Id, aud = "google", origins = new List<string> { "www.example.com" }, typ = "savetowallet", payload = JObject.Parse(JsonConvert.SerializeObject(new { // The listed classes and objects will be created // when the user saves the pass to their wallet genericClasses = new List<JObject> { serializedClass }, genericObjects = new List<JObject> { serializedObject } })) })); // Deserialize into a JwtPayload JwtPayload claims = JwtPayload.Deserialize(jwtPayload.ToString()); // The service account credentials are used to sign the JWT RsaSecurityKey key = new RsaSecurityKey(credentials.Key); SigningCredentials signingCredentials = new SigningCredentials( key, SecurityAlgorithms.RsaSha256); JwtSecurityToken jwt = new JwtSecurityToken( new JwtHeader(signingCredentials), claims); string token = new JwtSecurityTokenHandler().WriteToken(jwt); Console.WriteLine("Add to Google Wallet link"); Console.WriteLine($"https://pay.google.com/gp/v/save/{token}"); return $"https://pay.google.com/gp/v/save/{token}"; }
Node.js
Để bắt đầu quá trình tích hợp trong Nút, hãy tham khảo mã mẫu trên GitHub.
/** * Generate a signed JWT that creates a new pass class and object. * * When the user opens the "Add to Google Wallet" URL and saves the pass to * their wallet, the pass class and object defined in the JWT are * created. This allows you to create multiple pass classes and objects in * one API call when the user saves the pass to their wallet. * * @param {string} issuerId The issuer ID being used for this request. * @param {string} classSuffix Developer-defined unique ID for the pass class. * @param {string} objectSuffix Developer-defined unique ID for the pass object. * * @returns {string} An "Add to Google Wallet" link. */ createJwtNewObjects(issuerId, classSuffix, objectSuffix) { // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericclass let newClass = { 'id': `${issuerId}.${classSuffix}` }; // See link below for more information on required properties // https://developers.google.com/wallet/generic/rest/v1/genericobject let newObject = { 'id': `${issuerId}.${objectSuffix}`, 'classId': `${issuerId}.${classSuffix}`, 'state': 'ACTIVE', 'heroImage': { 'sourceUri': { 'uri': 'https://farm4.staticflickr.com/3723/11177041115_6e6a3b6f49_o.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Hero image description' } } }, 'textModulesData': [ { 'header': 'Text module header', 'body': 'Text module body', 'id': 'TEXT_MODULE_ID' } ], 'linksModuleData': { 'uris': [ { 'uri': 'http://maps.google.com/', 'description': 'Link module URI description', 'id': 'LINK_MODULE_URI_ID' }, { 'uri': 'tel:6505555555', 'description': 'Link module tel description', 'id': 'LINK_MODULE_TEL_ID' } ] }, 'imageModulesData': [ { 'mainImage': { 'sourceUri': { 'uri': 'http://farm4.staticflickr.com/3738/12440799783_3dc3c20606_b.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Image module description' } } }, 'id': 'IMAGE_MODULE_ID' } ], 'barcode': { 'type': 'QR_CODE', 'value': 'QR code' }, 'cardTitle': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic card title' } }, 'header': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic header' } }, 'hexBackgroundColor': '#4285f4', 'logo': { 'sourceUri': { 'uri': 'https://storage.googleapis.com/wallet-lab-tools-codelab-artifacts-public/pass_google_logo.jpg' }, 'contentDescription': { 'defaultValue': { 'language': 'en-US', 'value': 'Generic card logo' } } } }; // Create the JWT claims let claims = { iss: this.credentials.client_email, aud: 'google', origins: ['www.example.com'], typ: 'savetowallet', payload: { // The listed classes and objects will be created genericClasses: [newClass], genericObjects: [newObject] }, }; // The service account credentials are used to sign the JWT let token = jwt.sign(claims, this.credentials.private_key, { algorithm: 'RS256' }); console.log('Add to Google Wallet link'); console.log(`https://pay.google.com/gp/v/save/${token}`); return `https://pay.google.com/gp/v/save/${token}`; }
Go
Để bắt đầu tích hợp trong Go, hãy tham khảo mã mẫu hoàn chỉnh của chúng tôi trên GitHub mã mẫu trên GitHub.
// Generate a signed JWT that creates a new pass class and object. // // When the user opens the "Add to Google Wallet" URL and saves the pass to // their wallet, the pass class and object defined in the JWT are // created. This allows you to create multiple pass classes and objects in // one API call when the user saves the pass to their wallet. func (d *demoGeneric) createJwtNewObjects(issuerId, classSuffix, objectSuffix string) { genericObject := new(walletobjects.GenericObject) genericObject.Id = fmt.Sprintf("%s.%s", issuerId, objectSuffix) genericObject.ClassId = fmt.Sprintf("%s.%s", issuerId, classSuffix) genericObject.State = "ACTIVE" genericObject.Barcode = &walletobjects.Barcode{ Type: "QR_CODE", Value: "QR code", } genericObject.CardTitle = &walletobjects.LocalizedString{ DefaultValue: &walletobjects.TranslatedString{ Language: "en-us", Value: "Card title", }, } genericObject.Header = &walletobjects.LocalizedString{ DefaultValue: &walletobjects.TranslatedString{ Language: "en-us", Value: "Header", }, } genericJson, _ := json.Marshal(genericObject) var payload map[string]any json.Unmarshal([]byte(fmt.Sprintf(` { "genericObjects": [%s] } `, genericJson)), &payload) claims := jwt.MapClaims{ "iss": d.credentials.Email, "aud": "google", "origins": []string{"www.example.com"}, "typ": "savetowallet", "payload": payload, } // The service account credentials are used to sign the JWT key, _ := jwt.ParseRSAPrivateKeyFromPEM(d.credentials.PrivateKey) token, _ := jwt.NewWithClaims(jwt.SigningMethodRS256, claims).SignedString(key) fmt.Println("Add to Google Wallet link") fmt.Println("https://pay.google.com/gp/v/save/" + token) }
Ứng dụng Android
Khi phương thức savePasses
được gọi để cấp thẻ và vé cho người dùng, SDK Android của Google Wallet sẽ tự động ký JWT bằng vân tay số SHA-1 của khoá ký ứng dụng mà bạn đã cung cấp trong Google Wallet Business Console. Ngoài ra, bạn cũng có thể cấp thẻ/vé bằng JWT đã ký trước đó bằng phương thức savePassesJwt
của SDK Android.
Để biết thêm thông tin, hãy xem phần Phát hành thẻ và vé bằng SDK Android.