Is there a way to create new api keys on existing users? It looks api keys are only generated automatically on new user registrations (OnRegistered event).
Seems like you would want to generate keys during init database of apiKeys for any existing users.
You can basically just do what the ApiKeyAuthProvider does to generate new keys for new users, you’ll just need to do this for each user missing keys.
We don’t have the necessary APIs to do this for all supported API Key Auth Repositories, but here’s an example of how you could create API Keys for existing users without API Keys by registering an AfterInitCallback in your AppHost (so it’s run after all plugins are registered):
AfterInitCallbacks.Add(host =>
{
var authProvider = (ApiKeyAuthProvider)
AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name);
using (var db = host.TryResolve<IDbConnectionFactory>().Open())
{
var userWithKeysIds = db.Column<string>(db.From<ApiKey>()
.SelectDistinct(x => x.UserAuthId)).Map(int.Parse);
var userIdsMissingKeys = db.Column<string>(db.From<UserAuth>()
.Where(x => userWithKeysIds.Count == 0 || !userWithKeysIds.Contains(x.Id))
.Select(x => x.Id));
var authRepo = (IManageApiKeys)host.TryResolve<IAuthRepository>();
foreach (var userId in userIdsMissingKeys)
{
var apiKeys = authProvider.GenerateNewApiKeys(userId.ToString());
authRepo.StoreAll(apiKeys);
}
}
});
If you’re using a different Auth Repository you’ll just need to change it to get the existing UserIds that don’t have keys.
ok cool I’ll look into why that is, but here’s another way you can fetch the ApiKeyAuthProvider:
AfterInitCallbacks.Add(host =>
{
var authProvider = (ApiKeyAuthProvider) AuthenticateService.GetAuthProviders()
.First(x => x is ApiKeyAuthProvider);
using (var db = host.TryResolve<IDbConnectionFactory>().Open())
{
var userWithKeysIds = db.Column<string>(db.From<ApiKey>()
.SelectDistinct(x => x.UserAuthId)).Map(int.Parse);
var userIdsMissingKeys = db.Column<string>(db.From<UserAuth>()
.Where(x => userWithKeysIds.Count == 0 || !userWithKeysIds.Contains(x.Id))
.Select(x => x.Id));
var authRepo = (IManageApiKeys)host.TryResolve<IAuthRepository>();
foreach (var userId in userIdsMissingKeys)
{
var apiKeys = authProvider.GenerateNewApiKeys(userId.ToString());
authRepo.StoreAll(apiKeys);
}
}
});
Whilst you can also just reuse the instance you registered in theAuthFeature, e.g:
var authProvider = new ApiKeyAuthProvider(AppSettings);
Plugins.Add(new AuthFeature(
() => new E2HUserSession(),
new IAuthProvider[] {
new BasicAuthProvider(),
new ApiKeyAuthProvider() {},
new E2HAuthProvider(Resolve<IUserService>())
}
);
AfterInitCallbacks.Add(host => {
//...
var apiKeys = authProvider.GenerateNewApiKeys(userId.ToString());
});
ok the issue was due to not passing in an AppSettings when registering the Auth Provider, e.g:
new IAuthProvider[] {
new BasicAuthProvider(),
new ApiKeyAuthProvider() {},
new E2HAuthProvider(Resolve<IUserService>())
}
Instead of:
new IAuthProvider[] {
new BasicAuthProvider(AppSettings),
new ApiKeyAuthProvider(AppSettings) {},
new E2HAuthProvider(Resolve<IUserService>())
}
It’s a good idea to initialize it with an AppSettings even if you’re not using it as it later lets you customize it using any AppSettings without recompiling or redeploying, but I’ve changed it to call the same base constructor in this commit which will let you fetch the AuthProvider by name in the next release.
Otherwise your modified query also works, just means the filtering is performed on the client instead of in the RDBMS, but it only needs to be run once so either option would work well.