Cuando Looker está incorporado en un iframe mediante una incorporación de inicio de sesión único (SSO), algunos navegadores utilizan de forma predeterminada una política de cookies que bloquea las cookies de terceros. Las cookies de terceros se rechazan cuando el iframe incorporado se carga desde un dominio diferente al que carga la aplicación incorporada. Por lo general, puedes evitar esta limitación solicitando y usando un dominio personalizado. Sin embargo, en algunos casos, los dominios personalizados no se pueden usar. En estos casos, se puede usar la incorporación sin cookies de Looker.
¿Cómo funciona la incorporación sin cookies?
Cuando no se bloquean las cookies de terceros, se crea una cookie de sesión cuando un usuario accede a Looker por primera vez. Esta cookie se envía con cada solicitud de usuario, y el servidor de Looker la usa para establecer la identidad del usuario que inició la solicitud. Cuando se bloquean las cookies, estas no se envían con una solicitud, por lo que el servidor de Looker no puede identificar al usuario asociado con la solicitud.
Para resolver este problema, la incorporación sin cookies de Looker asocia tokens con cada solicitud que se pueden usar para recrear la sesión de usuario en el servidor de Looker. Es responsabilidad de la aplicación de incorporación obtener estos tokens y ponerlos a disposición de la instancia de Looker que se ejecuta en el iframe incorporado. El proceso de obtener y proporcionar estos tokens se describe en el resto de este documento.
Para usar cualquiera de las API, la aplicación de incorporación debe poder autenticarse en la API de Looker con privilegios de administrador. El dominio de incorporación también debe aparecer en la lista de entidades permitidas del dominio de incorporación o, si se usa Looker 23.8 o versiones posteriores, se puede incluir el dominio de incorporación cuando se adquiere la sesión sin cookies.
Cómo crear un iframe de incorporación de Looker
En el siguiente diagrama de secuencias, se ilustra la creación de un iframe incorporado. Se pueden generar varios iframes de forma simultánea o en el futuro. Cuando se implementa correctamente, el iframe se unirá automáticamente a la sesión que crea el primer iframe. El SDK de incorporación de Looker simplifica este proceso, ya que se une automáticamente a la sesión existente.
- El usuario realiza una acción en la aplicación de incorporación que da como resultado la creación de un iframe de Looker.
- El cliente de aplicación de incorporación adquiere una sesión de Looker. Se puede usar el SDK de Embed de Looker para iniciar esta sesión, pero se debe proporcionar una URL de extremo o una función de devolución de llamada. Si se usa una función de devolución de llamada, llamará al servidor de la aplicación de incorporación para adquirir la sesión de incorporación de Looker. De lo contrario, el SDK de Embed llamará a la URL del extremo proporcionada.
- El servidor de aplicaciones de incorporación usa la API de Looker para adquirir una sesión de incorporación. Esta llamada a la API es similar al proceso de firma de SSO de Looker, ya que acepta la definición del usuario incorporado como entrada. Si ya existe una sesión incorporada de Looker para el usuario que llama, se debe incluir en la llamada el token de referencia de sesión asociado. Este proceso se explicará con más detalle en la sección Adquirir sesión de este documento.
- El procesamiento de extremos de la sesión de incorporación adquirida es similar al extremo
/login/embed/{signed url)
firmado por SSO, ya que espera que la definición del usuario de incorporación de Looker sea el cuerpo de la solicitud, en lugar de la URL. El proceso de adquisición de extremos de sesión de incorporación valida y crea o actualiza el usuario de incorporación. También puede aceptar un token de referencia de sesión existente. Esto es importante, ya que permite que varios iframes incorporados de Looker compartan la misma sesión. El usuario de incorporación no se actualizará si se proporciona un token de referencia de sesión y esta no venció. Esto admite el caso de uso en el que se crea un iframe con una URL de SSO firmada y otros iframes se crean sin una URL de SSO firmada. En este caso, los iframes sin URL de SSO firmadas heredarán la cookie de la primera sesión. - La llamada a la API de Looker muestra cuatro tokens, cada uno con un tiempo de actividad (TTL):
- Token de autorización (TTL = 30 segundos)
- Token de navegación (TTL = 10 minutos)
- Token de API (TTL = 10 minutos)
- Token de referencia de la sesión (TTL = ciclo de vida restante de la sesión)
- El servidor de aplicaciones de incorporación debe realizar un seguimiento de los datos que muestran los datos de Looker y asociarlos al usuario que llama y al usuario-agente del navegador del usuario que lo llama. Las sugerencias para hacerlo se proporcionan en la sección Generar tokens de este documento. Esta llamada mostrará el token de autorización, un token de navegación y un token de API, junto con todos los TTL asociados. El token de referencia de la sesión debe estar protegido y no debe exponerse en el navegador que lo llama.
Una vez que se devuelven los tokens al navegador, se debe construir una URL de acceso de incorporación de Looker. El SDK de incorporación de Looker creará automáticamente la URL de acceso de incorporación. Si quieres usar la API de
windows.postMessage
para crear la URL de acceso de incorporación, consulta la sección Cómo usar la API dewindows.postMessage
de Looker de este documento para obtener ejemplos.La URL de acceso no contiene los detalles del usuario de la incorporación firmada. Contiene el URI de destino, incluido el token de navegación y el token de autorización como un parámetro de consulta. El token de autorización se debe usar en un plazo de 30 segundos y solo se puede usar una vez. Si se requieren iframes adicionales, se debe volver a adquirir una sesión de incorporación. Sin embargo, si se proporciona el token de referencia de sesión, este se asociará a la misma sesión.
El extremo de acceso de incorporación de Looker determina si el acceso es para la incorporación sin cookies, lo que se indica por la presencia del token de autorización. Si el token de autorización es válido, se verifica lo siguiente:
- La sesión asociada sigue siendo válida.
- El usuario de incorporación asociado aún es válido.
- El usuario-agente del navegador asociado con la solicitud coincide con el usuario-agente del navegador que está asociado con la sesión.
Si se pasan las verificaciones del paso anterior, la solicitud se redirecciona con el URI de destino que se incluye en la URL. Este es el mismo proceso que para el acceso de SSO de Looker Embed.
Esta solicitud es el redireccionamiento para iniciar el panel de Looker. Esta solicitud tendrá el token de navegación como parámetro.
Antes de ejecutar el extremo, el servidor de Looker busca el token de navegación en la solicitud. Si el servidor encuentra el token, verifica lo siguiente:
- La sesión asociada sigue siendo válida.
- El usuario-agente del navegador asociado con la solicitud coincide con el usuario-agente del navegador que está asociado con la sesión.
Si es válida, se restablece la sesión de la solicitud y se ejecuta la solicitud del panel.
El código HTML para cargar el panel se muestra en el iframe.
La IU de Looker que se ejecuta en el iframe determina que el HTML del panel es una respuesta de incorporación sin cookies. En ese momento, la IU de Looker envía un mensaje a la aplicación de incorporación para solicitar los tokens que se recuperaron en el paso 6. Luego, la IU espera hasta recibir los tokens. Si no llegan los tokens, se mostrará un mensaje.
La aplicación de incorporación envía los tokens al iframe incorporado de Looker.
Cuando se reciben los tokens, la IU de Looker que se ejecuta en el iframe comienza el proceso para renderizar el objeto de solicitud. Durante este proceso, la IU realizará llamadas a la API en el servidor de Looker. El token de la API que se recibió en el paso 15 se inserta automáticamente como un encabezado en todas las solicitudes a la API.
Antes de que se ejecute cualquier extremo, el servidor de Looker busca el token de la API en la solicitud. Si el servidor encuentra el token, verifica lo siguiente:
- La sesión asociada sigue siendo válida.
- El usuario-agente del navegador asociado con la solicitud coincide con el usuario-agente del navegador que está asociado con la sesión.
Si la sesión es válida, se restablece para la solicitud y se ejecuta la solicitud a la API.
Se muestran los datos del panel.
Se renderiza el panel.
El usuario controla el panel.
Genera tokens nuevos
- La IU de Looker que se ejecuta en el iframe incorporado supervisa el TTL de los tokens incorporados.
- Cuando los tokens se acercan al vencimiento, la IU de Looker envía un mensaje de token de actualización al cliente de la aplicación incorporada.
- Luego, el cliente de la aplicación de incorporación solicita nuevos tokens desde un extremo que se implementa en el servidor de aplicaciones de incorporación. El SDK de Embed de Looker solicitará tokens nuevos automáticamente, pero se debe proporcionar la URL del extremo o una función de devolución de llamada. Si se usa la función de devolución de llamada, llamará al servidor de la aplicación incorporada para generar tokens nuevos. De lo contrario, el SDK de Embed llamará a la URL del extremo proporcionada.
- La aplicación de incorporación busca el
session_reference_token
que está asociado con la sesión incorporada. En el ejemplo proporcionado en el repositorio de Git del SDK de incorporación de Looker, se usan cookies de sesión, pero también se puede usar una caché distribuida del servidor, Redis, por ejemplo. - El servidor de aplicaciones de incorporación llama al servidor de Looker con una solicitud para generar tokens. Esta solicitud también requiere tokens recientes de API y navegación, además del usuario-agente del navegador que inició la solicitud.
- El servidor de Looker valida al usuario-agente, el token de referencia de sesión, el token de navegación y el token de la API. Si la solicitud es válida, se generan tokens nuevos.
- Los tokens se devuelven al servidor de aplicaciones incorporado de llamada.
- El servidor de aplicaciones de incorporación quita el token de referencia de sesión de la respuesta y muestra la respuesta restante al cliente de la aplicación de incorporación.
- El cliente de aplicación de incorporación envía los tokens recién generados a la IU de Looker. El SDK de incorporación de Looker hará esto automáticamente. La incorporación de clientes de aplicaciones que usen la API de
windows.postMessage
será responsable de enviar los tokens. Una vez que la IU de Looker reciba los tokens, se usarán en las llamadas a la API y en las navegaciones de páginas posteriores.
Implementa la incorporación sin cookies de Looker
La incorporación sin cookies de Looker se puede implementar mediante el SDK de Embed de Looker o la API de windows.postMessage
. El método que usa el SDK de Embed de Looker es más fácil, pero también está disponible un ejemplo que muestra cómo usar la API de windows.postMessage
. Puedes encontrar explicaciones detalladas de ambas implementaciones en el archivo README del SDK de Embed de Looker. El repositorio de Git del SDK de Embed también contiene implementaciones activas.
Configura la instancia de Looker
La incorporación sin cookies es común en la incorporación de inicio de sesión único (SSO) de Looker. La incorporación sin cookies depende de que esté habilitada la autenticación SSO de incorporación. Sin embargo, a diferencia de lo que sucede en Looker SSO, la incorporación sin cookies no usa el parámetro de configuración Embed Secret. La incorporación sin cookies usa un token web JSON (JWT) con el formato Secret JWT Secret, que se puede configurar o restablecer en la página Embed de la sección Platform del menú Admin.
No se requiere la configuración del secreto JWT, ya que el primer intento de crear una sesión de incorporación sin cookies creará el JWT. Evita restablecer este token, ya que se invalidarán todas las sesiones activas de incorporación sin cookies.
A diferencia del secreto de incorporación, el secreto de JWT incorporado nunca se expone, ya que solo se usa de forma interna en el servidor de Looker.
Implementación del cliente de la aplicación
Esta sección incluye ejemplos de cómo implementar la incorporación sin cookies en el cliente de la aplicación y contiene las siguientes subsecciones:
- Instala y actualiza el SDK de incorporación de Looker
- Usa el SDK de incorporación de Looker
- Usa la API de
windows.postMessage
de Looker
Instala o actualiza el SDK de incorporación de Looker
Se requieren las siguientes versiones del SDK de Looker para usar la incorporación sin cookies:
@looker/embed-sdk >= 1.8
@looker/sdk >= 22.16.0
Cómo usar el SDK de incorporación de Looker
Se agregó un nuevo método de inicialización al SDK de Embed para iniciar la sesión sin cookies. Este método acepta dos strings de URL o dos funciones de devolución de llamada. Las strings de URL deben hacer referencia a los extremos en el servidor de aplicaciones de incorporación. Los detalles de implementación de estos extremos en el servidor de aplicaciones se abordan en la sección Implementación del servidor de aplicaciones de este documento.
LookerEmbedSDK.initCookieless(
runtimeConfig.lookerHost,
'/acquire-embed-session',
'/generate-embed-tokens'
)
En el siguiente ejemplo, se muestra cómo se usan las devoluciones de llamada. Las devoluciones de llamada solo se deben usar cuando sea necesario que la aplicación cliente de incorporación conozca el estado de la sesión de incorporación de Looker. También puedes usar el evento session:status
, por lo que no es necesario usar devoluciones de llamada con el SDK de Embed.
const acquireEmbedSessionCallback =
async (): Promise<LookerEmbedCookielessSessionData> => {
const resp = await fetch('/acquire-embed-session')
if (!resp.ok) {
console.error('acquire-embed-session failed', { resp })
throw new Error(
`acquire-embed-session failed: ${resp.status} ${resp.statusText}`
)
}
return (await resp.json()) as LookerEmbedCookielessSessionData
}
const generateEmbedTokensCallback =
async (): Promise<LookerEmbedCookielessSessionData> => {
const { api_token, navigation_token } = getApplicationTokens() || {}
const resp = await fetch('/generate-embed-tokens', {
method: 'PUT',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ api_token, navigation_token }),
})
if (!resp.ok) {
if (resp.status === 400) {
return { session_reference_token_ttl: 0 }
}
console.error('generate-embed-tokens failed', { resp })
throw new Error(
`generate-embed-tokens failed: ${resp.status} ${resp.statusText}`
)
}
return (await resp.json()) as LookerEmbedCookielessSessionData
}
LookerEmbedSDK.initCookieless(
runtimeConfig.lookerHost,
acquireEmbedSessionCallback,
generateEmbedTokensCallback
)
Usa la API de windows.postMessage
de Looker
Puedes ver un ejemplo detallado de cómo usar la API de windows.postMessage
en los archivos message_example.ts
y message_utils.ts
en el repositorio de Git del SDK de Embed. Los puntos destacados del ejemplo se detallan aquí.
En el siguiente ejemplo, se muestra cómo compilar la URL del iframe. La función de devolución de llamada es idéntica al ejemplo de acquireEmbedSessionCallback
que se vio antes.
private async getCookielessLoginUrl(): Promise<string> {
const { authentication_token, navigation_token } =
await this.embedEnvironment.acquireSession()
const url = this.embedUrl.startsWith('/embed')
? this.embedUrl
: `/embed${this.embedUrl}`
const embedUrl = new URL(url, this.frameOrigin)
if (!embedUrl.searchParams.has('embed_domain')) {
embedUrl.searchParams.set('embed_domain', window.location.origin)
}
embedUrl.searchParams.set('embed_navigation_token', navigation_token)
const targetUri = encodeURIComponent(
`${embedUrl.pathname}${embedUrl.search}${embedUrl.hash}`
)
return `${embedUrl.origin}/login/embed/${targetUri}?embed_authentication_token=${authentication_token}`
}
En el siguiente ejemplo, se muestra cómo escuchar solicitudes de tokens, generar tokens nuevos y enviarlos a Looker. La función de devolución de llamada es idéntica al ejemplo de generateEmbedTokensCallback
anterior.
this.on(
'session:tokens:request',
this.sessionTokensRequestHandler.bind(this)
)
private connected = false
private async sessionTokensRequestHandler(_data: any) {
const contentWindow = this.getContentWindow()
if (contentWindow) {
if (!this.connected) {
// When not connected the newly acquired tokens can be used.
const sessionTokens = this.embedEnvironment.applicationTokens
if (sessionTokens) {
this.connected = true
this.send('session:tokens', this.embedEnvironment.applicationTokens)
}
} else {
// If connected, the embedded Looker application has decided that
// it needs new tokens. Generate new tokens.
const sessionTokens = await this.embedEnvironment.generateTokens()
this.send('session:tokens', sessionTokens)
}
}
}
send(messageType: string, data: any = {}) {
const contentWindow = this.getContentWindow()
if (contentWindow) {
const message: any = {
type: messageType,
...data,
}
contentWindow.postMessage(JSON.stringify(message), this.frameOrigin)
}
return this
}
Implementación del servidor de aplicaciones
Esta sección incluye ejemplos de cómo implementar la incorporación sin cookies en el servidor de aplicaciones y contiene las siguientes subsecciones:
Implementación básica
La aplicación de incorporación es necesaria para implementar dos extremos del servidor que invocarán los extremos de Looker. Esto permite garantizar que el token de referencia de la sesión permanezca seguro. Estos son los extremos:
- Adquirir sesión: Si ya existe un token de referencia de sesión y aún está activo, las solicitudes de una sesión se unirán a la sesión existente. Se llama a la sesión de adquisición cuando se crea un iframe.
- Generar tokens: Looker activa llamadas a este extremo de forma periódica.
Sesión de adquisición
En este ejemplo de TypeScript, se usa la sesión para guardar o restablecer el token de referencia de sesión. No es necesario implementar el extremo en TypeScript.
app.get(
'/acquire-embed-session',
async function (req: Request, res: Response) {
try {
const current_session_reference_token =
req.session && req.session.session_reference_token
const response = await acquireEmbedSession(
req.headers['user-agent']!,
user,
current_session_reference_token
)
const {
authentication_token,
authentication_token_ttl,
navigation_token,
navigation_token_ttl,
session_reference_token,
session_reference_token_ttl,
api_token,
api_token_ttl,
} = response
req.session!.session_reference_token = session_reference_token
res.json({
api_token,
api_token_ttl,
authentication_token,
authentication_token_ttl,
navigation_token,
navigation_token_ttl,
session_reference_token_ttl,
})
} catch (err: any) {
res.status(400).send({ message: err.message })
}
}
)
async function acquireEmbedSession(
userAgent: string,
user: LookerEmbedUser,
session_reference_token: string
) {
await acquireLookerSession()
try {
const request = {
...user,
session_reference_token: session_reference_token,
}
const sdk = new Looker40SDK(lookerSession)
const response = await sdk.ok(
sdk.acquire_embed_cookieless_session(request, {
headers: {
'User-Agent': userAgent,
},
})
)
return response
} catch (error) {
console.error('embed session acquire failed', { error })
throw error
}
}
A partir de Looker 23.8, el dominio de incorporación se puede incluir cuando se adquiere la sesión sin cookies. Esta es una alternativa a agregar el dominio incorporado con el panel Administrar > Incorporar de Looker. Looker guarda el dominio incorporado en la base de datos interna de Looker, por lo que no se mostrará en el panel Admin > Embed. En cambio, el dominio de incorporación se asocia con la sesión sin cookies y existe solo durante la sesión. Revisa las prácticas recomendadas de seguridad si decides aprovechar esta función.
Generar tokens
En este ejemplo de TypeScript, se usa la sesión para guardar o restablecer el token de referencia de sesión. No es necesario implementar el extremo en TypeScript.
Es importante que sepa cómo manejar las respuestas 400, que se producen cuando los tokens no son válidos. Esto no debería suceder, pero, si es así, se recomienda finalizar la sesión.
app.put(
'/generate-embed-tokens',
async function (req: Request, res: Response) {
try {
const session_reference_token = req.session!.session_reference_token
const { api_token, navigation_token } = req.body as any
const tokens = await generateEmbedTokens(
req.headers['user-agent']!,
session_reference_token,
api_token,
navigation_token
)
res.json(tokens)
} catch (err: any) {
res.status(400).send({ message: err.message })
}
}
)
}
async function generateEmbedTokens(
userAgent: string,
session_reference_token: string,
api_token: string,
navigation_token: string
) {
if (!session_reference_token) {
console.error('embed session generate tokens failed')
// missing session reference treat as expired session
return {
session_reference_token_ttl: 0,
}
}
await acquireLookerSession()
try {
const sdk = new Looker40SDK(lookerSession)
const response = await sdk.ok(
sdk.generate_tokens_for_cookieless_session(
{
api_token,
navigation_token,
session_reference_token: session_reference_token || '',
},
{
headers: {
'User-Agent': userAgent,
},
}
)
)
return {
api_token: response.api_token,
api_token_ttl: response.api_token_ttl,
navigation_token: response.navigation_token,
navigation_token_ttl: response.navigation_token_ttl,
session_reference_token_ttl: response.session_reference_token_ttl,
}
} catch (error: any) {
if (error.message?.includes('Invalid input tokens provided')) {
// Currently the Looker UI does not know how to handle bad
// tokens. This should not happen but if it does expire the
// session. If the token is bad there is not much that that
// the Looker UI can do.
return {
session_reference_token_ttl: 0,
}
}
console.error('embed session generate tokens failed', { error })
throw error
}
Consideraciones sobre la implementación
La aplicación de incorporación debe realizar un seguimiento del token de referencia de la sesión y debe mantenerse seguro. Este token debe estar asociado con el usuario de la aplicación incorporado. El token de aplicación de incorporación se puede almacenar de una de las siguientes maneras:
- En la sesión del usuario de la aplicación incorporada
- En una caché del servidor que está disponible en un entorno agrupado
- En una tabla de base de datos asociada con el usuario
Si la sesión se almacena como una cookie, esta debe encriptarse. En el ejemplo del repositorio del SDK de incorporación, se usa una cookie de sesión para almacenar el token de referencia de sesión.
Cuando venza la sesión incorporada de Looker, se mostrará un diálogo en el iframe incorporado. En este punto, el usuario no podrá hacer nada en la instancia incorporada. Cuando esto ocurre, se generarán los eventos session:status
, lo que permitirá a la aplicación de incorporación detectar el estado actual de la aplicación de Looker incorporada y realizar algún tipo de acción.
Ejecuta el ejemplo de incorporación sin cookies de Looker
El repositorio del SDK de incorporación contiene un cliente Express y un servidor simple escrito en TypeScript que implementa una aplicación de incorporación simple. Los ejemplos que se muestran anteriormente se toman de esta implementación. En el siguiente ejemplo, se supone que tu instancia de Looker está configurada para usar incorporaciones sin cookies como se describió antes.
Puedes ejecutar el servidor de la siguiente manera:
- Clona el repositorio del SDK de Embed:
git clone git@github.com:looker-open-source/embed-sdk.git
- Cambia el directorio:
cd embed-sdk
. - Instala las dependencias:
npm install
- Configura el servidor, como se muestra en la sección Configura el servidor de este documento.
- Ejecuta el servidor:
npm run server
Configura el servidor
Crea un archivo .env
en la raíz del repositorio clonado (esto se incluye en .gitignore
).
El formato es el siguiente:
LOOKER_EMBED_HOST=your-looker-instance-url.com.
LOOKER_EMBED_API_URL=https://your-looker-instance-url.com
LOOKER_DEMO_HOST=localhost
LOOKER_DEMO_PORT=8080
LOOKER_EMBED_SECRET=embed-secret-from-embed-admin-page
LOOKER_CLIENT_ID=client-id-from-user-admin-page
LOOKER_CLIENT_SECRET=client-secret-from-user-admin-page
LOOKER_DASHBOARD_ID=id-of-dashboard
LOOKER_LOOK_ID=id-of-look
LOOKER_EXPLORE_ID=id-of-explore
LOOKER_EXTENSION_ID=id-of-extension
LOOKER_VERIFY_SSL=true