在 Sitecore 中有什么方法可以让我创建一个只能查看和编辑他们自己创建的项目的角色/用户吗?如果没有,我怎样才能做到这一点?
3 回答
为了解决这个问题,我在 sitecore/events 配置下添加了一个 item:created 事件。
<event name="item:created" xdt:Transform="Replace" xdt:Locator="Match(name)">
<handler type="Sirano.Dev.ItemEventHandlers.CustomItemEventHandler, Sirano.Dev" method="OnItemCreated" />
</event>
此事件将运行以下代码:
protected void OnItemCreated(object sender, EventArgs args)
{
if (args == null)
{
return;
}
var parameters = Event.ExtractParameters(args);
var item = ((ItemCreatedEventArgs)parameters[0]).Item;
if (item == null)
{
return;
}
var user = Sitecore.Context.User;
var accessRules = item.Security.GetAccessRules();
accessRules.Helper.AddAccessPermission(user,
AccessRight.ItemRead,
PropagationType.Any,
AccessPermission.Allow);
accessRules.Helper.AddAccessPermission(user,
AccessRight.ItemWrite,
PropagationType.Any,
AccessPermission.Allow);
item.Editing.BeginEdit();
item.Security.SetAccessRules(accessRules);
item.Editing.EndEdit();
}
简单来说,可以使用 Sitecore 的锁定和编辑功能。用户可以通过工作流组中的 Review > Edit 锁定。编辑完成后保存并单击签入。如果登录用户希望查看他锁定的项目,则用户可以右键单击内容树的左侧并选择我的锁定项目以查看我锁定的项目排水沟。甚至您也可以从“查看”>“我的项目”中查看所有锁定的项目。请注意,这不会对访问权限进行任何更改。但不允许除管理员以外的其他用户解锁项目。
我刚刚完成了这个功能。虽然没有开箱即用的方法,但有许多可能的方法可以解决这个问题,包括:
- 项目:保存事件处理程序(注意“保存”而不是“保存”,这是事后发生的),或
- 为 saveUI 管道创建一个处理器,它在 UI 中执行“保存”按钮时执行,或者我们走的方式
- 为 getContentEditorWarnings 管道创建一个处理器
最后一种方法允许您禁用 Sitecore UI 并向用户显示一条消息,但不会阻止代码或 API 更改项目,这对我们来说是理想的。我们的处理器接受路径列表(在配置中)作为子元素,允许我们将功能限制在站点的某些区域(我们控制对营销控制面板的访问)。
<getContentEditorWarnings>
这是我们注入我们的部分的管道的摘录。
....
<processor type="Sitecore.Pipelines.GetContentEditorWarnings.CanWrite, Sitecore.Kernel"/>
<processor type="PingWorks.Pipelines.GetContentEditorWarnings.EditorIsFromAuthorGroup, PingWorks.Pipelines.GetContentEditorWarnings" patch:source="PingWorks.Pipelines.GetContentEditorWarnings.config">
<ignoredRoles hint="list:AddIgnoredRole">
<role>sitecore\_UserBase</role>
</ignoredRoles>
<paths hint="list:AddPath">
<path>/sitecore/system/Marketing Control Panel/Taxonomies/</path>
<path>/sitecore/system/Marketing Control Panel/Campaigns/</path>
<path>/sitecore/system/Marketing Control Panel/Engagement Plans/</path>
<path>/sitecore/system/Marketing Control Panel/Experience Analytics/</path>
<path>/sitecore/system/Marketing Control Panel/FXM/</path>
<path>/sitecore/system/Marketing Control Panel/Outcomes/</path>
<path>/sitecore/system/Marketing Control Panel/Path Analyzer/</path>
<path>/sitecore/system/Marketing Control Panel/Personalization/</path>
<path>/sitecore/system/Marketing Control Panel/Test Lab/</path>
<path>/sitecore/system/Marketing Control Panel/Experience Explorer/</path>
<path>/sitecore/system/Marketing Control Panel/Analytics Filters/</path>
</paths>
</processor>
<processor type="Sitecore.Pipelines.GetContentEditorWarnings.CanWriteWorkflow, Sitecore.Kernel"/>
...
请注意如何使用 Sitecore 配置工厂来填充管道执行器将使用子元素创建的实例的属性,以及在这种情况下我们如何通过和方法将字符串添加到List<string>
属性中。::AddIgnoredRole()
::AddPath()
在我们的特定情况下,我们希望只允许编辑与原作者属于同一角色组的成员进行编辑,尽管您的逻辑将比我们的逻辑更直接。在我们的案例中,我们还为管理员用户添加了一个覆盖,并添加了一个自定义缓存来存储角色搜索结果以加快处理速度,因为在我们的案例中角色成员身份不会经常更改。
我会省去你处理的大部分工作,但关键在于::Process()
方法(我必须反映这段代码,因为我目前无法访问源代码):
public void Process(GetContentEditorWarningsArgs args)
{
string displayName;
this._item = args.Item;
if (!this._isValidForProcessing())
return;
User user = null;
List<string> creatorRoles = this._getRolesForUser(this._item.Statistics.CreatedBy, out user);
List<string> editorRoles = this._getRolesForUser(Context.User);
// compare creator's roles with current editor to find a match
if ( creatorRoles.Any() && editorRoles.Any() && editorRoles.Any( r => creatorRoles.Contains(r) ) )
return;
// if we haven't already aborted, add a warning to display and block editing
GetContentEditorWarningsArgs.ContentEditorWarning cew = args.Add();
cew.IsExclusive = true;
cew.Key = "EditorIsFromAuthorGroup";
cew.Title = "Editing restricted";
cew.Text = $"Editing for this item is restricted. Editors must share a role with the original author, in this case <{user?.DisplayName ?? "Unknown Author"}>.";
}
private bool _isValidForProcessing()
{
if (this._item == null)
return false;
if (Context.IsAdministrator)
return false;
if (!this._paths.Any<string>((string p) => this._item.Paths.FullPath.ToLower().StartsWith(p)))
return false;
return true;
}
这可能足以让您在需要的地方有一个良好的开端。