Cartes de fidélité. API Google Pay pour les passes dans ASP.NET

Les applications de stockage de cartes bancaires sont rapidement entrées dans nos vies grâce à Apple Wallet et Google Pay. Les deux plateformes, en plus de la banque, vous permettent également de travailler avec d'autres types de cartes - cartes de fidélité, cartes-cadeaux, billets d'événement, cartes d'embarquement, etc.




En travaillant pour une entreprise qui dessert un réseau de vente au détail assez important, j'ai dû intégrer les cartes de fidélité de ce réseau dans Apple Wallet et Google Pay. Et si vous deviez bricoler Apple Wallet simplement parce que la couche d'intégration est assez multifonctionnelle, alors avec Google Pay, la plupart des efforts et des cellules nerveuses ont été dépensés pour essayer de comprendre la documentation, trouver les bons outils et développer la première preuve de concept. Bien qu'en général le reste du travail soit allé beaucoup plus vite que pour Apple Wallet, j'ai passé une journée à trouver comment démarrer le service, donc cela ne me dérangerait pas si quelqu'un a écrit un article similaire avant moi.

1. Matériel


Les cartes de fidélité sont représentées à l'aide de deux entités: la classe de fidélité et l'objet de fidélité.

  • La classe de fidĂ©litĂ© est une sorte de modèle pour toutes les cartes de fidĂ©litĂ©. Il contient des champs communs Ă  toutes les cartes, tels que la couleur de la police, des liens vers les ressources des icĂ´nes, les arrière-plans, les champs de texte, etc., une description complète peut ĂŞtre trouvĂ©e ici:
  • Loyalty Object - une instance de LoyaltyClass. Il contient Ă©galement les donnĂ©es d'une carte spĂ©cifique d'un client particulier - numĂ©ro de carte, nom, champs de texte supplĂ©mentaires. Description ici: Loyaltyobject

Pour recevoir une carte, l'utilisateur doit suivre le lien de formatage
www.android.com/payapp/savetoandroidpay / {JWT} , où JWT est un jeton qui contient JSON avec des données LoyaltyClass. Mais comme la longueur de l'URL a des limites, il est recommandé de créer d'abord une classe de fidélité si sa structure contient de nombreux caractères.

Si vous devez mettre à jour la carte en raison d'un changement dans le modèle, les styles, la nécessité d'ajouter ou de modifier des champs de texte, vous pouvez le faire en utilisant l'API. Il suffit de remplir une demande POST avec la nouvelle version de la carte, les services Google synchronisent eux-mêmes toutes les applications des utilisateurs qui ont cette carte.


2. Outils et documentation


Le problème était que tous les exemples dans la documentation de l'API Google Pay pour les passes étaient exclusivement pour Java, PHP et Python, et la documentation elle-même recommandait fortement "d'utiliser les bibliothèques clientes pour simplifier le processus" de travail avec l'API.


En suivant ce conseil, je suis allée avec bonheur à nuget, mais la bibliothèque de Google Pay n'était pas là. Gloire à Brin, la première ligne de Google pour «google pay for pass dotnet» a renvoyé la page des bibliothèques de l'utilitaire Google Pay API for Passes , qui a trouvé ce dont j'avais besoin, bien que dans le format d'archive ZIP, dans lequel il y avait un projet .net avec une classe générée qui est un wrapper pour l'API Google Pay - Bibliothèque Google Pay API for Passes Client .


À en juger par la présence du fichier Google.Apis.Walletobjects.v1.1.9.2.00.nuspec dans le projet, le déploiement du package nuget faisait toujours partie des plans de l'équipe Google. Après avoir ouvert ce fichier à la recherche de documentation, je n'ai rien trouvé de concret, et certains liens qui se trouvaient dans la section description ont été envoyés à des pages inexistantes.

3. Obtenir un jeton d'accès


Pour commencer à travailler directement avec l'API Google Pay pour les passes, vous devez obtenir un jeton d'accès, pour cela, vous avez besoin:

  1. Avoir un compte marchand Google, que vous pouvez obtenir ici
  2. Créez un compte de service, obtenez un fichier avec ses informations d'identification - un document json avec les détails du compte de service, y compris l'identifiant, l'e-mail, la clé privée, etc. Comme la documentation le recommande, vous devez stocker ce fichier dans un endroit sûr.
  3. Associer un compte marchand et un compte de service dans Google Merchant Center

À l'aide de ce fichier, vous pouvez vous connecter à l'aide de la bibliothèque Google.Apis.Auth.OAuth2 :

private await Task<string> GetOAuthToken() {         string serviceAccountFile = string.Empty;         serviceAccountFile = ConfigurationManager.AppSettings["GooglePayServiceAccountConfigPath"];        /*              Credential, GoogleCredential              Service Account,   ,      scopes API,             */         var credential = GoogleCredential.FromFile(serviceAccountFile)                            .CreateScoped(WalletobjectsService.Scope.WalletObjectIssuer);        /*        Access token        ,   GetAccessTokenForRequestAsync         ,               */         var token = async credential.UnderlyingCredential.GetAccessTokenForRequestAsync();         return token; } 

4. Créez une carte


