Access custom user session and request

Hi!
I’ve defined my custom user session in this way:

    public class CustomUserSession : AuthUserSession
    {
            public string MyCustomProp { get; set; }
    
            public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
            {
                base.OnAuthenticated(authService, session, tokens, authInfo);

                var userAuthRepo = authService.TryResolve<IAuthRepository>();
                var userAuth = userAuthRepo.GetUserAuth(session, tokens);

                this.MyCustomProp = "random value";

                authService.SaveSession(session, null);
          }    
    }

In this way I can fill MyCustomProp with a random value when the user is authenticated… how can I return this value in the same Dto that I get back after the authentication?

You can’t change the AuthenticateResponse DTO that’s returned from the AuthenticateService, but there’s a Meta Dictionary property on AuthenticateResponse you can use to populate with custom metadata either by overriding Authenticate() in your Custom AuthProvider, casting to AuthenticateResponse then populating the Meta dictionary from the session, or by adding a Response Filter that populates the Meta dictionary when dto is AuthenticateResponse.

You can get the Users Session from anywhere that has access to IRequest with IRequest.GetSession().

Another option is to return it in a Custom Response Header. You can access the response from authService.Request.Response.

        public override object Authenticate(IServiceBase authService, IAuthSession session, Authenticate request)
        {
            var authResponse = (AuthenticateResponse)base.Authenticate(authService, session, request);

            return new
            {
                UserName = authResponse.UserName,
                SessionId = authResponse.SessionId,
                ReferrerUrl = authResponse.ReferrerUrl,
                RequestToken = "foobar"
            };
        }

mm… it seems that if I override the Authenticate() method, I get my custom AuthenticateResponse just on the first user login… if the user is already logged and I try to resend the credentials, the Authenticate() method seems to be by-passed so I can’t get my custom AuthenticateResponse but the default one, is it true?
Should I implement a Response Filter to get it on each credentials submit or I’m wrong?

I also can’t understand how to fill the Meta dictionary of my session… I haven’t a Meta property in my session.

Right, if you’re already authenticated ServiceStack doesn’t re-authenticate, it returns a populated AuthenticateResponse based on the UserSession. You’ll need to use a Response Filter to be able to modify the re-authenticated Response DTO.

There is no Meta dictionary on Session. The Meta Dictionary is just an extension point added to built-in Response DTO’s so you can add custom metadata to the response. The idea is to add your custom session properties to the Meta dictionary, not the other way around.

Hi Demis, I’ve tried to follow your instructions but I really can’t understand what I have to do… I’m sorry!
I can’t understand how to pass MyCustomProp from my CustomUserSession:

public class CustomUserSession : AuthUserSession
{
        public string MyCustomProp { get; set; }

        public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
        {
            base.OnAuthenticated(authService, session, tokens, authInfo);

            var userAuthRepo = authService.TryResolve<IAuthRepository>();
            var userAuth = userAuthRepo.GetUserAuth(session, tokens);

            this.MyCustomProp = "random value";

            authService.SaveSession(session, null);
      }    
}

to my AuthResponse Filter:

    public static void AuthResponse(IRequest req, IResponse res, object requestDto)
    {
        if (requestDto is AuthenticateResponse)
        {

        }
    }

I can't understand how and where use the Meta dictionary that you talked above… confused
Could you please paste a little code to show me what you mean?
Thank you for the patience!

The Meta Dictionary is on the AuthenticateResponse DTO and you can get the Session form IRequest.GetSession() so your Response Filter would just be something like:

public static void AuthResponse(IRequest req, IResponse res, object response)
{
    var authRes = response as AuthenticateResponse;
    if (authRes == null) return;
    
    var session = (CustomUserSession)req.GetSession();
    authRes.Meta = new Dictionary<string,string> { 
        {"MyCustomProp", session.MyCustomProp}
    };
}

Note: This should be a Response Filter and registered in GlobalResponseFilters.

1 Like

