Tjo!
Long time no
see. Råkade skaffa 2 barn så har inte haft tid att skriva nåt på ett tag.
Eftersom jag inte
hittade något användbart själv när jag googlade på behörighetsfipplande i
EPiServer 8 så tänkte jag att jag drar mitt strå till stacken och lägger upp
ett inlägg själv:
Scenariot är att när en egenskap som pekar ut en användare ändras på en EPiServer-sida så ska EPiServer-sidans behörigheter automatiskt ändras. Detta görs genom en initialiseringsmodul som hookar upp på Published-eventet. Men detta är en annan historia...
För att uppnå mina behov behövde jag två metoder, en som tar bort behörigheter från en sida och en metod som lägger till behörigheter.
Detta görs numera bäst med hjälp av servicen IContentSecurityRepository
som nås via ”ServiceLocator”-klassen (fick det aldrig att fungera genom att manipulera PageData.ACL...).
private IContentSecurityRepository _contentSecurityRepository
{
get
{
return ServiceLocator.Current.GetInstance<IContentSecurityRepository>();
}
}
Ta bort behörighet
En metod som
kollar om den utpekade sidan har någon entry för den specificerade rollen eller
användaren. Om så tas entryn bort. En borttagning sker lite
klurigt genom att man lägger till en entry med “NoAccess”-behörigheten och
skriver över befintliga regler (mha parametern SecuritySaveType.Replace i
save-metoden).
/// <summary>
/// Remove ACL entry for specified user and accessright for
specified page.
/// </summary>
/// <param name="userOrRoleName"></param>
/// <param name="securityEntityType"></param>
/// <param name="page"></param>
public void RemoveAccessRight(string userOrRoleName, SecurityEntityType securityEntityType, PageData page, bool keepInheritedSecurity)
{
// Check entry exists
if
(page.ACL.Contains(userOrRoleName))
{
IContentSecurityDescriptor securityDescriptor = (IContentSecurityDescriptor)_contentSecurityRepository.Get(page.ContentLink).CreateWritableClone();
// Remove inherited if set (will
throw error otherwise)
if (securityDescriptor.IsInherited)
{
securityDescriptor.IsInherited = false;
// Keep inherited security?
if (keepInheritedSecurity)
AddInheritedACLEntries(ref securityDescriptor,
page.ParentLink);
}
// Remove by adding an entry with
NoAccess and replace existing one (achieved with SecuritySaveType argument to
Save method)
securityDescriptor.AddEntry(new AccessControlEntry(userOrRoleName, AccessLevel.NoAccess,
securityEntityType));
_contentSecurityRepository.Save(page.ContentLink, securityDescriptor, SecuritySaveType.Replace);
}
}
Manuellt lägga till ärvda behörigheter
Dock så finns risken att sidans behörigheter är
inställda på att ärva behörigheter från föräldersidan. Denna flagga ” IsInherited”
på IContentSecurityDescriptor-objektet medför att vi får ett exception kastat
om vi försöker spara nya behörigheter. Så vi måste först för säkerhets skull sätta
“IsInherited” till false. För att då inte tappa alla behörigheter som arvet
medförde så har jag lagt till en parameter ”keepInheritedSecurity” som vid true
manuellt lägger till de ärvda behörigheterna mha metoden ”AddInheritedACLEntries”
nedan.
/// <summary>
/// Adds the inherited ACL entries as
new entries on specified security descriptor object
/// </summary>
/// <param name="securityDescriptor"></param>
/// <param name="parentLink"></param>
private void AddInheritedACLEntries(ref IContentSecurityDescriptor securityDescriptor, ContentReference parentLink)
{
if (!ContentReference.IsNullOrEmpty(parentLink))
{
// Read parent ACL entries and add
to security descriptor
PageData parent = _contentLoader.Get<PageData>(parentLink);
foreach (var aclEntry in parent.ACL.Entries)
{
securityDescriptor.AddEntry(aclEntry);
}
}
}
Lägga till behörighet
Slutligen en metod för att lägga till en behörighet
som är ganska self explanatory. Samma sak här angående flaggan ”IsInherited”.
Tänk också på att AccessLevel enum är en bitmask. Den
kan alltså innehålla flera värden samtidigt, t.ex. kan man skriva såhär för att ge en variabel alla värden utom ”Administer”:
AccessLevel accessLevel = AccessLevel.Read
| AccessLevel.Create | AccessLevel.Edit
| AccessLevel.Delete | AccessLevel.Publish;
Och här är metoden för att lägga till en behörighet:
/// <summary>
/// Add ACL entry for specified user
or role with specified level on specified page.
/// </summary>
/// <param name="userOrRoleName"></param>
/// <param name="accessLevel"></param>
/// <param name="securityEntityType"></param>
/// <param name="page"></param>
/// <param name="keepInheritedSecurity"></param>
public void AddAccessRight(string userOrRoleName, AccessLevel accessLevel, SecurityEntityType securityEntityType, PageData page, bool keepInheritedSecurity)
{
if (page != null &&
!page.ACL.Contains(userOrRoleName, accessLevel, securityEntityType))
{
IContentSecurityDescriptor securityDescriptor = (IContentSecurityDescriptor)_contentSecurityRepository.Get(page.ContentLink).CreateWritableClone();
// Remove inherited if set (will
throw error otherwise)
if (securityDescriptor.IsInherited)
{
securityDescriptor.IsInherited = false;
// Keep inherited security?
if (keepInheritedSecurity)
AddInheritedACLEntries(ref securityDescriptor,
page.ParentLink);
}
securityDescriptor.AddEntry(new AccessControlEntry(userOrRoleName,
accessLevel, securityEntityType));
_contentSecurityRepository.Save(page.ContentLink, securityDescriptor, SecuritySaveType.Replace);
}
}
Och det var det!
Dessa metoder lade jag sedan i en egen klass för behörighetsfippel.