首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >最小API密钥ServiceStack认证+授权

最小API密钥ServiceStack认证+授权
EN

Stack Overflow用户
提问于 2022-03-01 08:12:58
回答 1查看 263关注 0票数 1

我想使用API键访问安全的ServiceStack web服务,只要有可能:

  • 我不想注册用户
  • 我不需要用户权限或角色。
  • 自定义API键权限将是一个加号:
    • 能够将某些服务限制为特定的API密钥。

  • API键将直接从数据库中管理。
  • 我需要重写哪些类或方法?有许多扩展点,但我不知道保留什么和重写什么:
    • OrmLiteAuthRepository (碱?)
    • ApiKeyAuthProvider
    • AuthUserSession

我能够用Bearer (API键)调用服务。它还回200紫禁城。

ApiKeyAuthProvider.AuthenticateAsync():

代码语言:javascript
复制
// authRepo is ServiceStack.Auth.OrmLiteAuthRepositoryMultitenancy
var userAuth = await authRepo.GetUserAuthAsync(apiKey.UserAuthId, token).ConfigAwait();

userAuth为NULL,这将引发此异常:

代码语言:javascript
复制
throw HttpError.Unauthorized(ErrorMessages.UserForApiKeyDoesNotExist.Localize(authService.Request));

我将API键存储在SQL数据库中的“ApiKey”表中:

公开覆盖void (容器容器){ string connectionString = GetConnectionStringByName("Main");//创建和注册一个OrmLite DB工厂,默认配置为使用Live =新的OrmLiteConnectionFactory(connectionString,SqlServerDialect.Provider);container.Register( dbFactory );

代码语言:javascript
复制
// Tell ServiceStack you want to persist User Auth Info in SQL Server
container.Register<IAuthRepository>(c => new OrmLiteAuthRepository(dbFactory) { UseDistinctRoleTables = true });

// It’s safe to always call this in your AppHost as it’s just ignored if you already have the tables created
container.Resolve<IAuthRepository>().InitSchema();

Plugins.Add(new AuthFeature(
    () => new AuthUserSession(),
    new IAuthProvider[]
    {
        new ApiKeyAuthProvider(AppSettings) {RequireSecureConnection = false}
    }));

}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-03-01 09:02:43

API键AuthProvider可能不适合您的用例,因为它的目的是为注册用户生成APIs,为他们调用受保护的API提供另一种方式。

为了能够使用ServiceStack内置的Auth密钥提供程序来建模,我仍然需要一个注册的AuthProvider和代表使用API的客户端的用户。

但是,与其提供用户注册功能,不如手动将它们添加到数据库中,然后再添加为现有用户生成API密钥

您需要配置您喜欢的RDBMS来将API和用户存储在:

代码语言:javascript
复制
[assembly: HostingStartup(typeof(MyApp.ConfigureDb))]
public class ConfigureDb : IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureServices((context, services) => 
            services.AddSingleton<IDbConnectionFactory>(
                new OrmLiteConnectionFactory(                  
                    context.Configuration.GetConnectionString("DefaultConnection"),
                    SqliteDialect.Provider)));
}

配置带有8月特征的ServiceStack的API键AuthProvider

代码语言:javascript
复制
[assembly: HostingStartup(typeof(MyApp.ConfigureAuth))]
public class ConfigureAuth : IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureAppHost(appHost =>
        {
            appHost.Plugins.Add(new AuthFeature(() => new AuthUserSession(),
                new IAuthProvider[] {
                    new ApiKeyAuthProvider(appHost.AppSettings) {
                       RequireSecureConnection = false,
                       SessionCacheDuration = TimeSpan.FromMinutes(10),
                    }
                }));
        });
}

然后配置一个预先填充了您希望允许访问的客户端的关系数据库OrmLiteAuthRepository,然后在启动时为它们生成缺少的API键:

代码语言:javascript
复制
[assembly: HostingStartup(typeof(MyApp.ConfigureAuthRepository))]
public class ConfigureAuthRepository : IHostingStartup
{
    public void Configure(IWebHostBuilder builder) => builder
        .ConfigureServices(services => services.AddSingleton<IAuthRepository>(c =>
            new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())))
        .ConfigureAppHost(appHost => {
            var authRepo = appHost.Resolve<IAuthRepository>();
            authRepo.InitSchema();
            CreateUser(authRepo, "admin@email.com", "Admin User", "p@55wOrd", 
                roles: new[] { RoleNames.Admin });
            CreateUser(authRepo, "admin.client@email.com", "Client Admin", "p@55wOrd", 
                roles: new[] { "ClientAdmin", "Client" });
            CreateUser(authRepo, "client@email.com", "Client User", "p@55wOrd", 
                roles: new[] { "Client" });
        }, 
        afterAppHostInit: appHost => {
            var authProvider = (ApiKeyAuthProvider)
                AuthenticateService.GetAuthProvider(ApiKeyAuthProvider.Name);
            
            using var db = appHost.TryResolve<IDbConnectionFactory>().Open();
            var userWithKeysIds = db.Column<string>(db.From<ApiKey>()
                .SelectDistinct(x => x.UserAuthId)).Map(int.Parse);

            // Use custom UserAuth if configured
            var userIdsMissingKeys = db.Column<string>(db.From<UserAuth>()
                .Where(x => userWithKeysIds.Count == 0 || !userWithKeysIds.Contains(x.Id))
                .Select(x => x.Id));

            var authRepo = (IManageApiKeys)appHost.TryResolve<IAuthRepository>();
            foreach (var userId in userIdsMissingKeys)
            {
                var apiKeys = authProvider.GenerateNewApiKeys(userId);
                authRepo.StoreAll(apiKeys);
            }
        });

    // Add initial Users to the configured Auth Repository
    public void CreateUser(IAuthRepository authRepo, string email, string name, string password, string[] roles)
    {
        if (authRepo.GetUserAuthByUserName(email) == null)
        {
            var newAdmin = new AppUser { Email = email, DisplayName = name };
            var user = authRepo.CreateUserAuth(newAdmin, password);
            authRepo.AssignRoles(user, roles);
        }
    }
}

这将使您可以使用基于角色的auth保护对不同API的访问:

代码语言:javascript
复制
[ValidateIsAdmin]
public class AdminOnly { ... }

[ValidateHasRole("ClientAdmin")]
public class ClientAdminOnly { ... }

[ValidateHasRole("Client")]
public class AnyClient { ... }

注意:管理是一个超级用户角色,可以访问任何受保护的API。

如果您不需要应用程序的所有这些Auth组件,您必须创建自己的自定义Auth提供者来实现自己的身份验证,它不需要使用任何其他组件,因为它可以完全控制请求的身份验证方式。

您可以参考现有的ApiKeyAuthProvider.cs来了解如何实现API键IAuthWithRequest Auth提供者以在PreAuthenticateAsync()方法中验证BearerToken。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71305469

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档