Quick setup: Role-based cache variation for the ASP.NET Core Renderer

Overview

By default, the ASP.NET Core Renderer does not cache pages for signed-in visitors, because different users can see different content. Role-based cache variation lets the Renderer, and your CDN if you use one, cache pages for signed-in visitors by grouping users who have the same set of roles into one cache entry, instead of caching per user. For example, two users who are both members of the Editors role are served the same cached page.

To set it up, you configure both Sitefinity CMS and the Renderer:

  1. In Sitefinity CMS, you enable a signed cookie, sf-roles by default, that describes the visitor's roles.
  2. In the Renderer, you enable validation of that cookie, so that the Renderer uses it as part of its cache key.

You must use the same signing key and cookie name in both. Otherwise, the Renderer cannot use the cookie and signed-in visitors are not cached in their role bucket.

This article is a condensed procedure. For the complete reference, including the CDN configuration, see Configure cache » Role-based cache variation. The same version requirements apply.

IMPORTANT: Role-based cache variation is not suitable when permissions are assigned per individual user or when Deny permission entries are used. For affected pages, disable output caching for signed-in users by calling PageRouteHandler.RegisterNoCacheAuthenticatedUserOutputCacheVariation().

Set up role-based cache variation

Step 1: Generate a shared signing key

The signing key is a hex string of at least 32 hex digits (128 bits). A key of 64 hex digits (256 bits) is recommended.

Generate the key with a cryptographically secure random number generator. For example, in PowerShell:

PowerShell
$bytes = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
($bytes | ForEach-Object { $_.ToString('x2') }) -join ''

IMPORTANT: The key is a shared secret between Sitefinity CMS and the Renderer. Do not commit it to source control in plain text. Store it in a secret store or in environment-specific configuration.

The roles cookie settings are not available in the Sitefinity CMS backend. Add them to the appSettings section of the Sitefinity CMS web.config file:

XML
<appSettings>
  <add key="sf-env:authenticationConfig:enableCdnRolesCookie" value="true" />
  <add key="sf-env:authenticationConfig:cdnRolesCookieEncryptionKey" value="YOUR-HEX-KEY-HERE" />
</appSettings>

The cookie name defaults to sf-roles and the cookie time-to-live (TTL) defaults to 60 minutes. Set cdnRolesCookieName and cdnRolesCookieTtlMinutes only if you want to change these values. For more information, see Configuration reference.

Add the matching settings under the Sitefinity section of the Renderer's appsettings.json file:

JSON
{
  "Sitefinity": {
    "EnableOutputCacheVaryByRolesCookie": true,
    "OutputCacheRolesCookieSigningKey": "YOUR-HEX-KEY-HERE"
  }
}

OutputCacheRolesCookieSigningKey must be identical, character for character, to cdnRolesCookieEncryptionKey in Sitefinity CMS. If you changed cdnRolesCookieName in Step 2, also set OutputCacheVaryByRolesCookieName to the same value.

You can also set these values as environment variables, for example, Sitefinity__OutputCacheRolesCookieSigningKey. For more information, see Application settings.

Step 4: Cache content and navigation responses by role in Sitefinity CMS

The roles cookie controls only the Renderer and CDN cache. Sitefinity CMS must also allow its content and navigation responses to be cached for signed-in users. Otherwise, the Renderer caches those pages only for the shorter OutputCacheMissingKeysDuration period instead of the full OutputCacheDuration.

Add the following to the Sitefinity CMS web.config file:

XML
<appSettings>
  <add key="sf-env:systemConfig/outputCacheSettings:contentResponseCachingBehavior" value="VaryByUserRoles" />
  <add key="sf-env:systemConfig/outputCacheSettings:navigationResponseCachingBehavior" value="VaryByUserRoles" />
</appSettings>

contentResponseCachingBehavior controls content responses. navigationResponseCachingBehavior controls navigation widget responses and accepts the same values. Set both, because navigation widgets appear on most pages.

You can also configure both settings in the Sitefinity CMS backend, in Administration » Settings » Advanced » System » Output Cache Settings.

Step 5: Allow View permissions on roles only

VaryByUserRoles builds the cache key from the user's roles only. If a View permission is set on an individual user rather than on a role, users who have the same roles but different per-user permissions would share a cache entry.

To prevent this, add the following to the Sitefinity CMS web.config file:

XML
<appSettings>
  <add key="sf-env:systemConfig/outputCacheSettings:enforceRoleOnlyViewPermissions" value="true" />
</appSettings>

