Establecer la autenticación mediante vínculo profundo

Los vínculos profundos permiten que el usuario se autentique en la Web Shop a través del juego con un solo clic, en lugar de pasar por el proceso de autenticación mediante ID de usuario o mediante Xsolla Login.

Si el juego está instalado en el dispositivo móvil del usuario, a este se le redirigirá al juego mediante un vínculo profundo para obtener un token de autorización.

Flujo del usuario

  1. Un usuario no autorizado de la Web Shop pulsa en el botón de inicio de sesión o en el botón de compra. Se abre una ventana modal para introducir el ID de usuario o iniciar sesión mediante el juego móvil.
  1. El usuario pulsa en el botón de inicio de sesión a través del juego.
  2. Al usuario se le redirige al juego desde donde se le redirige automáticamente a Web Shop como un usuario autorizado.

  1. Un usuario no autorizado de la Web Shop pulsa en el botón de inicio de sesión o en el botón de compra. Se abre una ventana modal para introducir el ID de usuario o al iniciar sesión en la versión móvil del juego utilizando un código QR.

  1. El usuario escanea el código QR con su dispositivo móvil, tras lo cual se abre la Web Shop en su dispositivo móvil.
  2. La versión móvil del juego se abre en el dispositivo móvil del usuario
  3. Al usuario se le redirige automáticamente a la Web Shop como usuario autorizado.
  1. En la configuración de la aplicación móvil de su juego, registre un esquema de URL para abrir el juego a través de un vínculo profundo:
    • en aplicaciones de Android, en el archivo AndroidManifest.xml
    • en aplicaciones de iOS, en el archivo Info.plist
Tras registrar el esquema, cuando el usuario se autentique en Web Shop mediante el juego, este deberá abrirse en la dirección especificada. Ejemplo de esquema URL para registrar un juego: gamename://authorize, en el que:
  • gamename: el nombre de su juego que debe abrirse en un dispositivo móvil para la autenticación del usuario.
  • authorize: un ejemplo de un nombre de acción que debe ejecutarse después de que se abra el juego gamename. Use el nombre de acción que coincida con las acciones del sistema operativo de su aplicación.
