Salesforce Sharing Rule相关经验总结

本文深入探讨Salesforce平台上的记录级别安全(RLS)机制,包括SharingSettings、SharingReasons、UserManagedSharing与ApexManagedSharing的区别及应用,以及OWD、Profiles、SharingRules等关键组件如何共同作用于用户权限,确保数据安全与合规。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言】:这是一篇很容易被低估的文章,关于工作中RLS相关的所有问题,将在此处通过详实的案例来作分析,并试图探索事物的本质,以便更准确理解官方指南。
同时附带总结sharing相关的技术要点,供学习参考(倒序排列),若有错误之处或措辞不严谨之处,望指正

14、【Sharing Settings中User Visibility Settings对记录访问的影响】:

  • Portal User Visibility - portal users in the same customer or partner portal account can see each other, regardless of OWD. If Community User Visibility is also selected, users from the same community can see each other as well.
  • Community User Visibility - community users in the same community can see each other, regardless of OWD. If Portal Use Visibility is also selected, portal users can see other portal users from the same account as well.

结论验证(以Partner Connunuty User为实验对象):

背景介绍:现有两个Partner Account,Sales Team1和Sales Team2,如下图。这些Sales被放进同一个Partner Community,在User的Internal和External OWD均为Private且未使用任何诸如User Sharing Rules的前提下,我们以Lead Change Owner为载体,通过调整Portal User Visibility和Community User Visibility来观察Sales1对Partner User的可见性。

a. 两者都禁用,截图如下:

b. 只启用前者,截图如下:

c. 只启用后者,截图如下:同a

d. 两者都启用,截图如下:同b

结合实验结果发现和结论有出入,为确保实验的准确性,又创建了相关Report和Dynamic Dashboard供进一步核实,Dashboard截图如上。

13、【User Managed Sharing VS Apex Managed Sharing】:

  • User Managed Sharing (aka Manual Sharing, used in Sharing Button):
    • Allows the record owner or any user with Full Access to a record to share the record with a user or group of users.
    • Only the record owner and users above the owner in the role hierarchy are granted Full Access to the record.
    • User Managed Sharing is removed when the record owner changes or when the access granted in the sharing does not grant additional access beyond the object's organization-wide sharing default access level.
  • Apex Managed Sharing
    • Provides developers with the ability to support an application's particular sharing requirements programmatically through Apex or the SOAP API.
    • Similar to Managed Sharing, except only users with "Modify All Data" permission can add or change Apex managed sharing on a record.
    • Apex Managed Sharing is maintained across record owner changes.

共同问题:
A. 谁能通过Share Button手动Share记录给他人?
B. 对于Manual Sharing的记录和以Apex Share Reason共享的记录谁能编辑?

Demo设计:
假设Role Hierarchy中Chervin和Jeffery是平级,Shawn(Tech Leader)是二人上级,在Timesheet的OWD为Private情况下,分别通过手动共享和程序共享将Jeffrey的Timesheet共享给Chervin(手动共享权限 -> Read Only; 程序共享权限 -> Read/Write)。

系统截图:
a. Jeffrey视图:

b. Chervin视图:

c. Shawn视图:

d. 系统管理员视图:

实验结论:
a. 不论通过手动共享还是程序共享,也不管共享权限是Read还是Edit,对于Chervin来说Share Button不可见;Shawn作为Jeffrey上级继承了Jeffrey对记录的Full Access权限,所以和Jeffrey(Owner)一样能手动Share记录给他人。
所以,不管是记录Owner,或是通过继承获取Owner同等权限的上级,还是通过Modify All / Modify All Data获取到的Full Access的用户,都能通过手动方式共享记录给他人

b. 通过对比Jeffrey和Shawn的视图,作为Owner和上级等Full Access的人,对于手动共享的Share Row可修改,但无法修改程序共享的Share Row;又通过结合具有Modify All Data权限的系统管理员视图,通过程序共享的Share Row可修改

因此引用中红色高亮标记的结论有据可依!

12、【Sharing Reason Overview】:

SHARING TYPEREASON FIELD VALUEROW CAUSE VALUE
Managed SharingAccount SharingImplicitChild
Managed SharingAssociated record owner or sharingImplicitParent
Managed SharingOwnerOwner
Managed SharingOpportunity TeamTeam
Managed SharingSharing RuleRule
Managed SharingTerritory Assignment RuleTerritoryRule
User Managed SharingManual SharingManual
User Managed SharingTerritory ManualTerritoryManual
Territory2AssociationManual (API version >= 45)
Apex Managed SharingDefined by developerDefined by developer

