Аутентификация пользовательских учетных данных ServiceStack с использованием ключей API, сохраненных в БД

Прямо сейчас мы аутентифицируем наших пользователей с помощью этого:

public class WindowsAuthProvider : CredentialsAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "OurDomain"))
        {
            // TODO make sure user record exists in custom DB tables as well
            return pc.ValidateCredentials(userName, password);
        }
    }

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

Что прекрасно работает при использовании JsonServiceClient.

У нас есть некоторый унаследованный код, написанный на Visual FoxPro, который хочет вызывать некоторые аутентифицированные функции в ServiceStack... чтобы приспособиться к этому, мы хотели бы также разрешить использование ключей Api. Мы хотим, чтобы ключи API были сохранены в SQL Server, чтобы избежать проблем, если процесс останавливается / перезапускается. Таким образом, клиент будет аутентифицироваться с использованием учетных данных домена, а затем сгенерирует ключ API для последующих вызовов, которые будут сохранены в базе данных (в идеале можно просто использовать таблицу сервисных стеков (dbo.ApiKey).

Если бы мы установили это в соответствии с документами:

container.Register<IAuthRepository>(c => new OrmLiteAuthRepository(dbFactory));

Мы получаем ошибку на OnAuthenticated функция выше говорит нам, что мы должны позвонить Init()... как и попытка создать пользовательские таблицы. Поэтому я не уверен, как разрешить хранимые в БД API-ключи вместе с настраиваемой аутентификацией, которая опирается как на активный каталог, так и на наши пользовательские таблицы для пользователей и ролей.

Вместо того, чтобы наследовать от CredentialsAuthProvider, возможно, лучше зарегистрировать пользовательский IUserAuthRepository а также IManageRoles?

1 ответ

Решение

Ключ API AuthProvider должен быть зарегистрирован в вашей AuthFeature, например:

Plugins.Add(new AuthFeature(...,
    new IAuthProvider[] {
        new ApiKeyAuthProvider(AppSettings),
        new WindowsAuthProvider(AppSettings),
        //...
    }));

Который требует IAuthRepository как вы делаете

container.Register<IAuthRepository>(c => 
    new OrmLiteAuthRepository(dbFactory));

Любой AuthProvider, который требует создания внутренних таблиц или другой схемы, требует, чтобы его схема инициализировалась при запуске, что вы можете сделать с помощью:

container.Resolve<IAuthRepository>().InitSchema();

Всегда безопасно звонить InitSchema() поскольку он создает только отсутствующие таблицы или игнорируется иным образом для AuthRepositories, которые не требуют создания схемы.

Проблема, с которой вы столкнулись, заключается в том, что вы зарегистрировали IAuthRepository и наследуют CredentialsAuthProvider в котором вы не хотите его использовать, поэтому вы не можете вызвать CredentialsAuthProvider.OnAuthenticated(), поскольку он сохранит информацию об аутентификации пользователя в хранилище, если оно существует.

Так что вам нужно будет предоставить собственную реализацию без вызова base.OnAuthenticated()Например:

public class WindowsAuthProvider : CredentialsAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
    {
        using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "OurDomain"))
        {
            // TODO make sure user record exists in custom DB tables as well
            return pc.ValidateCredentials(userName, password);
        }
    }

    public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
    {
        try
        {
            session.IsAuthenticated = true;
            session.OnAuthenticated(authService, session, tokens, authInfo);
            AuthEvents.OnAuthenticated(authService.Request, session, authService, tokens, authInfo);
        }
        finally
        {
            this.SaveSession(authService, session, SessionExpiry);
        }

        return null;
    }
}
Другие вопросы по тегам