Stockage et accès aux attributs

Avec IBM Cloud® App ID, vous pouvez compiler des informations concernant les utilisateurs individuels de votre application sous forme de profil. Les informations contenues dans le profil peuvent être recueillies en fonction du mode d'interaction de vos utilisateurs avec votre application ou être ajoutées par vos soins pour leur compte. En stockant ces informations, vous pouvez y accéder pour pouvoir créer des expériences personnalisées de votre application pour vos utilisateurs.

Présentation des profils

Un profil utilisateur est l'ensemble des informations connues sur un utilisateur spécifique, compilées dans un objet JSON et stockées par App ID. Deux types d'informations, ou d'attributs, peuvent être obtenus et stockés dans un profil : prédéfinis (predefined) et personnalisés (custom). Les attributs prédéfinis sont spécifiques à l'identité de votre utilisateur et sont renvoyés par un fournisseur d'identité lorsque l'utilisateur se connecte à votre application. Ils peuvent comprendre son nom ou son âge. Les attributs personnalisés sont utilisés pour stocker des informations supplémentaires sur vos utilisateurs. Ils peuvent être définis par vous ou acquis au fur et à mesure que les utilisateurs interagissent avec votre application. Les attributs personnalisés peuvent inclure un rôle attribué, une préférence alimentaire ou un emplacement préféré côté couloir dans un avion.

caption-side=bottom"
App ID profils d'utilisateurs Flux d'informations sur les profils d'utilisateurs

Vous pouvez stocker jusqu'à 100 ko d'informations pour chaque utilisateur.

Comment obtenir les informations de profil utilisateur ?

Il existe plusieurs façons d'accéder aux informations utilisateur, ainsi que plusieurs raisons pour lesquelles vous le souhaitez. Le noeud final que vous choisissez pour l'appel peut varier en fonction de votre scénario d'utilisation.

Si vous devez utiliser une API, examinez l'image suivante et les informations correspondantes pour voir comment sont extraites les informations.

caption-side=bottom"
App ID user profile endpoint options Options d'extrémité pouvant être utilisées pour accéder aux informations de l'utilisateur

/oauth/v4/<tenantID>/token
Après une authentification réussie, vous recevez des jetons d'accès et d'identité contenant les informations courantes sur l'utilisateur (nom, photo, adresse e-mail, par exemple). Si vous souhaitez ajouter des renseignements supplémentaires, vous pouvez utiliser l'attribut custom claims-mapping pour configurer le service App ID pour qu'il insère ces informations dans le jeton avant de vous le renvoyer.
/oauth/v4/<tenantID>/userinfo
Si vous devez obtenir une vue détaillée des informations de profil utilisateur renvoyées par un fournisseur d'identité, vous pouvez appeler le noeud final /userinfo. Il est recommandé d'utiliser ce point de terminaison uniquement si les informations ne peuvent pas être mises en correspondance avec le jeton, car cela nécessite des appels réseau supplémentaires.
/api/v1/attributes
Si votre application requiert la lecture et la mise à jour d'attributs de profil personnalisés pour un utilisateur actuellement connecté, vous pouvez utiliser le noeud final /attributes. Par exemple, dans le cas où l'utilisateur souhaite mettre à jour une préférence alimentaire.
/management/v4/<tenantID>/users
Si vous générez des interfaces ou des processus d'administration pouvant s'appliquer à plusieurs utilisateurs, vous pouvez utiliser l'API de gestion d'App ID. Plus précisément, vous pouvez utiliser le noeud final /users.

La manière la plus simple d'utiliser des informations utilisateur est de passer par l'interface graphique ou un logiciel SDK. Avec ces options, tous les appels API sont effectués en coulisses pour vous.

Accès aux attributs lors de l'exécution

Après une authentification utilisateur réussie, votre application reçoit les jetons d'accès et d'identité d'App ID. Le service injecte automatiquement un sous-ensemble d'attributs dans vos jetons d'accès et d'identité. Si les informations ne figurent pas dans le jeton, vous pouvez utiliser l'un des noeuds finaux suivants pour les obtenir.

Accès au nœud final /userinfo