拓展与延伸 (自定义对象的Apex Share Reason的一些考虑)

  • Can only be created in Salesforce Classic UI or through Metadata API.
  • Can only be created up to 10 Apex sharing reason per custom object.
  • Delete an Apex sharing reason will delete all sharing on the object that uses the reason.
  • Under certain circumstances, inserting a share row results in an update of an existing share row, for ex:
    • a manual share access level is set to Read and you insert a new one set to Write
    • a sharing rule row cause (which is a higher access level) replaces the parent implicit share row cause
  • Also, in some circumstances, sharing will be removed during recalculation if the access they grant is considered redundant, for ex:
    • a manual sharing which grants Read Only access to a user, is deleted when object's sharing model changes from Private to Public Read Only

11、【Change Acc Owner保留User Managed Sharing created by Apex】:Protecting Force.com Custom Sharing Code
痛点说明:自定义对象我们可以使用Sharing Reason实现change owner不移除RowCause为Manual的share表,但对标准对象来说,我们依然需要一些策略来区分程序share的表和通过UI 手动share的表。

最佳实践:可以使用Shadow Table来决策是否在标准对象change owner时需要重新创建被移除的share table。以AccountShare为例其字段如下:

  • Account: Lookup to Account
  • Team Member: Lookup to User
  • Account Access: Picklist (Read, Edit)
  • Opportunity Access: Picklist (None, Read, Edit)
  • Case Access: Picklist (None, Read, Edit)
  • Contact Access: Picklist (None, Read, Edit)
  • Team Role: Picklist (Account Manager, Channel Manager, Executive Sponsor, Lead Qualifier, Pre-Sales Consultant, Sales Manager, Sales Rep)

代码示例

trigger AccountTriggers on Account (after update) {
    if(trigger.isAfter && trigger.isUpdate) {

        //First Determine which accounts had an ownership change
        String[] accountsToProcess = new String[]{};
        for (Account a:Trigger.new) {
          if(a.ownerId <> Trigger.oldMap.get(a.id).ownerId)
          accountsToProcess.add(a.id);
        }

        //If any accounts had an ownership change proceed
        if(accountsToProcess.size() > 0) {

           //Retrieve the list of all cloned shares
            List<Programmatic_Share__c> psList = [select account__c,
                                                   teamMember__c,
                                                   accountAccess__c,
                                                   opportunityAccess__c,
                                                   caseAccess__c,
                                                   contactAccess__c
                                                   from Programmatic_Share__c
                                                   where objectId__c in :accountsToProcess];
            //If programmatic shares were found continue
            if(psList.size() > 0) {
                List<AccountShare> asList = new List<AccountShare>();

                //Create AccountShare records for each cloned share
                for (Programmatic_Share__c ps: psList)
                    asList.add(new AccountShare(accountId = ps.account__c,
                                            userOrGroupId = ps.teamMember__c,
                                            accountAccessLevel = ps.accountAccess__c,
                                            caseAccessLevel = ps.caseAccess__c,
                                            contactAccessLevel = ps.contactAccess__c,
                                            opportunityAccessLevel = ps.opportunityAccess__c));

                //Insert the AccountShare records
                Database.insert(asList);
            }
        }
    }
}

10、【Change Acc Owner保留原有Account Teams记录】:Lock account teams (require keep account team on assigment)

解决方案

On Before Update - 
++++++++++++
List<AccountTeamMember> listATM = [SELECT Id, AccountAccessLevel, AccountId, CaseAccessLevel, UserId, ContactAccessLevel, OpportunityAccessLevel, TeamMemberRole, PhotoUrl, Title 
                                   FROM AccountTeamMember 
                                   WHERE AccountId IN :Trigger.new]; 
system.debug('AccountTeamMember records: '+(JSON.serialize(listATM))); 
String str = JSON.serialize(listATM); 
// delete team member records if required
retainOldTeamMemberOnOwnerChange(str); 
++++++++++++

@future
public static void retainOldTeamMemberOnOwnerChange(String str){
    system.debug('Future call '+str); 
    List<AccountTeamMember> newlistATM = (List<AccountTeamMember>) JSON.deserialize(str,List<AccountTeamMember>.class);
    for(AccountTeamMember objAccTeamMember : newlistATM){
        objAccTeamMember.Id= null;
    }
    system.debug('Account records to insert'+(JSON.serialize(newlistATM)));
    Upsert newlistATM;
}

