实现 SharePoint 网站分类解决方案

注意

有关 SharePoint Online 网站分类,请参阅以下文章:SharePoint“新式”网站分类

即使在管理良好的情况下,SharePoint 网站也可能不受控制的增长。 用户会在需要时创建网站,但很少会删除网站。 搜索爬网因为不使用的网站集而不堪重负,并且导致搜索产生过期且不相关的结果。 通过网站分类,可以确定并保留敏感数据。

本文向你介绍如何使用 Core.SiteClassification 示例实施网站分类解决方案,以及如何使用 SharePoint 网站策略强制执行删除操作。 可以将此解决方案集成到现有的网站设置解决方案来更好地管理你的网站。

准备工作

若要开始,请从 GitHub 上的 Office 365 开发人员模式和做法项目下载 Core.SiteClassification 示例。

注意

本文中的代码按原样提供,不提供任何明示或暗示的担保,包括对特定用途适用性、适销性或不侵权的默示担保。

定义并设置网站策略

首先,你需要定义并设置将在你的所有网站集中可用的网站策略。 Core.SiteClassification 示例适用于 SharePoint Online MT,但也可以在 SharePoint Online 专用版或 SharePoint 本地中使用。 网站策略是在内容类型中心(在 SharePoint Online MT 中的路径为 https://[tenantname]/sites/contentTypeHub)内进行设置。

若要设置网站策略,请依次转到“设置”>“网站集管理”>“网站策略”>“创建”。 此时,将会显示“新建网站策略”页。 有关网站策略选项的详细信息,请参阅 SharePoint Server 中的网站策略概述

在“新建网站策略”页面上,在字段中输入下列信息:

  • 名称:HBI

  • 描述:这是超级秘密。

  • 设置单选按钮“自动删除网站”。

  • 对于“删除事件:”,使用网站创建日期 + 1 年。

  • 选中“删除之前向网站所有者发送电子邮件通知:”复选框,并将其设置为 1 个月。

  • 选中“按以下间隔发送跟进通知:”复选框,并将其设置为 14 天。

  • 选中“拥有者可以延迟即将删除:”复选框,并将其设置为 1 个月。

  • 选中“关闭时,网站集将处于只读状态”复选框。

对于名称 MBILBI ,将这些步骤重复两次以上。 对删除或保留策略使用不同的设置。 完成后,你即可发布新策略。

插入自定义操作

你可以将网站分类的自定义操作插入到“设置”页面和“SharePoint 齿轮”图标。 此操作仅对具有 ManageWeb 权限的用户可用。 有关详细信息,请参阅默认自定义操作位置和 ID

/// <summary>
/// Adds a custom Action to a Site Collection.
/// </summary>
/// <param name="ctx">The Authenticated client context.</param>
/// <param name="hostUrl">The provider-hosted URL for the application</param>

static void AddCustomAction(ClientContext ctx, string hostUrl)
{
    var _web = ctx.Web;
    ctx.Load(_web);
    ctx.ExecuteQuery();

    // You only want the action to show up if you have manage web permissions.
    BasePermissions _manageWebPermission = new BasePermissions();
    _manageWebPermission.Set(PermissionKind.ManageWeb);

    CustomActionEntity _entity = new CustomActionEntity()
    {
        Group = "SiteTasks",
        Location = "Microsoft.SharePoint.SiteSettings",
        Title = "Site Classification",
        Sequence = 1000,
        Url = string.Format(hostUrl, ctx.Url),
        Rights = _manageWebPermission,
    };

    CustomActionEntity _siteActionSC = new CustomActionEntity()
    {
        Group = "SiteActions",
        Location = "Microsoft.SharePoint.StandardMenu",
        Title = "Site Classification",
        Sequence = 1000,
        Url = string.Format(hostUrl, ctx.Url),
        Rights = _manageWebPermission
    };
    _web.AddCustomAction(_entity);
    _web.AddCustomAction(_siteActionSC);
}

自定义网站分类

你可以使用“编辑网站信息”页面选择以下特定分类选项:

  • 访问群体范围:设置为“企业”、“组织”或“团队”。

  • 安全分类:设置为你输入的分类类别之一,例如 LBI

  • 过期日期:覆盖默认的过期日期,基于以前输入的分类。

“访问群体范围”和“网站分类”均可搜索,并且在爬网发生后都将具有与其关联的托管属性。 然后你可以使用这些属性,通过网站集中的自定义隐藏列表来搜索特定类型的网站。 此列表在 SiteManagerImpl 类的 Core.SiteClassification.Common 项目中实现。

private void CreateSiteClassificationList(ClientContext ctx)
{
  var _newList = new ListCreationInformation()
    {
    Title = SiteClassificationList.SiteClassificationListTitle,
    Description = SiteClassificationList.SiteClassificationDesc,
    TemplateType = (int)ListTemplateType.GenericList,
    Url = SiteClassificationList.SiteClassificationUrl,
    QuickLaunchOption = QuickLaunchOptions.Off
    };

  if(!ctx.Web.ContentTypeExistsById(SiteClassificationContentType.SITEINFORMATION_CT_ID))
    {
    // Content type.
    ContentType _contentType = ctx.Web.CreateContentType(SiteClassificationContentType.SITEINFORMATION_CT_NAME,
    SiteClassificationContentType.SITEINFORMATION_CT_DESC,
    SiteClassificationContentType.SITEINFORMATION_CT_ID,
    SiteClassificationContentType.SITEINFORMATION_CT_GROUP);

    FieldLink _titleFieldLink = _contentType.FieldLinks.GetById(new Guid("fa564e0f-0c70-4ab9-b863-0177e6ddd247"));
    titleFieldLink.Required = false;
    contentType.Update(false);

    // Key field.
    ctx.Web.CreateField(SiteClassificationFields.FLD_KEY_ID, 
      SiteClassificationFields.FLD_KEY_INTERNAL_NAME, 
      FieldType.Text, 
      SiteClassificationFields.FLD_KEY_DISPLAY_NAME, 
      SiteClassificationFields.FIELDS_GROUPNAME);

    // Value field.
    ctx.Web.CreateField(SiteClassificationFields.FLD_VALUE_ID, 
      SiteClassificationFields.FLD_VALUE_INTERNAL_NAME, 
      FieldType.Text, 
      SiteClassificationFields.FLD_VALUE_DISPLAY_NAME, 
      SiteClassificationFields.FIELDS_GROUPNAME);

    // Add Key field to content type.
    ctx.Web.AddFieldToContentTypeById(SiteClassificationContentType.SITEINFORMATION_CT_ID, 
      SiteClassificationFields.FLD_KEY_ID.ToString(), 
      true);

    // Add Value field to content type.
    ctx.Web.AddFieldToContentTypeById(SiteClassificationContentType.SITEINFORMATION_CT_ID,
      SiteClassificationFields.FLD_VALUE_ID.ToString(),
      true);
    }

  var _list = ctx.Web.Lists.Add(_newList);

  list.Hidden = true;
  list.ContentTypesEnabled = true;
  list.Update();
  ctx.Web.AddContentTypeToListById(SiteClassificationList.SiteClassificationListTitle,
    SiteClassificationContentType.SITEINFORMATION_CT_ID, true);
  this.CreateCustomPropertiesInList(_list);
  ctx.ExecuteQuery();
  this.RemoveFromQuickLaunch(ctx, SiteClassificationList.SiteClassificationListTitle);

}

默认情况下,当你创建现成可用的列表或使用 CSOM 创建列表时,列表将在“最近”菜单中可用。 但是列表需为隐藏状态。 以下代码会将项目从“最近”菜单中删除。

private void RemoveFromQuickLaunch(ClientContext ctx, string listName)
  {
  Site _site = ctx.Site;
  Web _web = _site.RootWeb;

  ctx.Load(_web, x => x.Navigation, x => x.Navigation.QuickLaunch);
  ctx.ExecuteQuery();

  var _vNode = from NavigationNode _navNode in _web.Navigation.QuickLaunch
      where _navNode.Title == "Recent"
      select _navNode;

  NavigationNode _nNode = _vNode.First<NavigationNode>();
  ctx.Load(_nNode.Children);
  ctx.ExecuteQuery();
  var vcNode = from NavigationNode cn in _nNode.Children
     where cn.Title == listName
     select cn;
  NavigationNode _cNode = vcNode.First<NavigationNode>();
 _cNode.DeleteObject();
  ctx.ExecuteQuery();    
  }

Core.SiteClassification 示例提供了让网站管理员或具有权限的人员可以删除新列表的可能性。 访问此页面时,将再次创建列表,但示例不会重新设置属性。 你可以通过扩展示例,将列表上的权限修改为仅网站集管理员可以访问来避免这一点。 或者,你可以使用 Core.SiteEnumeration PnP 示例在列表上进行检查并相应地通知网站管理员。

列表验证检查也可以在 SiteManagerImpl 类的 Initialize 成员中实现。

internal void Initialize(ClientContext ctx)
{
try {
       	 var _web = ctx.Web;
         var lists = _web.Lists;
         ctx.Load(_web);
         ctx.Load(lists, lc => lc.Where(l => l.Title == SiteClassificationList.SiteClassificationListTitle));
         ctx.ExecuteQuery();
                
          if (lists.Count == 0) {
                this.CreateSiteClassificationList(ctx); 
          }
      }
      catch(Exception _ex)
         {

         }
     }
}

