Getting session for Hangfire authorisation

I am using hangfire and want to protect it’s dashboard with SS authentication. I am using asp.net core project.

The example hangfire give is this:

public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
    public bool Authorize(DashboardContext context)
    {
        var httpContext = context.GetHttpContext();

        // Allow all authenticated users to see the Dashboard (potentially dangerous).
        return httpContext.User.Identity.IsAuthenticated;
    }
}

But obviously I need to get the ServiceStack context inside this method instead to access the session data, I tried:

var req = HostContext.TryGetCurrentRequest();

Inside the Authorize method but it returns null.

The DashboardContext has the following data:

Is there anyway to get the ServiceStack session from the asp.net core DefaultHttpContext or another way I can get session inside the authroize method?

I’m assuming Hangfire wouldn’t be executing in the same HTTP Request so you won’t be able to access the HTTP Request Cookies of the original request which references the Authenticated UserSession.

To access the session you’d need to pass the Session Id (from IRequest.GetSessionId()) with your Request DTO (using IHasSessionId interface is recommended). Then you can use the ICacheClient to retrieve the session in the following format:

urn:iauthsession:{sessionId}

Hangfire is added inside Configure() method like this :

app.UseHangfireDashboard("/hangfire", new DashboardOptions
{
    Authorization = new [] { new HangfireAuthorizationFilter() }
});

So I created new DashboardOptions to pass in session id

public class MyDashboardOptions : DashboardOptions
{
    public string ServiceStackSessionId { get; set; }
}

But how can I pass that session id from the Configure() method?

app.UseHangfireDashboard("/hangfire", new MyDashboardOptions
{
	Authorization = new[] { new HangfireAuthorizationFilter() },
	ServiceStackSessionId = ""  //how to populate?
});

I couldn’t tell you anything about how hangfire works as I’ve never used it before. But if you’re trying to execute a queued Request DTO you would need to populate it with the Session Id when the Request is being queued.

But if this is just to get the session for the current request, you can use the ToRequest() extension method to convert an underlying ASP.NET Context to a ServiceStack Context:

var req = context.GetHttpContext().ToRequest();
var session = req.GetSession();
1 Like

After converting it to SS context the UserAuthId is null so I tried this inside Authorize() method:

var coreContext = context.GetHttpContext();
var httpContext = coreContext.ToRequest();
var session = httpContext.GetSession(); //no user auth details
var cacheClient = httpContext.TryResolve<ICacheClient>();
var sessionCache = cacheClient.Get<CustomUserSession>($ "urn:iauthsession:{session.Id}");  //null

I checked in the cache_entry table and the ID created when I authenticate is different to the ID I get when I convert the asp.net core context to SS context. I tried re-authenticating but it’s always a different ID so I can’t tie it to authenticated session.

Any idea why I am getting a different session ID?

edit: discourse converts ($ ") without space into a random string so I added space in code, in my actual code there is no space between $ and "

The SessionId is contained in the ss-id/ss-pid Session Cookies which needs to be returned using:

var sessionId = req.GetSessionId();

If it’s not the Http Request context isn’t configured correctly, you can try accessing the cookies directly. If the ss-opt Cookie contains perm then use the ss-pid Cookie otherwise use the ss-id contains the SessionId. If these Cookies don’t exist it means this isn’t an Authenticated Request and there is no Session to get.

If you’re getting a different Session Id each time it means the Cookies aren’t being preserved and sent with each Request, ServiceStack will automatically generate new ss-id/ss-pid Cookies if they don’t exist on the Request.

I think issue was something to do with my local config with app and api running on different ports. I used postman to copy the cookies and it worked.

This is working solution:

public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
    public bool Authorize(DashboardContext context)
    {
        if (Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development")
        {
            return true;
        }

        var coreContext = context.GetHttpContext();
        var httpContext = coreContext.ToRequest();
        var session = httpContext.GetSession();

        if(session != null & session.IsAuthenticated & session.Roles != null && session.Roles.Contains("Admin"))
        {
            return true;
        }

        return false;
    }
}

Also what confused me is the ss-pid doesn’t match the cache key entry in database. ss-opt is set as temp. the ss-id is set as PJim9sRfwXcigrmTHEtV and it seems to relate to cache key urn:iauthsession:gZpQZdE0qNmN7jlxP1zT. I am not sure why this is.