9、【探索Apex重复插入不同类型的Share记录在SF中的行为】:Protecting Force.com Custom Sharing Code
以OpportunityShare表为例:
a. User Managed Sharing using Apex
a1. 对Opp记录Owner插入Share表

OpportunityShare oppShr = new OpportunityShare();
oppShr.OpportunityAccessLevel = 'Read';
oppShr.OpportunityId = '0062w000006MCEx';
oppShr.UserOrGroupId = '0052w000005DypyAAC'; // record owner - Sales2 SH
oppShr.RowCause = 'Manual';

insert oppShr;

结果:无法插入Share记录,系统报错System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []

2021-01-04思考:在实际开发或维护设计很复杂的其他开发者编写的代码时,由于系统逻辑与数据处理过于复杂,当上述问题出现时,很难基于业务甄别该错误对应的是哪种业务场景(INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY可能是该用户缺乏OLS baseline的权限问题,也有可能是上述提到的重复创建了share记录),最简单的做法是使用Database.insert(new List<OpportunityShare> {oppShr}, false);处理share记录的插入,这样至少能确保最小单元的错误,而不是因为这一错误,影响后续代码的进一步处理造成的大面积数据问题。

a2. 对拥有View All Data & Modify All Data的系统管理员 (非Owner)插入Share表

OpportunityShare oppShr = new OpportunityShare();
oppShr.OpportunityAccessLevel = 'Read';
oppShr.OpportunityId = '0062w000006MCEx';
oppShr.UserOrGroupId = '0052w000005DptAAAS'; // System Admin not owner

insert oppShr;


结果:一条Manual的Share记录插入成功,当Admin编辑该记录时不会报错

a3. 对不同Sales Team的另一个Sales同时插入多条Share记录

List<OpportunityShare> oppShrs = new List<OpportunityShare>();
OpportunityShare oppShr1 = new OpportunityShare();
oppShr1.OpportunityAccessLevel = 'Edit';
oppShr1.OpportunityId = '0062w000006MCEx';
oppShr1.UserOrGroupId = '0052w000005DypxAAC'; // Sales1 BJ
oppShr1.RowCause = 'Manual';
oppShrs.add(oppShr1);

OpportunityShare oppShr2 = new OpportunityShare();
oppShr2.OpportunityAccessLevel = 'Read';
oppShr2.OpportunityId = '0062w000006MCEx';
oppShr2.UserOrGroupId = '0052w000005DypxAAC'; // Sales1 BJ
oppShr2.RowCause = 'Manual';
oppShrs.add(oppShr2);
insert oppShrs;

结果:只有一条记录被插入,且后插入的覆盖先插入的,Sales1 BJ对该记录只读。

b. OpportunityTeamMember
b1. 紧随a3为同个Opp的同个Sales创建Opp Team

OpportunityTeamMember member = new OpportunityTeamMember();
member.OpportunityId = '0062w000006MCEx';
member.UserId = '0052w000005DypxAAC';
member.TeamMemberRole = 'Sales Rep'; // Sales1 BJ
member.OpportunityAccessLevel = 'Edit';
insert member;

结果:Opp Team记录创建成功,同时Share表同一个人对同一Opp记录多了Edit权限,使Sales1 BJ最终有编辑权限。

b2. 对b1权限从Edit修改为Read后,重复创建Opp Team,随后将OpportunityAccessLevel去掉后再Insert Opp Team Member

结果:无论insert几条Opp Team Member,最终Opp Team只有一条记录,且OpportunityAccessLevel访问权限会被后插入的覆盖;当去掉OpportunityAccessLevel后重新插入记录,OpportunityAccessLevel权限不会变化。

调研结论
a. 使用Apex创建User Managed Sharing或创建Opp Team Member,最终以Share Table的形式体现授权关系。
b. 对于同一"人或组",同一条记录2重维度下,Share表可以存在RowCase不同的多条Share记录,但最终"人或组"对该记录的权限由最大的权限决定。同时我们可以说UserOrGroupId + ParentId + RowCase 3重维度可以作为确定能否Insert的唯一性。

官方解读

Under certain circumstances, inserting a share row results in an update of an existing share row. Consider these examples:
a. A manual share access level is set to Read and you insert a new one set to Write. The original share rows are updated to Write, indicating the higher level of access.
b. Users can access an account because they can access its child records (contact, case, opportunity, and so on). If an account sharing rule is created, the sharing rule row cause (which is a higher access level) replaces the parent implicit share row cause, indicating the higher level of access.