Pour afficher les informations sur vos utilisateurs fournies par vos fournisseurs d'identité configurés, vous pouvez accéder à vos attributs prédéfinis.

  1. Assurez-vous de disposer d'un jeton d'accès valide dont la portée est openid. Vous pouvez vérifier que votre jeton est valide à l'aide du noeud final /introspect.

  2. Faire une demande au point de terminaison /userinfo. Si de nouveaux jetons ne sont pas transmis explicitement au logiciel SDK, App ID utilise les derniers jetons reçus pour extraire et valider la réponse. La transmission d'un jeton d'identité est facultative, mais le jeton transmis est utilisé pour valider la réponse.

    GET https://<region>.appid.cloud.ibm.com/oauth/v4/<tenantID>/userinfo
    Authorization: 'Bearer <accessToken>'
    
    // iOS Swift example
    
    AppID.sharedInstance.userProfileManager.getUserInfo(accessToken: String, identityToken: String?) { (error: Error?, userInfo: [String: Any]?) in guard
       let userInfo = userInfo, err == nil {
          return // an error has occurred
       }
       // retrieved user info successfully
    }
    
    AppID appId = AppID.getInstance();
    
    appId.getUserProfileManager().getUserInfo(accessToken, identityToken, new UserProfileResponseListener() {
       @Override
       public void onSuccess(JSONObject userInfo) {
       // retrieved attribute "name" successfully
       }
    
       @Override
       public void onFailure(UserInfoException e) {
       // exception occurred
       }
    });
    
    let userProfileManager = UserProfileManager(options: options)
    
    let accessToken = req.session[WebAppStrategy.AUTH_CONTEXT].accessToken;
    let identityToken = req.session[WebAppStrategy.AUTH_CONTEXT].identityToken;
    
    // Retrieve user info and validate against the given identity token
    userProfileManager.getUserInfo(accessToken, identityToken).then(function (profile) {
       // retrieved user info successfully
    });
    
    // Retrieve user info without validation
    userProfileManager.getUserInfo(accessToken).then(function (profile) {
    // retrieved user info successfully
    });
    
    // Server-side Swift example
    
    let userProfileManager = UserProfileManager(options: options)
    let accessToken = "<accessToken>"
    let identityToken = "<identityToken>"
    
    // If identity token is provided (recommended approach), response is validated against the identity token
    
    userProfileManager.getUserInfo(accessToken: accessToken, identityToken: identityToken) { (err, userInfo) in guard
       let userInfo = userInfo, err == nil {
       return
       }
    }
    
    // Retrieve the UserInfo without any validation
    
    userProfileManager.getUserInfo(accessToken: accessToken) { (err, userInfo) in guard
       let userInfo = userInfo, err == nil {
       return
       }
    }
    

    Exemple de sortie :

    "sub": "cad9f1d4-e23b-3683-b81b-d1c4c4fd7d4c",
    "name": "John Doe",
    "email": "john.doe@gmail.com",
    "picture": "https://lh3.googleusercontent.com/-XdUIqdbhg/AAAAAAAAI/AAAAAAA/42rbcbv5M/photo.jpg",
    "gender": "male",
    "locale": "en",
    "identities": [
       {
             "provider": "google",
             "id": "104560903311317789798",
             "profile": {
                "id": "104560903311317789798",
                "email": "john.doe@gmail.com",
                "verified_email": true,
                "name": "John Doe",
                "given_name": "John",
                "family_name": "Doe",
                "link": "https://plus.google.com/104560903311317789798",
                "picture": "https://lh3.googleusercontent.com/-XdUIqdbhg/AAAAAAAAI/AAAAAAA/42rbcbv5M/photo.jpg",
                "gender": "male",
                "locale": "en",
                "idpType": "google"
             }
       }
    ]
    
  3. Vérifiez que la revendication sub correspond exactement à la revendication sub dans le jeton d'identité. Si les demandes ne correspondent pas, n'utilisez pas les informations renvoyées. Pour en savoir plus sur la substitution de jetons, consultez la spécification OIDC.

Si des modifications sont apportées par un fournisseur d'identité externe, vous pouvez obtenir les informations mises à jour lorsque vos utilisateurs se reconnectent. Vos nouveaux jetons extraient les informations les plus à jour.

Accès au nœud final /attributes