Ejemplo de registro de un esquema URL en aplicaciones de iOS:
Copy
Full screen
Small screen
    <key>CFBundleURLTypes</key>
      <array>
        <dict>
          <key>CFBundleTypeRole</key>
          <string>Editor</string>
          <key>CFBundleURLSchemes</key>
          <array>
            <string>gamename</string>
          </array>
        </dict>
      </array>
    

    Ejemplo de registro de un esquema URL en aplicaciones de Android:

    Copy
    Full screen
    Small screen
      <intent-filter>
          <action android:name="android.intent.action.VIEW" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="android.intent.category.BROWSABLE" />
          <data android:scheme="gamename" android:host="authorize" />
      </intent-filter>
      

      1. Implemente la generación de un token de autorización en formato JWT empleando el ID de usuario del juego.

      ParámetroTipoDescripción
      stringID del método de autorización de Cuenta del editor. Obligatorio.
      stringURL para recibir el webhook User validation in Web Shop (Validación de usuarios en Web Shop). La URL debe coincidir con la dirección especificada cuando se establezca la autenticación mediante ID de usuario. Xsolla espera un código HTTP 200 como respuesta al webhook para autorizar al usuario de la Web Shop. Si Xsolla recibe una respuesta con un código HTTP 404 o no recibe respuesta, el usuario no será autorizado.

      Puede especificar el valor "webhookUrl": "https://nowebhook.com" para deshabilitar los webhooks cuando se autentique mediante un vínculo profundo. En este caso, Xsolla no comprueba la existencia del usuario, así que asegúrese de que en el parámetro user.id se transmite el ID de usuario que existe en el juego.
      Obligatorio.
      stringID del proyecto que se encuentra en Cuenta del editor, el cual se especifica junto al nombre de su proyecto en la barra de direcciones del navegador. La URL tiene el siguiente formato: https:​//publisher.xsolla.com/merchant ID/Publisher Account section. Obligatorio.
      stringID del usuario en el juego. Obligatorio.
      stringNombre de usuario. Obligatorio.

      Ejemplo de llamada al método API de generación de token de usuario a través de cURL:

      Copy
      Full screen
      Small screen
      curl --location 'https://sb-user-id-service.xsolla.com/api/v1/user-id' \
      --header 'Content-Type: application/json' \
      --data '{
       "loginId": "000001aa-001a-0ab0-00001-01a01a01a01a",
       "webhookUrl": "https://nowebhook.com",
       "settings": {
         "projectId": 123456,
         "merchantId": 123456
       },
       "user": {
         "id": "123",
         "name": "a-user-name"
       }
      }'
      

      Obtendrá una respuesta del tipo {token=“JWT_TOKEN”}.

      1. Agregue una ventana emergente con una notificación de autorización correcta (opcional).
      2. Implemente la apertura de Web Shop en el navegador mediante el token de usuario obtenido.

      Ejemplo de creación de una URL para abrir Web Shop en el navegador para un usuario autorizado:

      • https:​//example.com/?token={token}, si utiliza un dominio personalizado
      • https:​//example.xsollasitebuilder.com/?token={token}, si utiliza un dominio de Xsolla
      En el que {token} es el token de autorización del usuario.Puede realizar los ajustes en el lado de Site Builder utilizando los códigos de ejemplo sumistrados abajo.
      Para obtener ayuda para la instalación, contacte con su Gestor de éxito del cliente o envíe un correo electrónico a csm@xsolla.com.
      Nota
      Primero establezca la autenticación mediante ID de usuario Esto es necesario para que los usuarios tengan un modo alternativo de autenticación si la autenticación mediante vínculo profundo no está disponible. Por ejemplo, si el juego no está instalado en el dispositivo móvil de un usuario.
      1. Abra el proyecto en la Cuenta del editor.
      2. En el menú lateral, haga clic en Site Builder (Creador de sitios web).
      3. Haga clic en Configure en la ficha del sitio de su Web Shop con autenticación mediante ID de usuario.
      4. Agregue la autenticación mediante vínculo profundo utilizando un bloque de Custom code (Código personalizado).
      5. En el bloque Custom code de la pestaña JavaScript, agregue el código personalizado siguiente, que implementa la autenticación mediante vínculo profundo para las versiones móvil y de escritorio.
      1. Sustituya los valores de las constantes presentes en el código por sus valores, en el cual:
        • DEEPLINK_URL - esquema de URL para abrir el juego mediante vínculo profundo.
        • QR_CODE - código QR para abrir el juego en formato SVG. El código QR debe contener un enlace a la Web Shop con el parámetro source = pc.
        • deeplink__description - descripción que se muestra bajo el botón de autorización del juego en la aplicación móvil.
        • qr-code-auth__description - descripción que se muestra bajo el código QR en la versión de escritorio del juego.
      Copy
      Full screen
      Small screen
      {
          const DEEPLINK_URL = 'gamename://authorize';
          const QR_CODE = `YOUR_SVG_WITH_QR_CODE`;
          handleQRCodeRedirect();
      
      // Event handlers are set up for opening the authentication modal or for successful authentication.
      // If the event of opening the authentication modal occurs, the handler is triggered and a button or QR code is added to this window.
      // If the event of successful authentication occurs, the handler is triggered and the successful authentication modal is opened.
      
          window.addEventListener('custom-event:modal:render', updateLoginModal);
          window.addEventListener('custom-event:authorization:login', showLoginSuccessPopup);
          let getToken;
      
          const searchParams = new URLSearchParams(window.location.search);
          const tokenParam = searchParams.get('token');
          if (tokenParam) {
              showLoginSuccessPopup(tokenParam);
          }
      
          window.SB.subscribe(api => {
              getToken = api.getToken;
          });
      
      // Customization of the authentication modal window (adding a QR code for the desktop version of the game or a login button for the mobile version of the game).
      
          function updateLoginModal({detail}) {
              const {name, element} = detail;
              if (name !== 'user-id' || element.dataset.isQrAdded === 'true') return;
              const isMobile = checkMobileDevice();
              const ModalBody = element.querySelector('.ui-site-modal-window__body');
              const ModulInput = ModalBody.querySelector('.user-id-modal__input');
              element.classList.toggle('mobile-layout', isMobile);
              ModalBody.append(getTemplate(isMobile));
      
              element.dataset.isQrAdded = true;
          }
      
      // Function to display the successful authentication modal window.
      
        function showLoginSuccessPopup(t) {
          let username = 'Gamer';
          try {
            const token = getToken?.() || t;
            if (token) {
              const jwtData = parseJwt(token);
              const payload = JSON.parse(jwtData.payload);
              if (payload.userInfo.name) {
                username = payload.userInfo.name;
              } else if (jwtData.username) {
                username = jwtData.username;
              } else if (jwtData.server_custom_id) {
                username = jwtData.server_custom_id;
              }
            }
          } catch (e) {
            console.log('error', e);
          }
      
          const Modal = document.querySelector('.deeplink-auth');
          const ModalTitle = Modal.querySelector('.deeplink-auth__title');
      
          ModalTitle.textContent = ModalTitle.textContent.replace(/\{username}/g, username);
      
          Modal.classList.add('_visible');
          Modal.querySelector('.deeplink-auth__button').addEventListener('click', closeModal);
      
          function closeModal() {
            Modal.classList.remove('_visible');
          }
        }
      
      // Function that displays a QR code for the desktop version of the game or a login button for the mobile version of the game. Your_game should be replaced with the actual name of your game. To continue with the authentication, the game has to be installed on the user's phone.
      
        function getTemplate(isMobile) {
          const Deeplink = document.createElement('div');
      
          if (isMobile) {
            Deeplink.innerHTML = `
              <div class="deeplink__title"><span class="deeplink__title-text">or login via game</span></div>
              <a href="${DEEPLINK_URL}" class="deeplink__button" rel="noopener">Login via Mobile Game</a>
              <div class="deeplink__description">
                You need to have the Your_game installed on your phone in order to proceed with authorization and purchase
              </div>
            `;
      
            return Deeplink;
          }
      
          Deeplink.innerHTML = `
            <div class="separator">
              <span class="separator__text">or login via game</span>
            </div>
            <div class="qr-code-auth">
              <div class="qr-code-auth__image">${QR_CODE}</div>
              <span class="qr-code-auth__description">
              Scan the QR code with your phone and you will continue purchasing on your mobile device
              </span>
            </div>
          `;
      
          return Deeplink;
        }
      
        function checkMobileDevice() {
          return (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent));
        }
      
      //  Function that decodes the JWT token and returns its payload as a JavaScript object.
      
        function parseJwt(token) {
          const base64Url = token.split('.')[1];
          const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
          const jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
          }).join(''));
      
          return JSON.parse(jsonPayload);
        }
      
      // Function to verify the vent occurred when the user scanned the QR code.
      
        function handleQRCodeRedirect() {
          const url = new URL(window.location.href);
          const source = url.searchParams.get('source');
          if (source === 'pc') {
            if (checkMobileDevice()) {
              const button = document.getElementById("deeplink-redirect");
              button.click();
            }
      
            setTimeout(function () {
              url.searchParams.delete('source');
              window.history.pushState({}, '', url);
            }, 2000);
          }
        }
      }
      
      1. En el bloque Custom code de la pestaña HTML, agregue código para una ventana modal que indique la autorización correcta en la Web Shop. Puede establecer sus propios valores de texto.
      Copy
      Full screen
      Small screen
      <div class="ui-site-modal-window deeplink-auth">
        <div class="deeplink-auth__body">
          <div class="deeplink-auth__image"></div>
          <div class="deeplink-auth__title">Hi, {username}!</div>
          <div class="deeplink-auth__description">You’ve successfully logged in to the Web Shop</div>
          <button class="deeplink-auth__button">Continue</button>
        </div>
      </div>
      
      <a href="gamename://authorize" id="deeplink-redirect" style="display: none;"></a>
      
      1. En el bloque Custom code de la pestaña CSS, agregue estilos para los componentes de la nueva interfaz. Más abajo se sugieren los estilos recomendados. Especifique la URL de su propia imagen que se visualiza tras una autorización correcta.
      Copy
      Full screen
      Small screen
      --deeplink-success-image-url: url("Successful_authorization_image_url");
      
      .html-v2:has(.deeplink-auth._visible) {
        z-index: var(--modalsZIndex);
      }
      
      .user-id-modal__content {
        padding: 0 16px !important;
      }
      
      @media (min-width: 768px) {
        .user-id-modal__content {
          max-width: 460px !important;
          padding: 0 3.8rem 4rem !important;
          overflow: auto;
          justify-content: center;
        }
      }
      
      .mobile-layout .user-id-modal__close {
        right: 8px;
        top: 16px;
      }
      
      .user-id-modal__logo {
        width: 109px;
        height: 38px;
        margin: 4rem auto 2rem;
      }
      
      .user-id-modal.mobile-layout .user-id-modal__logo {
        margin: 3rem auto 2.5rem;
      }
      
      .user-id-modal__wrapper {
        margin-top: 0;
      }
      
      .user-id-modal__title {
        margin-bottom: 3rem;
      }
      
      .user-id-modal__input-wrapper .ui-site-input {
        height: 41px;
      }
      
      .user-id-modal__input {
        margin-top: 0;
        border-radius: var(--border-radius-16);
      }
      
      .user-id-modal__button {
        height: auto;
        margin: 12px auto 0;
        padding: 1.25rem;
        border-radius: var(--border-radius-16);
      }
      
      .user-id-modal__button .simple-button__text {
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
      }
      
      .user-id-modal .ui-site-instruction-cut__title .ui-site-description {
        margin-bottom: 3rem;
        font-size: 1.2em;
      }
      
      .user-id-modal .ui-site-instruction-cut__steps {
        overflow-y: visible;
      }
      
      .user-id-modal .ui-site-instruction-card:first-child {
        margin-top: 0;
      }
      
      .user-id-modal .ui-site-instruction-card:last-child {
        padding-bottom: 4rem;
      }
      
      .user-id-modal .separator {
        display: flex;
        margin-bottom: 3.8rem;
        align-items: center;
      }
      
      .user-id-modal .separator__text {
        padding: 0 1.5rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.8px;
      }
      
      .user-id-modal .separator::before,
      .user-id-modal .separator::after {
        content: "";
        background-color: #797979;
        height: 1px;
        flex-grow: 1;
      }
      
      .user-id-modal .qr-code-auth__image {
        display: block;
        width: 160px;
        height: 160px;
        margin: 0 auto 20px;
      }
      
      .user-id-modal .qr-code-auth__image svg {
        display: block;
        width: 100%;
        height: 100%;
      }
      
      .user-id-modal .qr-code-auth__description {
        display: inline-block;
        font-family: var(--main-font);
        font-size: 1.5rem;
        font-weight: 400;
        line-height: 2.5rem;
        text-align: center;
        color: rgba(255, 255, 255, 0.7);
      }
      
      .deeplink__title {
        display: flex;
        margin-bottom: 3.8rem;
        align-items: center;
      }
      
      .deeplink__title-text {
        padding: 0 1.5rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.8px;
      }
      
      .user-id-modal .deeplink__title::before,
      .user-id-modal .deeplink__title::after {
        content: "";
        background-color: #797979;
        height: 1px;
        flex-grow: 1;
      }
      
      .deeplink__button {
        display: block;
        margin-bottom: 2.2rem;
        padding: 1.3rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
        text-align: center;
        color: var(--button-text-color);
        background: var(--accent-color);
        border-radius: var(--border-radius-16);
        text-decoration: none;
        transition: transform .2s cubic-bezier(.509, .001, .25, 1);
      }
      
      .deeplink__button:hover {
        transform: scale(.95);
      }
      
      .deeplink__description {
        margin-bottom: 2rem;
        font-family: var(--main-font);
        font-size: 1.6rem;
        line-height: 2.3rem;
        text-align: center;
        color: rgba(255, 255, 255, 0.7);
        letter-spacing: 0.5px;
      }
      
      .deeplink__cta-wrapper {
        display: flex;
        flex-direction: row;
        gap: 1.8rem;
        padding: 0 1.2rem;
      }
      
      .deeplink__cta-wrapper .ui-site-calltoaction__item {
        margin: 0;
        flex-grow: 2;
      }
      
      .deeplink__cta-wrapper .ui-site-calltoaction {
        width: 100%;
        min-width: auto;
        height: auto;
        min-height: auto;
        padding-bottom: 36%;
        background-size: contain;
        border-radius: 0;
      }
      
      .deeplink-auth {
        display: none;
      }
      
      .deeplink-auth._visible {
        display: flex;
      }
      
      .deeplink-auth__body {
        position: relative;
        width: 100%;
        max-width: 336px;
        padding: 16px;
        border-radius: 12px;
        background-color: var(--colors-core-background-secondary-rgb);
        border: var(--border-size) solid var(--border-color);
        font-family: var(--main-font);
        color: var(--colors-core-text-primary);
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__body {
          max-width: 460px;
          padding: 24px 30px;
        }
      }
      
      .deeplink-auth__image {
        margin-bottom: 20px;
        padding-bottom: 49%;
        border-radius: 12px;
        background-image: var(--deeplink-success-image-url);
        background-repeat: no-repeat;
        background-position: center;
        background-size: cover;
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__image {
          padding-bottom: 37%;
        }
      }
      
      .deeplink-auth__title {
        margin-bottom: 10px;
        font-size: 20px;
        font-weight: 500;
        line-height: 24px;
        text-align: center;
        letter-spacing: 0.7px;
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__title {
          margin-bottom: 20px;
          font-size: 24px;
          line-height: 30px;
        }
      }
      
      .deeplink-auth__description {
        margin-bottom: 20px;
        font-size: 13px;
        font-weight: 400;
        line-height: 18px;
        text-align: center;
        letter-spacing: 0.5px;
        color: rgba(255, 255, 255, 0.7);
      }
      
      .deeplink-auth__button {
        display: block;
        width: 100%;
        padding: 1.3rem;
        font-family: var(--main-font);
        font-size: 1.8rem;
        font-weight: 500;
        line-height: 2.5rem;
        letter-spacing: 0.5px;
        text-align: center;
        color: var(--button-text-color);
        background: var(--accent-color);
        border-radius: var(--border-radius-16);
        text-decoration: none;
        transition: transform .2s cubic-bezier(.509, .001, .25, 1);
      }
      
      @media (min-width: 768px) {
        .deeplink-auth__button {
          padding: 12px;
          font-size: 16px;
          line-height: 24px;
        }
      }
      
      .deeplink-auth__button:hover {
        transform: scale(.95);
      }
      
      ¿Te ha resultado útil este artículo?
      ¡Gracias!
      ¿Hay algo en lo que podamos mejorar? Mensaje
      Lo sentimos
      Por favor, cuéntanos por qué no te ha resultado útil este artículo. Mensaje
      ¡Gracias por tu mensaje!
      Nos ayudará a mejorar tu experiencia.
      Valore esta página
      Valore esta página
      ¿Hay algo en lo que podamos mejorar?

      Prefiero no responder

      ¡Gracias por tu mensaje!
      Última actualización: 2 de Mayo de 2024

      ¿Has encontrado una errata u otro error de texto? Selecciona el texto y pulsa Ctrl+Intro.

      Informar de un problema
      Nos esforzamos por ofrecer contenido de calidad. Tus comentarios nos ayudan a mejorar.
      Déjanos tu correo electrónico para que te podamos responder
      ¡Gracias por tu mensaje!