Pour créer une carte de fidélité, vous devez d'abord créer une classe de fidélité. La classe de fidélité peut être créée à la fois à l'aide de l'API et à l'aide de l'interface Web de Google Merchant Center. Il convient de prêter attention au nom de la classe, car ce nom doit être unique dans l'infrastructure Google Pay.

Après avoir créé la classe de fidélité, vous pouvez créer l'objet de fidélité. Pour ce faire, nous aurons déjà besoin de la bibliothèque que nous avons ajoutée au projet plus tôt: créez un objet de demande, spécifiez le jeton OAuth, transférez l'objet LoyaltyObject créé et exécutez la demande:

 public GooglePayApiService() { // ,    Merchant Account IssuerId = ConfigurationManager.AppSettings["GooglePayIssuerId"]; _wobService = new WalletobjectsService(); } private async Task<LoyaltyObject> ConvertLoyaltyObjectFromTemplate(GooglePayPassTemplate template) { string id = $"{IssuerId}.{template.SerialNumber}"; string loyaltyClassName = ConfigurationManager.AppSettings["GooglePayStoreCardClassName"];     var loyaltyClass = await GetLoyaltyClass(loyaltyClassName); var result =  new LoyaltyObject { Id = id, AccountName = template.AccountName,          Barcode = new Barcode          {          AlternateText = template.BarcodeText,               Value = template.SerialNumber,               Type = "pdf417"          },          Kind = "walletObject#loyaltyObject",          ClassId = loyaltyClass.Id,          ClassReference = loyaltyClass,          State = "active"     };     return result; } private async Task<LoyaltyObject> CreateLoyaltyObject(LoyaltyObject loyaltyObject) { var saveRequest = _wobService.Loyaltyobject.Insert(loyaltyObject); saveRequest.OauthToken = await GetOAuthToken(); var savedObject = await saveRequest.ExecuteAsync(); return savedObject; } 

Dans cet exemple, GooglePayPassTemplate est un DTO qui stocke un modèle de carte pour un utilisateur, qui est généré par un service développé distinct.

5. Mise Ă  jour de la carte


Ici, le principe est le même que lors de la création: on génère une requête, on transfère l'objet LoyaltyObject mis à jour, on exécute:

 private async Task<LoyaltyObject> UpdateLoyaltyObject(LoyaltyObject loyaltyObject) { var updateRequest = _wobService.Loyaltyobject.Update(loyaltyObject, loyaltyObject.Id);           updateRequest.OauthToken = await GetOAuthToken(); var savedObject = await updateRequest.ExecuteAsync(); return savedObject; } 

Après avoir terminé la demande, la carte dans les applications des utilisateurs qui l'ont installée sera mise à jour après quelques secondes, si l'appareil est sur le réseau et dispose d'une connexion Internet.



6. Génération JWT


Pour installer la carte, vous devez rediriger l'utilisateur vers le lien www.android.com/payapp/savetoandroidpay / {JWT} . Une description de la structure du jeton peut être trouvée sur ce lien .


Le jeton est signé par RSA-SHA256 avec une signature qui peut être générée à l'aide du même fichier avec les informations d'identification du compte de service:

 public static class JwtHelper { public static string CreateJwtForLoyaltyObject(LoyaltyObject loyaltyObject) { /*       credential   ,         */ ServiceAccountCredential credential; var now = DateTime.UtcNow; DateTime unixEpoch = new DateTime(1970, 01, 01); // 1970-01-01 00:00:00 UTC var secondsSinceEpoch = (int)Math.Round((now - unixEpoch).TotalSeconds); string serviceAccountFile = serviceAccountFile = ConfigurationManager.AppSettings["GooglePayServiceAccountConfigPath"]; using (var fs = new FileStream(serviceAccountFile, FileMode.Open, FileAccess.Read, FileShare.Read)) { credential = ServiceAccountCredential.FromServiceAccountData(fs); } /*    JwtPayload,     payload-a  JWT */ var jwtPayload = new JwtPayload { iat = secondsSinceEpoch, iss = credential.Id, payload = new JwtInternalPayload { loyaltyObjects = new[] { new LoyaltyObjectPayload { id = loyaltyObject.Id } } } }; string header = @"{""alg"":""RS256"",""typ"":""JWT""}"; string payload = JsonConverter.SerializeObject(jwtPayload); string base64Header = EscapedBase64(Convert.ToBase64String(Encoding.UTF8.GetBytes(header))); string base64Payload = EscapedBase64(Convert.ToBase64String(Encoding.UTF8.GetBytes(payload))); //        Signature string signature = EscapedBase64(credential.CreateSignature( Encoding.UTF8.GetBytes($"{base64Header}.{base64Payload}") )); var token = $"{base64Header}.{base64Payload}.{signature}"; return token; } private static string EscapedBase64(string base64) { return base64.Replace('+', '-') .Replace('/', '_') .Replace("=", ""); } } 

Conclusion


Dans cet article, nous avons abordé les bases de l'utilisation de l'API Google Pay pour les passes: configurer des comptes, se connecter à l'API, créer la classe de fidélité et l'objet de fidélité.

Si UFO est en faveur, je vais vous expliquer séparément comment travailler avec Apple Wallet (tout est plus difficile en termes de mise en œuvre), comment se faire des amis d'Apple Wallet avec Google Pay dans un seul service Web et ne pas ressentir de douleur.


Liens utiles


Source: https://habr.com/ru/post/fr434486/


All Articles