Selon votre configuration, les attributs sont chiffrés et enregistrés dans le cadre d'un profil utilisateur lorsqu'un utilisateur interagit avec votre application. L'interaction peut être un utilisateur qui se connecte ou définit une préférence dans votre application. Pour accéder aux attributs, transmettez un jeton d'accès via une méthode d'API.

curl -X GET 'https://<region>.appid.cloud.ibm.com/api/v1/attributes'
-H 'Accept: application/json'
-H 'Authorization: Bearer <accessToken>'
//iOS Swift example

func setAttribute(key: String, value: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)
func setAttribute(key: String, value: String, accessTokenString: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)

func getAttribute(key: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)
func getAttribute(key: String, accessTokenString: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)

func getAttributes(completionHandler: @escaping(Error?, [String:Any]?) -> Void)
func getAttributes(accessTokenString: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)

func deleteAttribute(key: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)
func deleteAttribute(key: String, accessTokenString: String, completionHandler: @escaping(Error?, [String:Any]?) -> Void)
void setAttribute(@NonNull String name, @NonNull String value, UserAttributeResponseListener listener);
void setAttribute(@NonNull String name, @NonNull String value, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);

void getAttribute(@NonNull String name, UserAttributeResponseListener listener);
void getAttribute(@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);

void deleteAttribute(@NonNull String name, UserAttributeResponseListener listener);
void deleteAttribute(@NonNull String name, @NonNull AccessToken accessToken, UserAttributeResponseListener listener);

void getAllAttributes(@NonNull UserAttributeResponseListener listener);
void getAllAttributes(@NonNull AccessToken accessToken, @NonNull UserAttributeResponseListener listener);
const userProfileManager = require("ibmcloud-appid").UserProfileManager;
userProfileManager.init();
var accessToken = req.session[WebAppStrategy.AUTH_CONTEXT].accessToken;

// get all attributes
userProfileManager.getAllAttributes(accessToken).then(function (attributes) {

        });

// get single attribute
userProfileManager.getAttribute(accessToken, name).then(function (attributes) {

        });

// set attribute value
userProfileManager.setAttribute(accessToken, name, value).then(function (attributes) {

        });

// delete attribute
userProfileManager.deleteAttribute(accessToken, name).then(function () {

        });
//Server-side Swift example

func getAllAttributes(accessToken: String, completionHandler: (Swift.Error?, [String: Any]?) -> Void)
func getAttribute(accessToken: String, attributeName: String, completionHandler: (Swift.Error?, [String: Any]?) -> Void)
func setAttribute(accessToken: String, attributeName: String, attributeValue : "abc", completionHandler: (Swift.Error?, [String: Any]?) -> Void)
func deleteAllAttributes(accessToken: String, completionHandler: (Swift.Error?, [String: Any]?) -> Void)

Définition d'attributs personnalisés

Vous pouvez ajouter des informations sur vos utilisateurs dans leur profil, comme un rôle ou une préférence, en définissant un attribut personnalisé. Pour définir des attributs personnalisés avant la connexion d'un utilisateur à votre application, voir Pré-enregistrement de futurs utilisateurs.

