add dataset & scopes to token (#20)
This commit is contained in:
Родитель
854451d8a5
Коммит
1b2eec94a9
44
README.md
44
README.md
|
@ -43,7 +43,7 @@ Each API call sets the following HTTP header:
|
|||
|
||||
## Creating Embed Tokens
|
||||
Power BI Embedded uses embed token, which are HMAC signed JSON Web Tokens. The tokens are signed with the access key from your Azure Power BI Embedded workspace collection.
|
||||
Embed tokens are used to provide read only access to a report to embed into an application.
|
||||
Embed tokens, by default, are used to provide read only access to a report to embed into an application.
|
||||
|
||||
### Required Claims
|
||||
- ver: 0.2.0
|
||||
|
@ -87,3 +87,45 @@ The following decoded JSON web token
|
|||
"nbf": 1360043456
|
||||
}
|
||||
```
|
||||
|
||||
## Adding Permission Scopes to Embed Tokens
|
||||
When using Embed tokens, one might want to restrict usage of the resources he gives access to. For this reason, you can generate a token with scoped permissions.
|
||||
|
||||
### Required Claims - Scopes
|
||||
- scp: {scopesClaim}
|
||||
scopesClaim can be either a string or array of strings, noting the allowed permissions to workspace resources (Report, Dataset, etc.)
|
||||
|
||||
```javascript
|
||||
var powerbi = require('powerbi-api');
|
||||
var reportReadScope = 'Report.Read';
|
||||
var token = powerbi.PowerBIToken.createReportEmbedToken('{WorkspaceCollection}', '{workspaceId}', '{reportId}', '{scopes}');
|
||||
|
||||
var jwt = token.generate('{AccessKey}');
|
||||
```
|
||||
|
||||
## Token Example - With Scopes
|
||||
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXIiOiIwLjIuMCIsIndjbiI6IlN1cHBvcnREZW1vIiwid2lkIjoiY2E2NzViMTktNmMzYy00MDAzLTg4MDgtMWM3ZGRjNmJkODA5IiwicmlkIjoiOTYyNDFmMGYtYWJhZS00ZWE5LWEwNjUtOTNiNDI4ZWRkYjE3Iiwic2NwIjoiUmVwb3J0LlJlYWQiLCJpc3MiOiJQb3dlckJJU0RLIiwiYXVkIjoiaHR0cHM6Ly9hbmFseXNpcy53aW5kb3dzLm5ldC9wb3dlcmJpL2FwaSIsImV4cCI6MTM2MDA0NzA1NiwibmJmIjoxMzYwMDQzNDU2fQ.M1jkWXnkfwJeGQqh1x0vIAYB4EBKbHSZFoDB6n_LZyA
|
||||
|
||||
### Decoded
|
||||
The following decoded JSON web token
|
||||
**Header**
|
||||
```javascript
|
||||
{
|
||||
"typ": "JWT",
|
||||
"alg": "HS256"
|
||||
}
|
||||
```
|
||||
|
||||
**Payload**
|
||||
```javascript
|
||||
{
|
||||
"ver": "0.2.0",
|
||||
"wcn": "SupportDemo",
|
||||
"wid": "ca675b19-6c3c-4003-8808-1c7ddc6bd809",
|
||||
"rid": "96241f0f-abae-4ea9-a065-93b428eddb17",
|
||||
"scp": "Report.Read",
|
||||
"iss": "PowerBISDK",
|
||||
"aud": "https://analysis.windows.net/powerbi/api",
|
||||
"exp": 1360047056,
|
||||
"nbf": 1360043456
|
||||
}
|
||||
|
|
|
@ -14,18 +14,28 @@ export class PowerBIToken {
|
|||
};
|
||||
}
|
||||
|
||||
public static createReportEmbedToken(workspaceCollectionName: string, workspaceId: string, reportId: string, username: string = null, roles: string|string[] = null, expiration: Date = null): PowerBIToken {
|
||||
public static createReportEmbedToken(workspaceCollectionName: string, workspaceId: string, reportId?: string, datasetId?: string, scopes: string|string[] = '', username: string = null, roles: string|string[] = null, expiration: Date = null): PowerBIToken {
|
||||
|
||||
if (roles && !username)
|
||||
{
|
||||
if (roles && !username) {
|
||||
throw new Error('Cannot have an empty or null Username claim with the non-empty Roles claim');
|
||||
}
|
||||
|
||||
if (!reportId && !datasetId) {
|
||||
throw new Error('Token must contain either reportId or datasetId claim');
|
||||
}
|
||||
|
||||
var token = new PowerBIToken(expiration);
|
||||
token.addClaim('wcn', workspaceCollectionName);
|
||||
token.addClaim('wid', workspaceId);
|
||||
token.addClaim('rid', reportId);
|
||||
|
||||
if (reportId) {
|
||||
token.addClaim('rid', reportId);
|
||||
}
|
||||
|
||||
if (datasetId) {
|
||||
token.addClaim('did', datasetId);
|
||||
}
|
||||
|
||||
if(username != null) {
|
||||
token.addClaim('username', username);
|
||||
|
||||
|
@ -34,6 +44,14 @@ export class PowerBIToken {
|
|||
}
|
||||
}
|
||||
|
||||
if (scopes) {
|
||||
if (Array.isArray(scopes)) {
|
||||
scopes = (<string[]>scopes).join(' ');
|
||||
}
|
||||
|
||||
token.addClaim('scp', scopes);
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "powerbi-api",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "Node client library for Power BI API",
|
||||
"main": "./lib/index.js",
|
||||
"typings": "./lib/index.d.ts",
|
||||
|
|
|
@ -11,8 +11,12 @@ describe('Power BI Token', () => {
|
|||
const workspacCollection: string = 'TestCollection';
|
||||
const workspaceId: string = 'fd41b1db-9e26-4103-99a7-f9ad336b99a7';
|
||||
const reportId: string = 'fe607ad3-97bf-4dd5-98eb-db4a4d5de4e0';
|
||||
const datasetId: string = 'fe123ad3-97bf-4dd5-98eb-db7c432de4e0';
|
||||
const accessKey: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
|
||||
const username: string = 'TestUser';
|
||||
const scopes: string = 'Scope1';
|
||||
const scopesArray: string[] = ['Scope1', 'Scope2'];
|
||||
const scopesArrayDecoded: string = 'Scope1 Scope2';
|
||||
|
||||
it('is defined', () => {
|
||||
expect(powerbi.PowerBIToken).to.exist;
|
||||
|
@ -66,6 +70,13 @@ describe('Power BI Token', () => {
|
|||
expect(jwt).not.to.be.null;
|
||||
});
|
||||
|
||||
it('can be created for datasetId', () => {
|
||||
let token = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, null, datasetId);
|
||||
let jwt = token.generate(accessKey);
|
||||
|
||||
expect(jwt).not.to.be.null;
|
||||
});
|
||||
|
||||
it('are created with a default expiration', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
|
@ -78,12 +89,75 @@ describe('Power BI Token', () => {
|
|||
expect(decoded.exp).to.equal(exp)
|
||||
});
|
||||
|
||||
it('are created with the correct claims - minimal params', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
let expiration = new Date(exp * 1000);
|
||||
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId);
|
||||
let token = embedToken.generate(accessKey);
|
||||
let decoded = jwt.decode(token, accessKey);
|
||||
|
||||
expect(decoded.ver).to.equal(version);
|
||||
expect(decoded.aud).to.equal(resource);
|
||||
expect(decoded.iss).to.equal(issuer);
|
||||
expect(decoded.wcn).to.equal(workspacCollection);
|
||||
expect(decoded.wid).to.equal(workspaceId);
|
||||
expect(decoded.rid).to.equal(reportId);
|
||||
});
|
||||
|
||||
it('are created with the correct claims', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
let expiration = new Date(exp * 1000);
|
||||
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, username, 'TestRole', expiration);
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, datasetId, scopes, username, 'TestRole', expiration);
|
||||
let token = embedToken.generate(accessKey);
|
||||
let decoded = jwt.decode(token, accessKey);
|
||||
|
||||
expect(decoded.ver).to.equal(version);
|
||||
expect(decoded.aud).to.equal(resource);
|
||||
expect(decoded.iss).to.equal(issuer);
|
||||
expect(decoded.wcn).to.equal(workspacCollection);
|
||||
expect(decoded.wid).to.equal(workspaceId);
|
||||
expect(decoded.rid).to.equal(reportId);
|
||||
expect(decoded.did).to.equal(datasetId);
|
||||
expect(decoded.nbf).to.equal(nbf);
|
||||
expect(decoded.exp).to.equal(exp);
|
||||
expect(decoded.scp).to.equal(scopes);
|
||||
expect(decoded.username).to.equal(username);
|
||||
expect(decoded.roles).to.equal('TestRole');
|
||||
});
|
||||
|
||||
it('are created with the correct claims - datasetId only', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
let expiration = new Date(exp * 1000);
|
||||
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, null, datasetId, scopes, username, 'TestRole', expiration);
|
||||
let token = embedToken.generate(accessKey);
|
||||
let decoded = jwt.decode(token, accessKey);
|
||||
|
||||
expect(decoded.ver).to.equal(version);
|
||||
expect(decoded.aud).to.equal(resource);
|
||||
expect(decoded.iss).to.equal(issuer);
|
||||
expect(decoded.wcn).to.equal(workspacCollection);
|
||||
expect(decoded.wid).to.equal(workspaceId);
|
||||
expect(decoded.rid).to.be.undefined;
|
||||
expect(decoded.did).to.equal(datasetId);
|
||||
expect(decoded.nbf).to.equal(nbf);
|
||||
expect(decoded.exp).to.equal(exp);
|
||||
expect(decoded.scp).to.equal(scopes);
|
||||
expect(decoded.username).to.equal(username);
|
||||
expect(decoded.roles).to.equal('TestRole');
|
||||
});
|
||||
|
||||
it('are created with the correct claims - scopes as array', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
let expiration = new Date(exp * 1000);
|
||||
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, null, scopesArray, username, 'TestRole', expiration);
|
||||
let token = embedToken.generate(accessKey);
|
||||
let decoded = jwt.decode(token, accessKey);
|
||||
|
||||
|
@ -95,17 +169,18 @@ describe('Power BI Token', () => {
|
|||
expect(decoded.rid).to.equal(reportId);
|
||||
expect(decoded.nbf).to.equal(nbf);
|
||||
expect(decoded.exp).to.equal(exp);
|
||||
expect(decoded.scp).to.equal(scopesArrayDecoded);
|
||||
expect(decoded.username).to.equal(username);
|
||||
expect(decoded.roles).to.equal('TestRole');
|
||||
});
|
||||
|
||||
|
||||
it('are created with multiple RLS roles', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
let expiration = new Date(exp * 1000);
|
||||
let roles = ['TestRole1', 'TestRole2'];
|
||||
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, username, roles, expiration);
|
||||
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, datasetId, scopes, username, roles, expiration);
|
||||
let token = embedToken.generate(accessKey);
|
||||
let decoded = jwt.decode(token, accessKey);
|
||||
|
||||
|
@ -113,6 +188,12 @@ describe('Power BI Token', () => {
|
|||
expect(decoded.roles).to.eql(roles);
|
||||
});
|
||||
|
||||
it('fail to create when missing reportId and datasetId', () => {
|
||||
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId))
|
||||
.to
|
||||
.throw('Token must contain either reportId or datasetId claim');
|
||||
});
|
||||
|
||||
it('fail to create when RLS username is empty and roles is not', () => {
|
||||
let nbf = powerbi.Util.getUnixTime(new Date());
|
||||
let exp = nbf + 3600;
|
||||
|
@ -121,7 +202,7 @@ describe('Power BI Token', () => {
|
|||
let badUsernames = [null, undefined, ''];
|
||||
|
||||
badUsernames.forEach(badUsername => {
|
||||
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId, reportId, badUsername, role, expiration))
|
||||
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId, reportId, datasetId, scopes, badUsername, role, expiration))
|
||||
.to
|
||||
.throw('Cannot have an empty or null Username claim with the non-empty Roles claim');
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче