Populating IAuthSession with data from the databas

2019-05-11 16:26发布

问题:

So I've created a custom CredentialsAuthProvider using ServiceStack as per the examples located here: https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization

I have the authentication side of things working but I'm not sure how I populate the session with data from the database in the OnAuthenticated method. In the example they show the following:

     //Fill the IAuthSession with data which you want to retrieve in the app eg:
    session.FirstName = "some_firstname_from_db"; 

In the TryAuthenticate method I have the username/password, which I can use to authenticate the user against the database, but once it goes to the OnAuthenticated method, how/what do I use to access/retrieve the user information from the database?

回答1:

Another good example of a ServiceStack's CustomUserSession is in the SocialBootstrapApi project. Rather than pulling information out of the data, it extracts the information out of the UserSession and populates its own Custom User Table using the registered DB Factory resolved from the AppHost IOC:

authService.TryResolve<IDbConnectionFactory>().Run(db => db.Save(user));

Rather than using it to extract and save data from the user's session, you can also use any of your registered dependencies to fetch data and populate the session with:

public override void OnAuthenticated(
    IServiceBase authService, 
    IAuthSession session, 
    IOAuthTokens tokens, 
    Dictionary<string, string> authInfo)
{
    using (var db = authService.TryResolve<IDbConnectionFactory>().OpenDbConnection()) 
    {
        var user = db.Id<MyUser>(session.UserId);
        session.FirstName = user.FirstName;
    }
}


回答2:

I know this is an older thread but it may still be relevant because unfortunately not much has improved since Sep of 2012 in terms of availability of ServiceStack documentation, clarity of examples or even comments in the code. (@mythz: It would be very helpful if you guys could add meaningful summaries to all your classes and methods.)

I struggled with the same dilemma until I looked at the actual code of CredentialsAuthProvider (which in general is pretty much the only way to understand how things work in ServiceStack). The OnAuthenticated is called right after TryAuthenticate inside the Authenticate method, so I figured it's not necessary to make all your DB calls in OnAuthenticated as @mythz suggests in his examples. Instead I placed the code that populates the IAuthSession object right into my implementation of TryAuthenticate, like so:

public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
    try
    {
        // Use my own repo to authenticate the user.
        var userRepo = authService.TryResolve<IUserRepository>();
        var user = userRepo.Authenticate(userName, password);

        // Populate session properties with data from my user POCO.
        var session = authService.GetSession();
        session.Id = user.CurrentSession.ID.ToString();
        session.IsAuthenticated = true;
        session.CreatedAt = DateTime.UtcNow;
        session.DisplayName = session.FirstName = session.LastName = user.FullName;
        session.UserAuthName = session.UserName = user.Username;
        session.UserAuthId = user.ID.ToString();
    }
    catch (Exception ex)
    {
        // Log the exception, etc....
        return false;
    }
    return true;
}

However, you still have to override OnAuthenticated in order to save the cookie in HTTP response (which I assume is required for subsequent requests from the same browser to be authenticated) because the base implementation only sets the cookie if it finds IUserAuthRepository in the IOC container, which in my case won't happen because I use my own repository. So my implementation now looks like this:

public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
    try
    {
        // Save the browser cookie.
        var httpRes = authService.RequestContext.Get<IHttpResponse>();
        if (httpRes != null)
        {
            httpRes.Cookies.AddPermanentCookie(HttpHeaders.XUserAuthId, session.UserAuthId);
        }

        // Save the user session object (ServiceStack stores it in the in-memory cache).
        authService.SaveSession(session, SessionExpiry);
    }
    catch (Exception ex)
    {
        // Log the exception, etc....
    }
}

@mythz: Please let me know if the above makes sense or not.