Armazenando e acessando atributos

Com o IBM Cloud® App ID, é possível compilar informações sobre os usuários individuais de seu aplicativo em um perfil. As informações no perfil podem ser aprendidas sobre seus usuários pela maneira como eles interagem com seu app ou incluídas por você em seu nome. Ao armazenar as informações, é possível acessá-la para ajudar a criar experiências personalizadas de seu app para seus usuários.

Entendendo perfis

Um perfil de usuário são todas as informações conhecidas sobre um usuário específico, compiladas em um objeto JSON e armazenadas pelo App ID. Há dois tipos de informações ou atributos que podem ser obtidos e armazenados em um perfil: predefined e custom. Os atributos predefinidos são específicos para a identidade de seu usuário e são retornados por um provedor de identidade quando seu usuário se conecta ao seu aplicativo e podem incluir informações como seu nome ou idade. Os atributos customizados são usados para armazenar informações adicionais sobre seus usuários. Elas podem ser configuradas por você ou aprendidas sobre o usuário à medida que ele interage com seu app. Os atributos customizados podem incluir uma função designada, uma preferência alimentar ou um assento de corredor preferencial em um avião.

caption-side=bottom"
App ID perfis de usuário Fluxo de informações de perfil de usuário

É possível armazenar até 100 KB de informações para cada usuário.

Como obtenho as informações do perfil do usuário?

Há várias maneiras diferentes nas quais é possível acessar informações do usuário, e várias razões diferentes por que você desejaria. O terminal que você escolhe para chamar pode variar dependendo de seu caso de uso.

Se você precisar trabalhar com uma API, confira a imagem a seguir e as informações correspondentes para ver como as informações são extraídas.

caption-side=bottom"
App ID opções de endpoint do perfil do usuário Opções de endpoint que podem ser usadas para acessar informações do usuário

/oauth/v4/<tenantID>/token
Após uma autenticação bem-sucedida, você recebe tokens de acesso e identidade que contêm as informações sobre o usuário mais comuns: um nome, uma figura ou um e-mail, por exemplo. Se desejar incluir informações adicionais, será possível usar o mapeamento de solicitações customizadas para configurar o App ID para injetar as informações no token antes que ele seja retornado a você.
/oauth/v4/<tenantID>/userinfo
Se precisar de uma visão detalhada das informações do perfil do usuário retornadas por um provedor de identidade, você poderá chamar o endpoint /userinfo. Recomenda-se usar esse ponto de extremidade somente se as informações não puderem ser mapeadas para o token, pois isso exige chamadas de rede adicionais.
/api/v1/attributes
Se o seu aplicativo requerer a leitura e a atualização de atributos de perfil customizado para um usuário atualmente com login efetuado, será possível usar o terminal /attributes. Por exemplo, o usuário deseja atualizar uma preferência alimentar.
/management/v4/<tenantID>/users
Se você estiver desenvolvendo interfaces ou processos administrativos que podem se aplicar a múltiplos usuários, será possível usar a API de gerenciamento do App ID. Especificamente, é possível usar o terminal /users.

As maneiras mais fáceis de trabalhar com informações sobre o usuário são usando a GUI ou um SDK. Com essas opções, todas as chamadas de API são feitas nos bastidores para você.

Acessando atributos no tempo de execução

Após a autenticação bem-sucedida do usuário, seu app recebe tokens de acesso e de identidade do App ID. O serviço injeta automaticamente um subconjunto de atributos em seus tokens de acesso e identidade. Se as informações não estiverem no token, será possível usar qualquer um dos terminais a seguir para localizar as informações.

Acessando o terminal /userinfo

Para ver as informações sobre seus usuários que são fornecidos por seus provedores de identidade configurados, é possível acessar seus atributos predefinidos.

  1. Certifique-se de que você tenha um token de acesso válido com um escopo openid. É possível verificar seo token é válido usando o terminal /introspect.

  2. Faça uma solicitação para o ponto de extremidade /userinfo. Se novos tokens não forem passados explicitamente para o SDK, o App ID usará os tokens recebidos pela última vez para recuperar e validar a resposta. A passagem de um token de identidade é opcional, mas, quando passado, ele é usado para validar a resposta.

    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
       }
    }
    

    Saída de exemplo:

    "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. Verifique se a solicitação sub corresponde exatamente à solicitação sub no token de identidade. Se elas não corresponderem, não use as informações retornadas. Para saber mais sobre a substituição de tokens, consulte a especificação OIDC.

Se as mudanças forem feitas por um provedor de identidade externo, você poderá obter as informações atualizadas quando osusuários efetuarem login novamente. Os novos tokens recuperam os dados mais atualizados.

Acessando o terminal /attributes

Dependendo de sua configuração, os atributos são criptografados e salvos como parte de um perfil do usuário quando um usuário interage com seu aplicativo. A interação pode ser um usuário se conectando ou configurando uma preferência em seu app. Para acessar os atributos, passe um token de acesso por meio de um método de 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)

Configurando atributos customizados

É possível incluir informações sobre seus usuários em seu perfil, como uma função ou uma preferência, configurando um atributo customizado. Para configurar atributos customizados antes que um usuário se conecte ao seu aplicativo, consulte Pré-registrando usuários futuros.

Por padrão, os atributos customizados são modificáveis e podem ser atualizados usando um token de acesso do App ID por meio de um aplicativo cliente. Sem tomar as devidas precauções, o usuário ou o aplicativo pode atualizar atributos customizados imediatamente após a primeira conexão do usuário, se eles tiverem um token de acesso. Fazer isso pode potencialmente levar a consequências indesejadas. Por exemplo, um usuário pode mudar sua função de usuário para administrador, o que pode expor privilégios administrativos a usuários maliciosos.

  1. Acesse a guia Perfis do usuário > Configurações do painel do App ID.

  2. Alterne atributos customizados para Ativado.

  3. Obter tokens de acesso e identidade com a API.

    1. Obtenha seu ID de locatário, ID de cliente, segredo e URL do OAuth Server por meio de suas credenciais.

    2. Codifique o seu ID e segredo do cliente usando um codificador base64.

    3. Use os exemplos de código a seguir para recuperar seus tokens. O tipo de concessão que você usa para obter o seu token pode diferir dependendo do tipo de autorização com a qual você está trabalhando. Para obter uma lista detalhada de opções, consulte a documentação do 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. Usando o terminal attributes, faça uma solicitação de 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
    }