When this setting is enabled:

  • Administrators cannot set View permissions on individual users. They must set them on roles instead.
  • Pages that display content with existing per-user View permissions are not cached for signed-in users.

The setting takes effect only when contentResponseCachingBehavior is VaryByUserRoles.

Step 6: Restart both applications

Saving web.config restarts the Sitefinity CMS application. Restart the Renderer to apply the changes in appsettings.json or in environment variables.

Step 7: Verify the setup

  1. In the Renderer's appsettings.json, temporarily set EnableOutputCacheStatusHeader to true and restart the Renderer.
    The Renderer adds an sf-cache-status header with value HIT or MISS to each response.
  2. Sign in to the website as a frontend user who has at least one role.
    In the browser developer tools, verify that the sf-roles cookie is present.
  3. In a different browser or a private window, sign in as a second user with the same roles.
    The sf-roles cookie value must be identical for both users, as long as they signed in within the same cdnRolesCookieTtlMinutes window.
  4. As the second user, open a page that the first user already opened.
    The response must contain sf-cache-status: HIT.
  5. Sign in as a user with different roles and open the same page.
    The sf-roles cookie value must be different and the first response must contain sf-cache-status: MISS.
  6. Set EnableOutputCacheStatusHeader back to false.

Configuration reference

SettingWhereRequiredDescription
enableCdnRolesCookieSitefinity CMS web.configYesEnables the signed roles cookie. Default: false.
cdnRolesCookieEncryptionKeySitefinity CMS web.configYesHex signing key, at least 32 hex digits.
cdnRolesCookieNameSitefinity CMS web.configNoName of the roles cookie. Default: sf-roles.
cdnRolesCookieTtlMinutesSitefinity CMS web.configNoLength of the window, in minutes, during which users with the same roles receive the same cookie value. Default: 60.
EnableOutputCacheVaryByRolesCookieRenderer appsettings.jsonYesVaries the Renderer cache by the roles cookie. Default: false.
OutputCacheRolesCookieSigningKeyRenderer appsettings.jsonYesMust equal cdnRolesCookieEncryptionKey.
OutputCacheVaryByRolesCookieNameRenderer appsettings.jsonNoMust equal cdnRolesCookieName. Default: sf-roles.
contentResponseCachingBehaviorSitefinity CMS web.configRecommendedSet to VaryByUserRoles to cache content responses by role. Default: Auto.
navigationResponseCachingBehaviorSitefinity CMS web.configRecommendedSet to VaryByUserRoles to cache navigation widget responses by role. Default: Auto.
enforceRoleOnlyViewPermissionsSitefinity CMS web.configRecommendedSet to true to block per-user View permissions. Default: false.

Troubleshooting

SymptomPossible cause and solution
The sf-roles cookie does not appear after sign-in.
  • enableCdnRolesCookie is not true.
  • cdnRolesCookieEncryptionKey is missing, shorter than 32 hex digits, or not a valid hex string. Check the Sitefinity CMS error log.
  • The user has no roles. The cookie is not issued for users without roles.
  • The user is a backend user. See the next row.
Backend users never receive the sf-roles cookie.This is expected. Sitefinity CMS does not issue the roles cookie to backend users, and the Renderer does not cache their requests.
Two users with the same roles have different sf-roles values.The users signed in during different cdnRolesCookieTtlMinutes windows. The values become identical after the cookies are refreshed in the same window.
Signed-in users see the anonymous version of a page, or are never cached in their role bucket.OutputCacheRolesCookieSigningKey in the Renderer does not match cdnRolesCookieEncryptionKey in Sitefinity CMS, or OutputCacheVaryByRolesCookieName does not match cdnRolesCookieName. When the Renderer cannot validate the cookie, it treats the request as anonymous.
The Renderer does not cache pages for signed-in users at all.EnableOutputCacheVaryByRolesCookie is not true in the Renderer.
The Renderer caches pages for signed-in users only briefly.contentResponseCachingBehavior or navigationResponseCachingBehavior is still Auto or VaryByAuthenticationStatus. Set both to VaryByUserRoles. For more information, see Step 4.
Signed-in users still get no-cache responses on a specific page.A widget on the page calls PageRouteHandler.RegisterNoCacheAuthenticatedUserOutputCacheVariation(). This call disables caching for signed-in users on the entire page.
Administrators cannot set View permissions on an individual user.This is expected when enforceRoleOnlyViewPermissions is true. Set the permission on a role instead.
Want to learn more?
Enhance your Sitefinity skills by enrolling in free training sessions. Become Sitefinity certified through Progress Education Community to strengthen your professional credentials.