Tableau Embedding

Tableau Server에서 설정

Tableau Embedding API Version 2

Tableau Embedding API Version 3

tsm(Tableau Server Manager)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 명령 처리기 [예] 클릭
C:\Windows\System32\drivers\etc\hosts
1
2
127.0.0.1 server.tableau.com
127.0.0.2 web.tableau.com

Mac

Mac(iterm, terminal)
1
2
3
4
5
6
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/에서 확인

JSONWebToken.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
}
)
JSONWebToken.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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());
nest.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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;
}
}
Author

Joy

Posted on

2023-03-01

Updated on

2023-07-31

Licensed under

댓글