将分类指示器添加到网站页面

你可以在网站页面中添加指示器以显示其分类。 Core.SiteClassification 示例说明如何将显示通知的图片嵌入到“网站标题”旁边。 在 SharePoint 的早期版本中,此操作通过服务器端委派控件执行。 尽管你可以使用 JavaScript 的自定义母版页,但此示例使用嵌入式 JavaScript 模式。 当你在“编辑网站信息”页面中更改“网站策略”时,这会将网站指示器更改为对每个网站分类选项使用不同的背景颜色来显示一个小框。

以下方法在 Core.SiteClassificationWeb 项目、脚本和 classifier.js 中定义。 图片存储在 Microsoft Azure 网站中。 您需要更改硬编码的 URL 以匹配您的环境。

function setClassifier() {
    if (!classified)
    {
        var clientContext = SP.ClientContext.get_current();
        var query = "<View><Query><Where><Eq><FieldRef Name='SC_METADATA_KEY'/><Value Type='Text'>sc_BusinessImpact</Value></Eq></Where></Query><ViewFields><FieldRef Name='ID'/><FieldRef Name='SC_METADATA_KEY'/><FieldRef Name='SC_METADATA_VALUE'/></ViewFields></View>";
        var list = clientContext.get_web().get_lists().getByTitle("Site Information");
        clientContext.load(list);
        var camlQuery = new SP.CamlQuery();
        camlQuery.set_viewXml(query);
        var listItems = list.getItems(camlQuery);
        clientContext.load(listItems);

        clientContext.executeQueryAsync(Function.createDelegate(this, function (sender, args) {
            var listItemInfo;
            var listItemEnumerator = listItems.getEnumerator();

            while (listItemEnumerator.moveNext()) {
                listItemInfo = listItemEnumerator.get_current().get_item('SC_METADATA_VALUE');
                
                var pageTitle = $('#pageTitle')[0].innerHTML;
                if (pageTitle.indexOf("img") > -1) {
                    classified = true;
                }
                else {
                    var siteClassification = listItemInfo;
                    if (siteClassification == "HBI") {
                        var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/hbi.png' title='Site contains personally identifiable information (PII), or unauthorized release of information on this site would cause severe or catastrophic loss to Contoso.' alt='Site contains personally identifiable information (PII), or unauthorized release of information on this site would cause severe or catastrophic loss to Contoso.'></a>");
                        $('#pageTitle').prepend(img);
                        classified = true;
                    }
                    else if (siteClassification == "MBI") {
                        var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/mbi.png' title='Unauthorized release of information on this site would cause severe impact to Contoso.' alt='Unauthorized release of information on this site would cause severe impact to Contoso.'></a>");
                        $('#pageTitle').prepend(img);
                        classified = true;
                    }
                    else if (siteClassification == "LBI") {
                        var img = $("<a href='http://insertyourpolicy' target=_blank><img id=classifer name=classifer src='https://spmanaged.azurewebsites.net/content/img/lbi.png' title='Limited or no impact to Contoso if publically released.' alt='Limited or no impact to Contoso if publically released.'></a>");
                        $('#pageTitle').prepend(img);
                        classified = true;
                    }
                }
            }
        }));
    }

替代方法

你可以使用 OfficeDevPnP Core 中 ObjectPropertyBagEntry.cs 文件中的扩展方法 Web.AddIndexedPropertyBagKey ,来将分类值存储在网站属性包而非列表中。 此方法使属性包可爬网或可搜索。

另请参阅