本项目中,客户有明显的总公司和分公司的切分。
要求:
1)各分公司间的数据隔离
2)总公司可以看到分公司的数据
CRM中的权限结合组织架构,可以很方便实现这种安全级隔离。我们将组织架构设置成,根节点,为总公司。然后在总公司下分别建各分公司的节点。
总公司用户挂在根节点上,而分公司用户分别挂在分公司的子节点上。
但是也要看到,也会带来一些预想之外的工作。下面一一道来
1.CRM的 角色会自动继承到各节点上,导致在上述的结构中存在一个矛盾的地方。
CRM中有一个系统管理员的角色,是谁都不能动的,这个角色也会自动继承到每个节点上。而分公司必定会设置一个系统管理员来打理分公司内的系统上的设置事务(分公司系统管理员要具备可以设置用户安全角色的权限),这就有一个现成的后门,即分公司系统管理员可以把自己设置成这个系统中固定的系统管理员角色,从而获得了最高经级的权限,就可以看到其他分公司甚至总公司的数据。
把角色设置权限全部收到总部,这也不现实,分公司的日常事务要总公司的系统管理员来做,也是繁琐不已。
CRM的安全架构就是和一个树型组织结构紧密结合,所以只能用些unsupported的定制方法了。
首先,让我们整理出规则就是:
1)要阻止根节点的安全角色不能继承到各子节点。
对策:CRM会根据组织架构自动插入多条角色记录,考虑在表RoleBase上建Trigger,将这些继承的记录都打上删除标记(deletionstatecode=1)
2)而非根节点的安全角色可以继承到其的子节点下
对策:要能检索出当前角色是不是从根节点的安全角色中继承下来的。
接下来就可以开始行动了,自然要先解决如何判断出当前的角色是不是从根节点继承下来的问题。组织架构的遍历检索自然就是一个递归查找的问题。SQL 2005的CTE技术可以派上用处了。
先建立一个函数,判断是否是从根节点上继承下来的。
USE [OCS_MSCRM]
GO
/****** 对象: UserDefinedFunction [dbo].[fn_IsRootHirachyRole] 脚本日期: 04/01/2007 19:24:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ==============================
-- Author: <Author,,wengyan>
-- Create date: <Create Date, ,2007/07/02>
-- Description: <Description, ,identify if the role is inherit from root unit>
-- ==============================
CREATE FUNCTION [dbo].[fn_IsRootHirachyRole]
(
-- Add the parameters for the function here
@roleid uniqueidentifier
)
RETURNS int
AS
BEGIN
-- Declare the return variable here
declare @cnt int;
-- Add the T-SQL statements to compute the return value here
with rolehirachy(roleid,name
as
(
select roleid,name,ParentRoleId,0 as level from rolebase
where roleid=@roleid
union all
select d.roleid,d.name,d.ParentRoleId,level+1
from rolehirachy e inner join
rolebase d on
d.roleid=e.ParentRoleId
)
select @cnt=count(1)
from rolehirachy e
inner join rolebase c
on e.roleid=c.roleid
inner join businessunitbase d
on c.businessunitid=d.businessunit
where e.parentroleid is null and d.parentbusinessunitid is null
-- Return the result of the function
RETURN @cnt
END
然后就是写一个insert时候的trigger,这简直就是小菜一碟了。
-- ==============================
-- Template generated from Template Explorer using:
-- Create Trigger (New Menu).SQL
--
-- Use the Specify Values for Template Parameters
-- command (Ctrl-Shift-M) to fill in the parameter
-- values below.
--
-- See additional Create Trigger templates for more
-- examples of different Trigger statements.
--
-- This block of comments will not be included in
-- the definition of the function.
-- ==============================
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
-- ==============================
-- Author: <Author,,wengyan>
-- Create date: <Create Date,,2007/07/02>
-- Description: <Description,,
-- 当创建角色时,从根节点继承下来的角色设置删除标记=1>
-- ==============================
CREATE TRIGGER tg_set_deletionstatecode_on
ON rolebase
AFTER INSERT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
update role set deletionstatecode=1
where dbo.fn_IsRootHirachyRole(roleid)=1 and ParentRoleId is not null
END
GO
经过测试,一切OK。
这个问题的解决要了解CRM的特点,然后加上一定的数据库功底即可。