使用DB存储的Api密钥对ServiceStack自定义凭据进行身份验证

时间:2016-08-11 14:22:57

标签: servicestack api-key servicestack-auth

目前,我们正在通过以下方式对用户进行身份验证:

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 Keys。我们希望API密钥存储在SQL Server中,以避免在进程停止/重新启动时出现问题。因此,客户端将使用域凭据进行身份验证,然后为将要存储在数据库中的后续调用生成API密钥(理想情况下,只需使用表servicestack就可以创建(dbo.ApiKey)。

如果我们按照文档设置:

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

上面的OnAuthenticated函数出现错误,告诉我们应该调用Init() ...就像尝试创建用户表一样。所以我不确定如何允许数据库存储的API密钥,以及依赖于活动目录的自定义身份验证以及用户和角色的自定义表。

而不是从CredentialsAuthProvider继承,也许最好注册自定义IUserAuthRepositoryIManageRoles

1 个答案:

答案 0 :(得分:2)

API Key AuthProvider需要在您的AuthFeature中注册,例如:

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

这需要像您一样IAuthRepository

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

任何需要创建后端表或其他架构的AuthProvider都要求在Startup上初始化其架构,您可以使用:

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

始终调用InitSchema()是安全的,因为它只会创建缺少的表,否则会忽略不需要创建模式的AuthRepositories。

您遇到的一个问题是您注册了IAuthRepository并继承了CredentialsAuthProvider您不想使用它,因此您无法拨打{{3}因为它会将用户身份验证信息保存到存储库(如果存在)。

因此,您需要在不调用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;
    }
}