简体   繁体   English

最小API Key ServiceStack认证+授权

[英]Minimum API Key ServiceStack authentication + authorization

I would like to use API key to access secured ServiceStack web service simply as possible:我想使用 API 密钥尽可能简单地访问受保护的 ServiceStack web 服务:

  • I do not want to be able to register an user我不想注册用户
  • I do not need user permissions or roles我不需要用户权限或角色
  • Custom API key permissions would be a plus:自定义 API 密钥权限将是一个加号:
    • Be able to limit some service to a specific API key.能够将某些服务限制为特定的 API 密钥。
  • API keys will be managed directly from the database API 密钥将直接从数据库管理
  • What are the classes or methods I need to override?我需要覆盖哪些类或方法? There are many extension points but I do not know what to keep and what to rewrite:有很多扩展点,但我不知道要保留什么以及重写什么:
    • OrmLiteAuthRepository (base?) OrmLiteAuthRepository(基础?)
    • ApiKeyAuthProvider ApiKeyAuthProvider
    • AuthUserSession授权用户会话

I am able to call a service with Bearer token (API key).我可以使用 Bearer 令牌(API 密钥)调用服务。 It returns 200 Forbidden.它返回 200 Forbidden。

ApiKeyAuthProvider.AuthenticateAsync(): ApiKeyAuthProvider.AuthenticateAsync():

// authRepo is ServiceStack.Auth.OrmLiteAuthRepositoryMultitenancy
var userAuth = await authRepo.GetUserAuthAsync(apiKey.UserAuthId, token).ConfigAwait();

userAuth is NULL and this will throw this exception: userAuth 是 NULL,这将引发此异常:

throw HttpError.Unauthorized(ErrorMessages.UserForApiKeyDoesNotExist.Localize(authService.Request));

I store my API keys at the 'ApiKey' table in SQL database:我将我的 API 密钥存储在 SQL 数据库的“ApiKey”表中:

public override void Configure(Container container) { string connectionString = GetConnectionStringByName("Main"); public override void Configure(Container container) { string connectionString = GetConnectionStringByName("Main"); // Create and register an OrmLite DB Factory configured to use Live DB by default var dbFactory = new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider); // 创建并注册一个默认配置为使用 Live DB 的 OrmLite 数据库工厂 var dbFactory = new OrmLiteConnectionFactory(connectionString, SqlServerDialect.Provider); container.Register(dbFactory); container.Register(dbFactory);

// 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}
    }));

} }

The API Key AuthProvider may not suit your use-case as it's designed to generate API Keys for registered users to provide an alternative way for them to call protected APIs. API 密钥 AuthProvider可能不适合您的用例,因为它旨在为注册用户生成 API 密钥,以便为他们提供调用受保护 API 的替代方式。

To be able to model this using ServiceStack's built-in Auth API Key Auth Providers I would still have a registered AuthProvider and users representing the client that would use the API Keys.为了能够 model 使用 ServiceStack 的内置 Auth API Key Auth Provider,我仍然会有一个注册的 AuthProvider 和代表将使用 API 密钥的客户端的用户。

But instead of providing User registration functionality, add them into the database manually then Generating API Keys for Existing Users .但不是提供用户注册功能,而是手动将它们添加到数据库中,然后Generating API Keys for Existing Users

You'll need to configure your preferred RDBMS to store the API Keys and Users in:您需要配置首选 RDBMS以将 API 密钥和用户存储在:

[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)));
}

Configure ServiceStack's Auth Feature configured with the API Key AuthProvider :使用API Key AuthProvider配置 ServiceStack 的Auth Feature

[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),
                    }
                }));
        });
}

Then configure an RDBMS OrmLiteAuthRepository pre-populated with the clients you want to allow access to, then generate any missing API Keys for them on startup:然后配置一个RDBMS OrmLiteAuthRepository预填充您要允许访问的客户端,然后在启动时为它们生成任何缺少的 API 密钥:

[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);
        }
    }
}

This will let you protect access to different APIs using role-based auth:这将使您可以使用基于角色的身份验证来保护对不同 API 的访问:

[ValidateIsAdmin]
public class AdminOnly { ... }

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

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

Note: The Admin is a super user role that can access any protected API注意: Admin是超级用户角色,可以访问任何受保护的 API

If you don't want all these Auth components for your App you'll have to create your own Custom Auth Provider that implements its own Authentication which doesn't need to use any other components as it has full control over how the request is authenticated.如果您不希望您的应用程序使用所有这些 Auth 组件,您必须创建自己的Custom Auth Provider来实现自己的 Authentication,它不需要使用任何其他组件,因为它可以完全控制请求的身份验证方式.

You can refer to the existing ApiKeyAuthProvider.cs for a guide on how to implement an API Key IAuthWithRequest Auth Provider that validates the BearerToken in its PreAuthenticateAsync() method .您可以参考现有的ApiKeyAuthProvider.cs以获取有关如何实现 API Key IAuthWithRequest Auth Provider的指南,该提供程序在其PreAuthenticateAsync() 方法中验证 BearerToken。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM