I am trying to subclass the ApiKeyAuthProvider to do more sophisticated auth provision and usage tracking.
My issue is around different APIs called requiring the new functionality, as opposed to previous functionality (current denoted by attached Attribute)
To do what I am doing, I need the Session NOT to be cached when the new functionality, but remain cached as part of existing functionality.
The issue I have is that the SessionCacheDuration value is based on the SS instance, and not specific to each authorisation request. Thus, although setting it to NULL stops the caching, it stops it permanently for all calls.
Unfortunately there is no ability to override the session caching functionality in a descendant class.
The overridden OnAuthenticated doesn’t seem to be called, so I can’t use it to remove the cached session.
In reviewing the underlying code, I found my best approach was to replace the entire ApiKeyAuthProvider and then add two virtual functions CacheSession() and CachedSession() used within PreAuthenticateWithApiKey.
I could then in my descendant version, override either or both of these to manage caching on a case by case basis.
This works fine, except we’re still using v5.7 of ServiceStack, and when we migrate to newer versions, I’ll have to re-do this work on a newer version of the provider.
Below is what I did, and poerhaps similar could be implemented in the said provider.
Any other suggestions greatly appreciated.
public void PreAuthenticateWithApiKey(IRequest req, IResponse res, ApiKey apiKey)
{
if (RequireSecureConnection && !req.IsSecureConnection)
throw HttpError.Forbidden(ErrorMessages.ApiKeyRequiresSecureConnection.Localize(req));
ValidateApiKey(req, apiKey);
var apiSessionKey = GetSessionKey(apiKey.Id);
if (CachedSession(req, apiSessionKey))
{
req.Items[Keywords.ApiKey] = apiKey;
return;
}
//Need to run SessionFeature filter since its not executed before this attribute (Priority -100)
SessionFeature.AddSessionIdToRequestFilter(req, res, null); //Required to get req.GetSessionId()
using (var authService = HostContext.ResolveService<AuthenticateService>(req))
{
var response = authService.Post(new Authenticate
{
provider = Name,
UserName = "ApiKey",
Password = apiKey.Id,
});
}
CacheSession(req, apiSessionKey);
}
public virtual bool CachedSession(IRequest req, string cacheKey)
{
if (SessionCacheDuration != null)
{
var session = req.GetCacheClient().Get<IAuthSession>(cacheKey);
if (session != null)
session = HostContext.AppHost.OnSessionFilter(req, session, session.Id);
if (session != null)
{
req.Items[Keywords.Session] = session;
return true;
}
}
return false;
}
public virtual void CacheSession(IRequest req, string cacheKey)
{
if (SessionCacheDuration != null)
{
var session = req.GetSession();
req.GetCacheClient().Set(cacheKey, session, SessionCacheDuration);
}
}