I was far from the solution!
Thank you very much for your help, you solved my problems!

I have one last question about this Response Filter, I’m trying to access the db to get a value and add it to the AuthResponse Meta too…
I’ve tried this way:

var db = req.TryResolve<IDbConnectionFactory>().OpenDbConnection();

and

var db = req.TryResolve<IDbConnectionFactory>().OpenDbConnection().Open();

but I can’t get the base methods (Select / Update) of a normal Db connection, is there a way to do it?

You can use your first example, or you can resolve dependencies anywhere from the HostContext singleton, they both returned an Open IDbConnection, e.g:

using (var db = HostContext.TryResolve<IDbConnectionFactory>().Open())
{
}

If you’re missing OrmLite API’s it’s because you don’t have the ServiceStack.OrmLite namespace which contains all OrmLite’s extension methods. I recommend using a tool like ReSharper which will save you time from future missing namespaces.

1 Like

Hi Demis,
I am trying to return back some additional data on auth response while doing Basic&Credential auth. I am overriding the Authenticate method and populating the Meta dictionary with the data that I want returned. I can see in the debugger that the Meta dictionary gets populated in the Authenticate but the response in Swagger-UI shows it as null.

Please show the code you’re using to populate the data as well as the raw HTTP Request Headers for that Request l.

Please see the requested info:


Raw headers:

{Connection=keep-alive&Content-Length=34&Content-Type=application%2fx-www-form-urlencoded&Accept=application%2fjson&Accept-Encoding=gzip%2c+deflate&Accept-Language=en-US%2cen%3bq%3d0.5&Cookie=ss-id%3dH9iDVCBuo4OKs7oHjjQr%3b+ss-pid%3dIpznxUeAn4n6Lave6pvA&Host=localhost%3a56241&Referer=http%3a%2f%2flocalhost%3a56241%2fswagger-ui%2f&User-Agent=Mozilla%2f5.0+(Windows+NT+10.0%3b+WOW64%3b+rv%3a47.0)+Gecko%2f20100101+Firefox%2f47.0}

Also, I should mention that I am seeing this behavior sporadically, where the Authenticate method would get called twice - the first time around the overriden session values didn’t show up when I try to use it for populating “Meta”. The second time around i see the correct values and they also make it across in my final response DTO. I tried to close the debug session and start all over again so that the behavior is not related to a saved session but that did not help…

By Raw HTTP Headers I mean a copy of the raw HTTP Request/Response, i.e. so we can see exactly what’s over the wire which you can get using either Chrome Web Inspector or Fiddler.

If it’s happening sporadically it sounds like what you think is getting called isn’t getting called. i.e. when the results aren’t being returned your Authenticate method modifying the dictionary isn’t getting called. I’d start by looking finding what the exact steps are that reproduces the issue, then once you have it debug it to find out what’s going on.

I’ve got it to a repeatable behavior (removed basic auth and just using credential auth). The first time I authenticate it does not return me data in the Meta dictionary - the values that I set in my custom session object (in the OnAuthenticated method) are not there when the control returns back to Authenticated method in the overridden CredentialsAuthProvider class. If I login again without logging out everything works as expected and I get data in the Meta dict. If I logout, it does the same thing described above, i.e., nothing returned in meta.
1st trip request:
POST http://localhost:56241/auth HTTP/1.1
Host: localhost:56241
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:56241/swagger-ui/
Content-Length: 34
Cookie: ss-opt=temp
Connection: keep-alive

