Dans cet article nous allons voir comment sécuriser dynamiquement l’accès aux dimensions ayant une hiérarchie Parent/Child dans un cube SSAS.
Il s’agit ici de limiter la vue des membres d’une dimension en utilisant la fonction MDX UserName qui renvoie l’ID de l’utilisateur connecté.
Nous allons prendre comme exemple la dimension Employee du Cube AdventureWorks.
Nous voulons définir un rôle unique qui sera utilisé par tous les employés. Dans ce rôle, nous voulons appliquer la sécurité de telle sorte que chaque employé n’ai accès qu’à ces données et celles de ces descendants.
Pour cela il faudra rajouter à notre Cube :
Une Dimension Users
Il nous faudra créer une dimension technique qui contient uniquement deux attributs : Un ID technique et les identifiants Windows des employées.
CREATE TABLE [dbo].[Users]( [IdUser] [int] identity (1,1) NOT NULL, [Login] [nvarchar](100) NULL ) ON [PRIMARY] INSERT INTO [dbo].[Users] SELECT DISTINCT [LoginID] FROM [dbo].[DimEmployee]
Une Table de bridge
La table de bridge est une table qui permet de créer la correspondance entre l’IdUser de la table Users créer précédemment et l’EmployeeKey de la table DimEmployee.
CREATE TABLE [dbo].[BridgeSecurity]( [IdUser] [int] NULL, [EmployeeKey] [int] NULL ) INSERT INTO [dbo].[BridgeSecurity] SELECT [IdUser] ,[EmployeeKey] FROM [dbo].[DimEmployee] emp INNER JOIN [dbo].[Users] usr ON usr.[Login] = emp.LoginID
Il faudra ensuite rajouter ces deux tables à la DSV du cube AdventureWorks en spécifiant les relations comme ceci:
La table BridgeSecurity sera considérée comme un groupe de mesure et la table Users comme une dimension. Il faudra veiller à mettre leur visibilité à False afin de ne pas créer la confusion lors de l’exploration du cube par les utilisateurs.
Une fois le groupe de mesure et la dimension crées dans le cube, dans l’onglet Dimension Usage, les liens entre le groupe de mesure et les dimensions doivent ressembler à ceci :
Maintenant l’étape la plus délicate qui consiste via MDX à sécuriser le cube suivant la hiérarchie de dimension Parent/Child.
Après création d’un nouveau Rôle, dans l’onglet Dimension Data, sélectionner l’attribut Employees de la dimension Employee.
Dans l’onglet Advanced, coller le code suivant :
Generate ( NonEmpty ( [Employee].[Employee] .[Employee].Members, ( [Measures].[Employee Count], StrToMember ('[Users].[User].[' + UserName () + ']') ) ), { LinkMember ( Employee.Employee.CurrentMember, Employee.Employees ) }
- La fonction Generate applique un jeu à chaque membre d’un autre jeu, puis effectue la jointure par union des jeux résultants, dans notre cas retourne les membres de la dimension Employee pour lesquels l‘utilisateur a accès.
- La fonction UserName ( ) retourne le nom de l’utilisateur actuel, on rajoute la fonction StrToMember qui retourne le membre spécifié d’une chaîne au format MDX.
- La fonction LinkMember prend le membre Employee.Employee.CurrentMember et retourne l’employé actuel du set, ensuite retourne les membres de la hiérarchie Parent/Child Employee.Employees associés.
La dernière étape consiste à rajouter les utilisateurs dans l’onglet Membership.
Pour visualiser le résultat, il suffit de naviguer dans le cube en se connectant avec le rôle précédemment crée. Etant donné que dans notre cas nous utilisons les identifiants windows fictifs de AdventureWorks, on ne sera pas aptes à naviguer dans le cube, pour cela il suffit de commenter la fonction UserName et mettre un identifiant en dur.
--StrToMember ('[Users].[User].[' + UserName () + ']') [Users].[User].[adventure-worksdavid0]
C’est ainsi que l’utilisateur avec l’identifiant adventure-worksdavid0 n’aura accès qu’à ces données et celles de ces membres enfants.
Very nice article with lots of information. Thanks for sharing this one with us.