最低API密钥ServiceStack身份验证+授权



我想使用API密钥尽可能简单地访问安全的ServiceStack web服务:

  • 我不想注册用户
  • 我不需要用户权限或角色
  • 自定义API密钥权限将是一个优势:
    • 能够将某些服务限制为特定的API密钥
  • API密钥将直接从数据库进行管理
  • 我需要重写哪些类或方法?有很多扩展点,但我不知道保留什么,重写什么:
    • OrmLiteAuthRepository(基本?(
    • ApiKeyAuthProvider
    • AuthUserSession

我可以使用承载令牌(API密钥(调用服务。它返回200禁忌。

ApiKeyAuthProvider.AuthenticateSync((:

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

userAuth为NULL,这将引发以下异常:

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

我将API密钥存储在SQL数据库中的"ApiKey"表中:

公共重写void配置(容器容器({string connectionString=GetConnectionStringByName("Main"(;//创建并注册配置为默认使用Live DB的OrmLite DB工厂var dbFactory=new OrmLiteConnectionFactory(connectionString,SqlServerDialect.Provider(;容器寄存器(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}
}));

}

API密钥AuthProvider可能不适合您的使用,因为它旨在为注册用户生成API密钥,为他们提供调用受保护API的替代方法。

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

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

您需要配置首选的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)));
}

配置使用API密钥AuthProvider:配置的ServiceStack的Auth功能

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

然后配置预先填充有要允许访问的客户端的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);
}
}
}

这将允许您使用基于角色的身份验证来保护对不同API的访问:

[ValidateIsAdmin]
public class AdminOnly { ... }
[ValidateHasRole("ClientAdmin")]
public class ClientAdminOnly { ... }
[ValidateHasRole("Client")]
public class AnyClient { ... }

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

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

有关如何实现API密钥IAuthWithRequest Auth提供程序的指南,请参阅现有的ApiKeyAuthProvider.cs,该提供程序可在其PreAuthenticateAsync((方法中验证BearerToken。

最新更新