From f73342cb6b0592d3a6310f9a12fd40b4bf218e5c Mon Sep 17 00:00:00 2001 From: crupest Date: Sun, 18 Dec 2022 20:07:29 +0800 Subject: Develop secret api. v42 --- .../CrupestApi.Commons/Crud/CrudService.cs | 17 ++-- .../Crud/CrudServiceCollectionExtensions.cs | 10 +- .../Crud/CrudWebApplicationExtensions.cs | 5 +- .../CrupestApi/CrupestApi.Commons/Error.cs | 19 ---- .../CrupestApi.Commons/HttpContextExtensions.cs | 110 +++++++++++++++++++++ .../CrupestApi.Commons/HttpResponseAction.cs | 3 - .../CrupestApi.Commons/ISecretService.cs | 6 ++ .../CrupestApi/CrupestApi.Commons/Json.cs | 62 ------------ .../CrupestApi.Secrets/SecretsService.cs | 14 --- 9 files changed, 138 insertions(+), 108 deletions(-) delete mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs delete mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs create mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Commons/ISecretService.cs delete mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs delete mode 100644 docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsService.cs (limited to 'docker/crupest-api/CrupestApi') diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs index d371c84..184ac0a 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs @@ -20,15 +20,20 @@ public class CrudService : IDisposable where TEntity : class _jsonHelper = jsonHelper; _logger = loggerFactory.CreateLogger>(); - if (!_table.CheckExistence(_dbConnection)) - { - DoInitializeDatabase(_dbConnection); - } + CheckDatabase(_dbConnection); } public EntityJsonHelper JsonHelper => _jsonHelper; - public virtual void DoInitializeDatabase(IDbConnection connection) + protected virtual void CheckDatabase(IDbConnection dbConnection) + { + if (!_table.CheckExistence(dbConnection)) + { + DoInitializeDatabase(dbConnection); + } + } + + private void DoInitializeDatabase(IDbConnection connection) { using var transaction = connection.BeginTransaction(); connection.Execute(_table.GenerateCreateTableSql(), transaction: transaction); @@ -59,7 +64,7 @@ public class CrudService : IDisposable where TEntity : class return (string)key; } - public void Update(object key, JsonElement jsonElement) + public void UpdateByKey(object key, JsonElement jsonElement) { var updateClauses = _jsonHelper.ConvertJsonElementToUpdateClause(jsonElement); _table.Update(_dbConnection, WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key), updateClauses); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudServiceCollectionExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudServiceCollectionExtensions.cs index 8854976..d51c0a1 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudServiceCollectionExtensions.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudServiceCollectionExtensions.cs @@ -12,13 +12,19 @@ public static class CrudServiceCollectionExtensions return services; } - public static IServiceCollection AddCrud(this IServiceCollection services) where TEntity : class + public static IServiceCollection AddCrud(this IServiceCollection services) where TEntity : class where TCrudService : CrudService { AddCrudCore(services); - services.TryAddScoped>(); + services.TryAddScoped, TCrudService>(); services.TryAddScoped>(); return services; } + + public static IServiceCollection AddCrud(this IServiceCollection services) where TEntity : class + { + return services.AddCrud>(); + } + } diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs index 7331273..9e85c68 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs @@ -2,10 +2,11 @@ namespace CrupestApi.Commons.Crud; public static class CrudWebApplicationExtensions { - public static WebApplication UseCrud(this WebApplication app, string path) where TEntity : class + public static WebApplication UseCrud(this WebApplication app, string path, string? key) where TEntity : class { app.MapGet(path, async (context) => { + var crudService = context.RequestServices.GetRequiredService>(); var allEntities = crudService.GetAll(); await context.ResponseJsonAsync(allEntities.Select(e => crudService.JsonHelper.ConvertEntityToDictionary(e))); @@ -44,7 +45,7 @@ public static class CrudWebApplicationExtensions } var jsonDocument = await context.Request.ReadJsonAsync(); - crudService.Update(key, jsonDocument.RootElement); + crudService.UpdateByKey(key, jsonDocument.RootElement); await context.ResponseJsonAsync(crudService.JsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key))); }); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs deleted file mode 100644 index b298f7a..0000000 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Error.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace CrupestApi.Commons; - -public class ErrorBody -{ - public ErrorBody(string message) - { - Message = message; - } - - public string Message { get; set; } -} - -public static class CrupestApiErrorExtensions -{ - public static async Task WriteErrorMessageAsync(this HttpResponse response, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) - { - await response.WriteJsonAsync(new ErrorBody(message), statusCode: statusCode, beforeWriteBody, cancellationToken); - } -} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs new file mode 100644 index 0000000..1d7d858 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpContextExtensions.cs @@ -0,0 +1,110 @@ +using System.Text.Json; +using Microsoft.Extensions.Options; + +namespace CrupestApi.Commons; + +public delegate void HttpResponseAction(HttpResponse response); + +public class MessageBody +{ + public MessageBody(string message) + { + Message = message; + } + + public string Message { get; set; } +} + +public static class CrupestApiJsonExtensions +{ + public static IServiceCollection AddJsonOptions(this IServiceCollection services) + { + services.AddOptions(); + services.Configure(config => + { + config.AllowTrailingCommas = true; + config.PropertyNameCaseInsensitive = true; + config.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; + }); + + return services; + } + + public static async Task ReadJsonAsync(this HttpRequest request) + { + using var stream = request.Body; + return await JsonDocument.ParseAsync(stream); + } + + public static async Task WriteJsonAsync(this HttpResponse response, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) + { + var jsonOptions = response.HttpContext.RequestServices.GetRequiredService>(); + byte[] json = JsonSerializer.SerializeToUtf8Bytes(bodyObject, jsonOptions.Value); + + var byteCount = json.Length; + + response.StatusCode = statusCode; + response.Headers.ContentType = "application/json; charset=utf-8"; + response.Headers.ContentLength = byteCount; + + if (beforeWriteBody is not null) + { + beforeWriteBody(response); + } + + await response.Body.WriteAsync(json, cancellationToken); + } + + public static async Task WriteMessageAsync(this HttpResponse response, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) + { + await response.WriteJsonAsync(new MessageBody(message), statusCode: statusCode, beforeWriteBody, cancellationToken); + } + + public static Task ResponseJsonAsync(this HttpContext context, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) + { + return context.Response.WriteJsonAsync(bodyObject, statusCode, beforeWriteBody, cancellationToken); + } + + public static Task ResponseMessageAsync(this HttpContext context, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) + { + return context.Response.WriteMessageAsync(message, statusCode, beforeWriteBody, cancellationToken); + } + + public static string? GetToken(this HttpRequest request) + { + var token = request.Headers["Authorization"].ToString(); + if (token.StartsWith("Bearer ")) + { + token = token.Substring("Bearer ".Length); + return token; + } + + if (request.Query.TryGetValue("token", out var tokenValues)) + { + return tokenValues.Last(); + } + + return null; + } + + public static bool RequirePermission(this HttpContext context, string? permission) + { + if (permission is null) return true; + + var token = context.Request.GetToken(); + if (token is null) + { + context.ResponseMessageAsync("Unauthorized", 401); + return false; + } + + var secretService = context.RequestServices.GetRequiredService(); + var permissions = secretService.GetPermissions(token); + if (!permissions.Contains(permission)) + { + context.ResponseMessageAsync("Forbidden", 403); + return false; + } + return true; + } +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs deleted file mode 100644 index 9023f4e..0000000 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace CrupestApi.Commons; - -public delegate void HttpResponseAction(HttpResponse response); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/ISecretService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/ISecretService.cs new file mode 100644 index 0000000..eeabb0d --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/ISecretService.cs @@ -0,0 +1,6 @@ +namespace CrupestApi.Commons; + +interface ISecretService +{ + List GetPermissions(string secret); +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs deleted file mode 100644 index 61bcc61..0000000 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System.Text.Json; -using Microsoft.Extensions.Options; -using Microsoft.Net.Http.Headers; - -namespace CrupestApi.Commons; - -public static class CrupestApiJsonExtensions -{ - public static IServiceCollection AddJsonOptions(this IServiceCollection services) - { - services.AddOptions(); - services.Configure(config => - { - config.AllowTrailingCommas = true; - config.PropertyNameCaseInsensitive = true; - config.PropertyNamingPolicy = JsonNamingPolicy.CamelCase; - }); - - return services; - } - - public static async Task ReadJsonAsync(this HttpRequest request) - { - using var stream = request.Body; - return await JsonDocument.ParseAsync(stream); - } - - public static async Task WriteJsonAsync(this HttpResponse response, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) - { - var jsonOptions = response.HttpContext.RequestServices.GetRequiredService>(); - byte[] json = JsonSerializer.SerializeToUtf8Bytes(bodyObject, jsonOptions.Value); - - var byteCount = json.Length; - - response.StatusCode = statusCode; - response.Headers.ContentType = "application/json; charset=utf-8"; - response.Headers.ContentLength = byteCount; - - if (beforeWriteBody is not null) - { - beforeWriteBody(response); - } - - await response.Body.WriteAsync(json, cancellationToken); - } - - public static async Task WriteMessageAsync(this HttpResponse response, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) - { - await response.WriteJsonAsync(new ErrorBody(message), statusCode: statusCode, beforeWriteBody, cancellationToken); - } - - public static Task ResponseJsonAsync(this HttpContext context, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) - { - return context.Response.WriteJsonAsync(bodyObject, statusCode, beforeWriteBody, cancellationToken); - } - - public static Task ResponseMessageAsync(this HttpContext context, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) - { - return context.Response.WriteMessageAsync(message, statusCode, beforeWriteBody, cancellationToken); - } - -} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsService.cs deleted file mode 100644 index 7051602..0000000 --- a/docker/crupest-api/CrupestApi/CrupestApi.Secrets/SecretsService.cs +++ /dev/null @@ -1,14 +0,0 @@ -using CrupestApi.Commons.Crud; - -namespace CrupestApi.Secrets; - -public class SecretsService : CrudService -{ - private readonly ILogger _logger; - - public SecretsService(ITableInfoFactory tableInfoFactory, IDbConnectionFactory dbConnectionFactory, ILoggerFactory loggerFactory) - : base("secrets", tableInfoFactory, dbConnectionFactory, loggerFactory) - { - _logger = loggerFactory.CreateLogger(); - } -} -- cgit v1.2.3