Par défaut, les attributs personnalisés sont modifiables et peuvent être mis à jour à l'aide d'un jeton d'accès App ID provenant d'une application client. Sans prendre les précautions appropriées, l'utilisateur ou l'application peut mettre à jour les attributs personnalisés immédiatement après la première connexion de l'utilisateur, s'ils ont un jeton d'accès. Cela peut entraîner des conséquences non intentionnelles. Par exemple, un utilisateur peut changer son rôle d'utilisateur en administrateur, ce qui peut octroyer des privilèges d'administration à des utilisateurs malveillants.

  1. Accédez à l'onglet Profils d'utilisateur > Paramètres du tableau de bord App ID.

  2. Faites basculer le paramètre des attributs personnalisés sur Activé.

  3. Obtenir des jetons d'accès et d'identité avec l'API.

    1. Obtenez votre ID de titulaire, votre ID client, votre secret et l'adresse URL du serveur OAuth à partir de vos données d'identification.

    2. Encodez votre ID client et votre secret à l'aide d'un encodeur base64.

    3. Utilisez les exemples de code suivants pour récupérer vos jetons. Le type d'octroi que vous utilisez pour obtenir votre jeton peut différer selon le type d'autorisation. Pour une liste détaillée des options, consultez la documentation de swagger.

      curl -X POST 'https://<region>.appid.cloud.ibm.com/oauth/v4/<tenantID>/token' \
      -H 'Authorization: Basic base64Encoded{<clientID>:<clientSecret>}' \
      -H 'Accept: application/json' \
      -F 'grant_type=password' \
      -F 'username=testuser@test.com' \
      -F 'password=testuser'
      
      // iOS Swift example
      
      class delegate : TokenResponseDelegate {
         public func onAuthorizationSuccess(accessToken: AccessToken?, identityToken: IdentityToken?, refreshToken: RefreshToken?, response:Response?) {
         //User authenticated
         }
      
         public func onAuthorizationFailure(error: AuthorizationError) {
         //Exception occurred
         }
      }
      
      AppID.sharedInstance.signinWithResourceOwnerPassword(username: username, password: password, delegate: delegate())
      
      AppID.getInstance().signinWithResourceOwnerPassword(getApplicationContext(), username, password, new TokenResponseListener() {
         @Override
         public void onAuthorizationFailure (AuthorizationException exception) {
            //Exception occurred
         }
      
         @Override
         public void onAuthorizationSuccess (AccessToken accessToken, IdentityToken identityToken, RefreshToken refreshToken) {
            //User authenticated
         }
      });
      
      // Declare the API you want to protect
      app.get("/api/protected",
      
         passport.authenticate(APIStrategy.STRATEGY_NAME, {
         session: false
         }),
         function(req, res) {
         // Get full appIdAuthorizationContext from request object
         var appIdAuthContext = req.appIdAuthorizationContext;
      
         appIdAuthContext.accessToken; // Raw access_token
         appIdAuthContext.accessTokenPayload; // Decoded access_token JSON
         appIdAuthContext.identityToken; // Raw identity_token
         appIdAuthContext.identityTokenPayload; // Decoded identity_token JSON
         appIdAuthContext.refreshToken; // Raw refresh_token
         ...
         }
      );
      
      // Server-side swift example
      
      let options = [
         "clientId": "<clientID>",
         "secret": "<secret>",
         "tenantId": "<tenantID>",
         "oauthServerUrl": "<oauthServerURL>",
         "redirectUri": "<appURL>" + CALLBACK_URL
      ]
      let webappKituraCredentialsPlugin = WebAppKituraCredentialsPlugin(options: options)
      let kituraCredentials = Credentials()
      kituraCredentials.register(plugin: webappKituraCredentialsPlugin)
      
  4. En utilisant le noeud final attributes, effectuez une demande PUT.

    curl -X PUT "https://<region>.appid.cloud.ibm.com/api/v1/attributes/<attributeName>" \
    -H "Authorization: Bearer <token>" \
    -d "<attributeValue>"
    
    // iOS Swift example
    
    AppID.sharedInstance.userProfileManager?.setAttribute("key", "value") { (error, result) in
       guard let result = result, error == nil else {
          return // an error has occurred
       }
    // attributes recieved as a Dictionary
    })
    
    appId.getUserProfileManager().setAttribute(name, value, useThisToken, new UserProfileResponseListener() {
       @Override
       public void onSuccess(JSONObject attributes) {
       // attributes received in JSON format on successful response
       }
    
       @Override
       public void onFailure(UserAttributesException e) {
       // exception occurred
       }
    });
    
    const userProfileManager = require("ibmcloud-appid").UserProfileManager;
    userProfileManager.init();
    
    var accessToken = req.session[WebAppStrategy.AUTH_CONTEXT].accessToken;
    
    userProfileManager.setAttribute(accessToken, name, value).then(function (attributes) {
       // attributes returned as dictionary
    });
    
    // Server-side Swift
    
    let userProfileManager = UserProfileManager(options: options)
    let accesstoken = "access token"
    
    userProfileManager.setAttribute(accessToken: accessToken, attributeName: "name", attributeValue : "abc") { (error, response) in
       guard let response = response, error == error else {
       return // an error has occurred
       }
       // attributes received as a Dictionary
    }