Thanks for the approval, love the stack! I’ve done a lot of reading up on Authentication with ServiceStack:
All of the documentation I’ve read a few times, and am wondering if there is a better way than my band-aid implementation for authentication? It feels a little rough around the edges. I’ve got production data (around 70 tables, roughly 3k users), all of which reference AspNetUsers (legacy ASP.NET Identity / Auth system) - 40 FK’s.
What I’ve done is extend (read: migrate) the AspNetUsers table to include all properties needed by the UserAuth object, and my T4 Generated POCO (AspNetUser) now extends UserAuth:
[Alias("AspNetUsers")]
public class AspNetUser : UserAuth
{ ... }
This feels a little off here, because now my ServiceModel project references ServiceStack.Auth, but moving on…
I wrote a custom AuthProvider, inheriting from CredentialsAuthProvider, that uses an ASP.NET Core DI Injected IPasswordHasher that I register in the IoC (that way I can re-use the legacy “PasswordHash” check), if the check fails I pass back to the base.TryAuthenticate method:
public class CustomAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
var dbFactory = authService.ResolveService<IDbConnectionFactory>();
var passwordHasher = authService.ResolveService<IPasswordHasher<AspNetUser>>();
using (var db = dbFactory.Open())
{
var user = db.Single<AspNetUser>(x => x.Email == userName || x.UserName == userName);
if (user == null)
return false;
var result = passwordHasher.VerifyHashedPassword(user, user.PasswordHash, password);
switch (result)
{
case PasswordVerificationResult.Success: //Same Version Identity
case PasswordVerificationResult.SuccessRehashNeeded: // Legacy Version Hash (which we will likely get coming from pre ASP.NET Core Identity)
return true;
default:
return base.TryAuthenticate(authService, userName, password); //delegate to default hash/salt check from ServiceStack
}
}
}
public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
return base.OnAuthenticated(authService, session, tokens, authInfo);
}
}
Is there a better way? This works, when I use a legacy password, it authenticates, when I use the wrong legacy password, it fails.
Where are roles stored (the master list, I see that there is a UserAuthRole table)?