Derek Dysart

Derek Dysart


Periodic notes from an independent Sitecore Developer/Architect

December 2017
M T W T F S S
« Nov    
 123
45678910
11121314151617
18192021222324
25262728293031

Categories


Get Rendered HTML From Sitecore Item

Derek DysartDerek Dysart

I thought I’d cross post this answer of mine from StackOverflow, as it is useful in a number of contexts. As I mentioned there, the code was cribbed from a similar situation where I needed a URL to feed to a PDF to HTML library, which behind the scenes fired up IE on the server and hit the site as an anonymous user. This needed to be launched from within the the Content Editor, but since the PDF library hit the site anonymously, I needed to silently login the user.

This way we could pass a limited time security token via the query string.

First we need an extension method on the User to create the token and a way to check if the token is valid:

 

public static class UserExtensions
{
public const string TokenKey = “UserToken”;
public const string TokenDateKey = “UserTokenDate”;

public static ID CreateUserToken(this User user)
{
if (user.IsAuthenticated)
{
var token = ID.NewID;
user.Profile.SetCustomProperty(TokenKey, token.ToString());
user.Profile.SetCustomProperty(TokenDateKey, DateTime.Now.ToString());
user.Profile.Save();
return token;
}
else
return ID.Null;
}

public static bool IsTokenValid(this User user, string token, TimeSpan maxAge)
{
var tokenId = ID.Null;
if (ID.TryParse(token, out tokenId))
{
var minDate = DateTime.Now.Add(-maxAge);
var tokenDateString = user.Profile.GetCustomProperty(TokenDateKey);
var tokenDate = DateTime.MinValue;

DateTime.TryParse(tokenDateString, out tokenDate);

if (tokenDate < minDate)
return false;

var storedToken = user.Profile.GetCustomProperty(TokenKey);
var storedTokenId = ID.NewID;
if (ID.TryParse(storedToken, out storedTokenId))
return storedTokenId == tokenId;
}

return false;
}
}

Next we patch in a HttpRequestProcessor to look for the token:

public class SilentUserLogin : HttpRequestProcessor
{
public TimeSpan MaximumAge
{
get;
set;
}

public override void Process(HttpRequestArgs args)
{
var userValue = args.Context.Request.QueryString[“user”];
var tokenValue = args.Context.Request.QueryString[“token”];

if (!string.IsNullOrEmpty(userValue) && !string.IsNullOrEmpty(tokenValue))
{
// find user
var user = User.FromName(userValue, AccountType.User);
if (user != null)
{
// Check token is valid
if ((user as User).IsTokenValid(tokenValue, MaximumAge))
{
// log user in
AuthenticationManager.Login(user as User);
}
else
Log.Audit(“User token has expired for user: ‘{0}'”.FormatWith(user.Name), this);
}
else
Log.Audit(“Failed to locate auto login user ” + userValue, this);
}
}

Patch this in with a config file:


<configuration xmlns:patch=”http://www.sitecore.net/xmlconfig/”>
<sitecore>
<pipelines>
<httpRequestBegin>
<processor type=”Namespace.SilentUserLogin,Assembly” patch:after=”*[@type=’Sitecore.Pipelines.HttpRequest.StartMeasurements, Sitecore.Kernel’]”>
<MaximumAge>00:02:00</MaximumAge>
</processor>
</httpRequestBegin>
</pipelines>
</sitecore>
</configuration>

Finally, when we need to use this (either to pass a URL to the PDF library, or in the case of the question to WebClient or HtmlAgility), we build the URL as follows:


var token = Sitecore.Context.User.CreateUserToken();

var url = new UrlString();
url.HostName = HttpContext.Current.Request.Url.Host;
url.Protocol = HttpContext.Current.Request.IsSecureConnection ? “https” : “http”;
url.Path = “/”;

url[“sc_itemid”] = myItem.ID.ToString();
url[“sc_lang”] = myItem.Language.ToString();

// Add parameters to allow accessing the master DB
url[“user”] = Sitecore.Context.User.Name;
url[“token”] = token.ToString();

// Call the url here

Independent Sitecore developer. I also blog about other stuff from time to time.