Tableau Embedding

2023년 03월 01일
3

Tableau Server에서 설정

Tableau Embedding API Version 2

Tableau Embedding API Version 3

cd /opt/tableau/tableau_server/
tsm configuration get -k gateway.public.host
#server.tableau.com
tsm configuration get -k gateway.trusted
#127.0.0.1, 127.0.0.2
tsm configuration get -k gateway.trusted_hosts
#server.tableau.com
tsm configuration get -k gateway.public.port
#443
 
tsm configuration get -k vizportal.rest_api.cors.enabled
#true
tsm configuration get -k vizportal.rest_api.cors.allow_origin
#https://127.0.0.1 https://server.tableau.com, https://127.0.0.2, https://web.tableau.com
tsm configuration get -k wgserver.unrestricted_ticket
#true
tsm configuration get -k wgserver.clickjack_defense.enabled
#false
tsm configuration get -k vizportal.oauth.external_authorization_server.max_expiration_period_in_minutes
#600
 
tsm pending-changes apply

Window

  1. hosts 파일 우클릭 > Code(으)로 열기 > 수정 > 저장 > "Failed to save 'hosts': Insufficient permissions.
  2. Select 'Retry as Admin' to retry as administrator."라는 알림창이 뜨면 [Retry as Admin...] 클릭 > Windows 명령 처리기 [예] 클릭
127.0.0.1 server.tableau.com
127.0.0.2 web.tableau.com

Mac

sudo vim /private/etc/hosts #i
 
127.0.0.1 server.tableau.com
127.0.0.2 web.tableau.com
 
# :wq

*.tableau.com로 Domain 맞춰서 SameSite Error 해결

Python, Java, JavaScript로 구현

token이 제대로 됐는지 https://jwt.io/에서 확인

import jwt
token = jwt.encode(
	{
		"iss": connectedAppClientId,
		"exp": datetime.datetime.utcnow() + datetime.timedelta(minutes=5),
		"jti": str(uuid.uuid4()),
		"aud": "tableau",
		"sub": user,
		"scp": ["tableau:views:embed", "tableau:metrics:embed"]
	},
		connectedAppSecretKey,
		algorithm = "HS256",
		headers = {
		'kid': connectedAppSecretId,
		'iss': connectedAppClientId
        }
  )
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jwt.*;
 
import java.util.*;
 
...
 
String secret = "secretvalue";
	String kid = "connectedAppSecretId";
	String clientId = "connectedAppClientId";
	List<String> scopes = new
ArrayList<>(Arrays.asList("tableau:views:embed"));
	String username = "username";
	JWSSigner signer = new MACSigner(secret);
	JWSHeader header = new
JWSHeader.Builder(JWSAlgorithm.HS256).keyID(kid).customParam("iss", clientId).build();
	JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
		.issuer(clientId)
		.expirationTime(new Date(new Date().getTime() + 60 * 1000)) //expires in 1 minute
		.jwtID(UUID.randomUUID().toString())
		.audience("tableau")
		.subject(username)
		.claim("scp", scopes)
		.build();
	SignedJWT signedJWT = new SignedJWT(header, claimsSet);
	signedJWT.sign(signer);
	model.addAttribute("token", signedJWT.serialize());
import { Injectable } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { v4 as uuid } from 'uuid';
import * as config from 'config';
 
const tableauConfig = config.get('tableau');
 
@Injectable()
export class TableauService {
	constructor(private jwtService: JwtService) {}
 
	async getTableauToken(username: string){
		const token = await this.jwtService.sign(
			{
				iss: tableauConfig.connectedAppClientId,
				aud: 'tableau',
				jti: uuid(),
				sub: username,
				scp: [
					'tableau:view:embed',
					'tableau:views:embed_authoring',
				],
			},
			{
				header: {
					alg: 'HS256',
					kid: tableauConfig.connectedAppSecretId,
					iss: tableauConfig.connectedAppClientId,
				},
				secret: tableauConfig.secretvalue,
				expiresIn: '5m',
			},
		);
		return token;
	}
}