项目经验
假如Financial Account(FA)可以关联Account1,2,3,4,且FA上有Primary和Secondary Consultant字段,Account和FA OWD为Private。
现有FA1 (Owner为Integration User,从外部系统同步过来,且Primary, Secondary Consultant分别为Sales1,2)记录上有Acc1 (Owner为Sales1),Acc2 (Owner为Sales2),Acc3 (Owner为Sales1),如果Acc1 Owner变更为Sales3后,我们想移除Sales1作为失去对Acc1的权限从而失去FA1的权限,可以直接删除FA Share表里面的记录吗?

答:不能,我们仍需要评估FA1上的其他Acc的Owner,来最终确定是否能删除Sales1对FA1的Share记录

8、【探索change owner对apex managed sharing影响】:
实验一:验证标准对象影响
对象:client(private), admin(owner) -> change owner to sales1
sales2(apex managed sharing - manual) - done
sales3(shared by user managed sharing) - done
sales4(shared by teams) - done

假设1:change owner后, sales2, sales3被移除, sales4保留
结论change owner后sharing rule重新计算,移除不符合sharing rule的share记录,保留任然满足条件的share记录;manual sharing和teams share的记录都被清除。

实验二:验证自定义对象影响
对象:fund(private), admin owner -> change owner to sales1
A. apex managed sharing - manual (shared with sales2) - done
B. apex managed sharing - developer defined sharing reason (shared with sales3) - done

假设2:change owner后,sales2的sharing记录被移除,sales3的sharing记录保留
结论:成立。

实验三:验证重复apex managed sharing - manual
结论在代码中同一批次可以为相同的人对同一个记录创建重复的share记录,数据库层面不会报错;但是最终DB对重复的share记录只会保留一个。

代码片段:

// Account Share
AccountShare ashr = new AccountShare();
ashr.AccountId = '0010l000018TmE5';
// ashr.RowCause = 'Manual'; // defualt is manual
ashr.UserOrGroupId = '0050l000002hH6C';
ashr.AccountAccessLevel = 'Read';
ashr.OpportunityAccessLevel = 'None';
ashr.CaseAccessLevel = 'None';

insert ashr;

// Fund Share - custom sharing reason
Fund__Share jobShr = new Fund__Share();
jobShr.ParentId = 'a0D0l00000BFdqn';
jobShr.UserOrGroupId = '0050l000003QDT2';
jobShr.AccessLevel = 'Read';
jobShr.RowCause = Schema.Fund__Share.RowCause.Automatic_Sharing__c;

insert jobShr;

// Fund Share - duplicated manual sharing
Fund__Share jobShr1 = new Fund__Share();
jobShr1.ParentId = 'a0D0l00000BFdqn';
jobShr1.UserOrGroupId = '0050l000002hH6C';
jobShr1.AccessLevel = 'Read';
jobShr1.RowCause = Schema.Fund__Share.RowCause.Manual; 

insert jobShr1;

Fund__Share jobShr2 = new Fund__Share();
jobShr2.ParentId = 'a0D0l00000BFdqn';
jobShr2.UserOrGroupId = '0050l000002hH6C';
jobShr2.AccessLevel = 'Read';
jobShr2.RowCause = Schema.Fund__Share.RowCause.Manual; 

insert jobShr2;

过程记录:

7、【Salesforce共享记录的21种方式】:

Use Cases:
a. Sharing Sets[13]: Sharing Records with High-Volume Portals and Communities
Sharing Sets on Cases - 在Case的External OWD Private下,如果想让同一个Partner Account里面的Users互相看到各自的Case可以使用Sharing Set,这里Case和Account直接有Direct Lookup关系
当然Indirect Lookup之间也可以使用Sharing Set,如外包的Service Contractors专门服务你的客户的Solar Panel安装工作,那么假如某Account Homeowners购买了Asset Solar Panel,这时Asset与Account间有Direct Lookup关系,然后这个Asset Solar Panel被分配给Partner Account Service Contractors来负责安装工作,这时Asset与Partner Account间又有一个Direct Lookup关系,从而构成Partner Account与Account间的Indirect Lookup关系,因此也适用Sharing Set。

b. Sharing Group[14]
Sharing Groups授予内部用户访问记录通过Sharing Sets,用户在Sharing Group获取通过Sharing Sets被共享记录的Full Access.
假如某个Support Agents需要访问到某个Partner Account的所有Case,因此可以使用Sharing Group。