UserName=rucheeg&Password=password
1st trip response
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Vary: Accept
Server: Microsoft-IIS/10.0
X-Powered-By: ServiceStack/4.512 NET45 Win32NT/.NET
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=WQr4mvP1L8NcWJAinQcm; path=/; HttpOnly
Set-Cookie: ss-pid=2yEU4l0Dt2dYwknKIRRY; expires=Wed, 15-Jul-2037 03:50:41 GMT; path=/; HttpOnly
Set-Cookie: ss-opt=temp; expires=Wed, 15-Jul-2037 03:50:41 GMT; path=/; HttpOnly
Set-Cookie: X-UAId=1004; expires=Wed, 15-Jul-2037 03:50:44 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNccmd1cHRhXFNvdXJjZVxSZXBvc1xtYXN0ZXJfaW52ZW50b3J5XHNyY1xBTVMgU2VydmljZXNcRGV2aWNlU2VydmljZVxEZXZpY2UuQVBJLkhvc3RcYXV0aA==?=
X-Powered-By: ASP.NET
Date: Sat, 15 Jul 2017 03:50:48 GMT
Content-Length: 274

{“UserId”:“1004”,“SessionId”:“WQr4mvP1L8NcWJAinQcm”,“UserName”:“rucheeg”,“DisplayName”:“rucheeg”,“ReferrerUrl”:null,“BearerToken”:null,“RefreshToken”:null,“ResponseStatus”:{“ErrorCode”:null,“Message”:null,“StackTrace”:null,“Errors”:null,“Meta”:null},“Meta”:{“ClientId”:“0”}}

2nd trip request:
POST http://localhost:56241/auth HTTP/1.1
Host: localhost:56241
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:47.0) Gecko/20100101 Firefox/47.0
Accept: application/json
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Referer: http://localhost:56241/swagger-ui/
Content-Length: 34
Cookie: ss-opt=temp; ss-id=WQr4mvP1L8NcWJAinQcm; ss-pid=2yEU4l0Dt2dYwknKIRRY; X-UAId=1004
Connection: keep-alive

UserName=rucheeg&Password=password
2nd trip response:
HTTP/1.1 200 OK
Cache-Control: private
Content-Type: application/json; charset=utf-8
Vary: Accept
Server: Microsoft-IIS/10.0
X-Powered-By: ServiceStack/4.512 NET45 Win32NT/.NET
X-AspNet-Version: 4.0.30319
Set-Cookie: ss-id=utKiPdHtdzjIdnoqNbt0; path=/; HttpOnly
Set-Cookie: ss-pid=5EEBzrq4dAuaggjxVwBb; expires=Wed, 15-Jul-2037 03:53:07 GMT; path=/; HttpOnly
Set-Cookie: ss-opt=temp; expires=Wed, 15-Jul-2037 03:53:07 GMT; path=/; HttpOnly
Set-Cookie: X-UAId=1004; expires=Wed, 15-Jul-2037 03:53:12 GMT; path=/; HttpOnly
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNccmd1cHRhXFNvdXJjZVxSZXBvc1xtYXN0ZXJfaW52ZW50b3J5XHNyY1xBTVMgU2VydmljZXNcRGV2aWNlU2VydmljZVxEZXZpY2UuQVBJLkhvc3RcYXV0aA==?=
X-Powered-By: ASP.NET
Date: Sat, 15 Jul 2017 03:53:17 GMT
Content-Length: 287

{“UserId”:“1004”,“SessionId”:“utKiPdHtdzjIdnoqNbt0”,“UserName”:“rucheeg”,“DisplayName”:“rucheeg”,“ReferrerUrl”:null,“BearerToken”:null,“RefreshToken”:null,“ResponseStatus”:{“ErrorCode”:null,“Message”:null,“StackTrace”:null,“Errors”:null,“Meta”:null},“Meta”:{“ClientId”:“1”,“Roles”:"[]"}}

Did you confirm when you debugged the request that your Custom AuthProvider which populated the Response DTO was called? You can also debug Service Responses with a Response Filter, e.g:

this.GlobalResponseFilters.Add((req, res, responseDto) => 
{
    if (responseDto as AuthenticateResponse authResponse)
    {
        //inspect authResponse
    }
});

That’s correct - my CustomAuthProvider was getting called. I think I will use the ResponseFilter for now - I am able populate the Meta dic there with custom key-values. Thanks!