Authenticate server to server communication with A

2019-07-13 20:23发布

问题:

I have a couple of self-hosted windows services running with ServiceStack. These services are used by a bunch of WPF and WinForms client applications. I have written my own CredentialsAuthProvider. My first implementation of the user database was on MSSQL server using NHibernate. Now since the system is growing I reorganize things a bit. I have created a central 'infrastructue' service which uses Redis as data store and is responsible for account management, central configuration and preferences management. Later it will also contain central logging and RedisMQ. All accounts, roles etc are now stored there (instead of MSSQL). Account migration was successfuly and authentication works fine so far.

Now I have the problem, that clients and servers need to get and set their configurations / preferences. This means that my servers are also clients since they not only serve client requests for their specific business domain but itself need to call the 'infrastructure' server to load / update its own configuration and later log entries and messages.

To authenticate such requests I thought an API key is a good way to go. These requests are not user related and therefore do not need a gateway functionality, they simply need some communication with the central infrastructure server. So I was reading the ServiceStack docs about the API Key Provider, but unfortunately for me a lot remains unclear.

Here first some relevant code from my 'infrastructure' server's Configure method:

private PooledRedisClientManager RedisBusinessPool { get; set; }
//...
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager(connStrBus));
container.Register(c => new AppUserRepository(RedisBusinessPool));

Plugins.Add(new AuthFeature(() => new AuthUserSession(), 
    new IAuthProvider[] {
        new BediCredentialsAuthProvider(),
    }
));
// For the API keys I tried:
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[] {
       new ApiKeyAuthProvider(AppSettings)
       {
           KeyTypes = new []{"secret", "publishable"},
       }, 
    }
));

Since I enabled the API Key plugin I get an error on the client when I try to login:

ERROR; AccountManagerWinDesktop; [LoginViewModel+<Login>d__50.MoveNext]; - <username> failed to login to server <myInfrastructureServer>. Exception: 404 NotFound
Code: NotFound, Message: No configuration was added for OAuth provider 'credentials'

Does this mean, that I have to implement my own ApiKeyProvider to cooperate with my implementation of the CredentialAuthProvider? If so, what do I need to add?

In my CredentialAuthProvider implementation I have overwritten Logout, Authenticate, OnAuthenticated and TryAuthenticate. A WPF client offers a UI to store users and roles. They are stored on the Redis database including hashed passwords etc. In my TryAuthenticate implementation I simply have:

public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{   
    AppUser user = null;
    try
    {
        //the repository handles all Redis database access
        var userRepo = HostContext.TryResolve<AppUserRepository>();
        user = userRepo.GetAppUser(userName);

        if (user == null)
            throw HttpError.NotFound("User '{0}' not found. Please try again.".Fmt(userName));

        authService.Request.Items.Add("AppUser", user);
        var pwdMgr = new PwdManager();
        var hpwd = pwdMgr.GetHashedPassword(password, user.Salt);
        if (hpwd == user.Password)
        {
            //do stuff
        }
        else
        {
            // do other stuff
        }
        return hpwd == user.Password;
    }
    catch (Exception ex)
    {
        Log.Error($"Error retrieving user {user} to authenticate. Error: {ex}");
        throw;
    }
}

What I do not understand right now - Questions:

  1. How are API keys related to my own implementation of CredentialsAuthProvider?
  2. How can I issue API keys to an application server? (I read that ServiceStack creates keys automatically when a user is created, but I do not need this in my scenario)
  3. Do I also have to implement my own ApiKeyAuthProvidersimilar to the CredentialsAuthProvider I have overwritten? If so, is there a sample somewhere?
  4. Is there any object / data model for API keys?
  5. Do I need to implement something like the TryAuthenticate method above to verify my API Keys?

回答1:

You should only ever register 1 of any Plugin type, so change your AuthFeature plugin to register all Auth Providers you want to enable, e.g:

Plugins.Add(new AuthFeature(() => new AuthUserSession(),
    new IAuthProvider[] {
       new BediCredentialsAuthProvider(),
       new ApiKeyAuthProvider(AppSettings)
       {
           KeyTypes = new []{"secret", "publishable"},
       }, 
    }
));
  1. How are API keys related to my own implementation of CredentialsAuthProvider?

An API Key is assigned to a User, i.e. when a request is received with an API Key, they're authenticated as the user the API Key is assigned to. API Keys are created for each new user that's registered, the above configuration creates a secret and publishable key for a new register created with the /register service.

API Keys requires using a User Auth Repository

Your users need to be persisted in an AuthRepository in order to use the API Key AuthProvider. The list of support Auth Repositories are listed on in the documentation. Although you can use your own custom User Auth Repository if it implements IUserAuthRepository and IManableApiKeys interfaces.

  1. How can I issue API keys to an application server? (I read that ServiceStack creates keys automatically when a user is created, but I do not need this in my scenario)

An API Key is assigned to a User - all of ServiceStack AuthProviders revolves around Authenticating Users. One idea is to create a "User" to represent that App Server. You can use the IManageApiKeys API to create your own API Keys, there's an example of using this in the code-snippet for creating API Keys for existing Users.

  1. Do I also have to implement my own ApiKeyAuthProvider similar to the CredentialsAuthProvider I have overwritten? If so, is there a sample somewhere?

You wont need to implement anything to use the existing ApiKeyAuthProvider but if it doesn't do what you need you can take ApiKeyAuthProvider.cs and create a customized version that does what you need.

  1. Is there any object / data model for API keys?

The ApiKey class is the model that contains the API Key itself, which is persisted in all supported Auth Repositories.

  1. Do I need to implement something like the TryAuthenticate method above to verify my API Keys?

No.