c. Account Relationship[21]: Share Data Using an Account Relationship
Let’s say that you have a distributor who needs access to a subset of the customer accounts owned by his reseller so that he can effectively support them. Or you have a distributor who needs to collaborate with a reseller on specific deals.

Example: To share all leads owned by external users of Northern Trail Outfitters with Cloud Kicks.

Example Screenshots:

6、【Profile如何通过设定OLS来影响RLS】:
类型:CRED + View All(查看org指定对象的所有记录,忽略sharing) + Modify All(RED org指定对象的所有记录)
a. CRED on owned records.
b. CRED on others owned records access but respect sharing.

解读b:假设用户的Profile为CRED,但是OWD为Private,那么该用户对自己的记录拥有CRED,但是对其他人记录的CRED需要遵循sharing,而OWD Private说明对他人记录访问受限,所有无法RED他人的记录。

5、【设定OWD访问级别的铁律】:


第一步:找到需要最少访问的用户;
第二步:分配匹配该用户访问权限的访问权限。
示例:A用户不能看其他人的记录;B用户需要读写其他用户的Lead记录。
结果:遵循A用户的访问权限,设置OWD为Private。

4、【实例矩阵解读OWD 与 Profiles相互作用下用户的RLS】:

对Del的考虑如果OWD为Public Read Write,Profile为CRED,则该用户无法删除其他人的记录;一般而言,如果需要删除其他人的记录,declarative方法可以通过Profile或Permission Set在相应对象勾选Modiffy All,或勾上Modify All Data(对所有对象)。

OWDProfileResult(仅关注RE,未考虑CD)
PrivateCREDMy records: Read / Edit
PrivateCRMy records: Read
Private-No access
Public Read OnlyCREDMy records: Read / Edit
Other records: Read
Public Read OnlyCRMy records: Read
Other records: Read
Public Read Only-No access
Public Read WriteCREDMy records: Read / Edit
Other records: Read / Edit - 不能删除别人拥有的记录
Public Read WriteRMy records: Read
Other records: Read - Profile OLS没给写的权限,无法更新别人的记录。(inline-edit会失效)
Public Read Write-No access
Public Read OnlyRMy records: Read
Other records: Read
Public Read OnlyCRED / View AllMy records: Read / Edit
Other records: Read
Public Read WriteCRED / View AllRead / Edit all records
PrivateCRED / View AllMy records: Read / Edit
Other records: Read
Public Read WriteCR / View AllMy records: Read
Other records: Read
Public Read OnlyCR / View AllMy records: Read
Other records: Read
Public Read OnlyModify AllRead / Edit all records
Public Read WriteModify AllRead / Edit all records
PrivateModify AllRead / Edit all records

黄金法则:
a. Profile + Permission Set控制的是作为记录的 Owner,你能对记录咋样。
b. OWD控制的是对别人拥有的记录,你能咋样。
c. 对别人的记录,即便RLS给了高于Profile + Permission Set的访问权限,也无法对别人记录有超过OLS级别的权限。

3、【RLS权限优先级】:
a. Profile > Sharing Rule: Profile A的Lead权限为Read,通过Sharing Rule将无权限的Lead1 以Read/Write形式Share给该Profile的User u,此时u对Lead1只读,不可编辑。 

2、【User基于条件的Sharing Rule】:Criteria Based Sharing rules: Allow Lookup/formula/dynamic values and user field
用例:现存系统需要从主Role Hierarchy上开一个新部门,为了避免两个部门间的User可以互相看见,需要将原User的OWD从Public Read Only改为Private,并通过Sharing Rule来还原原部门user share logic,同时满足新部门的需求,即各个部门内的internal user间Read Only。
方案:我们已经新建了两个Group:A Internal Users / B Internal Users,并在新部门B的User上维护Department字段,计划用Department和UserType来实现Internal User在部门内部间Read Only。由于Share条件无法选择到Std UserType,所以需要通过自定义Text字段 + Workflow Field Update来解决。

1、【Campaign Sharing Rue注意事项】:Share Camps | Sharing Considerations | Camp Mgmt Implementation Guide
Q1. Camp OWD Private前提下通过Sharing Rule授予Full Access或R/W权限,被shared人无法编辑(无Edit按钮)该记录?
A1: 被Shared人需要分配Marketing User的Feature License;

未完待续........

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值