From 8b5d4ff5f7f5508e571509b229169f7f6d13a7f4 Mon Sep 17 00:00:00 2001 From: hzhang Date: Tue, 11 Mar 2025 11:47:37 +0000 Subject: [PATCH] add: Keycloak auth & git api client --- Alchegos.Core.csproj | 16 +-- nswag.json | 100 ++++++++++++++++++ .../Gitea/GiteaApiClient.Extension.cs | 19 ++++ src/Services/Gitea/GiteaApiOptions.cs | 7 ++ .../KeyCloak/IKeyCloakAuthProvider.cs | 6 ++ src/Services/KeyCloak/KeyCloakAuthOptions.cs | 11 ++ src/Services/KeyCloak/KeyCloakAuthProvider.cs | 38 +++++++ 7 files changed, 190 insertions(+), 7 deletions(-) create mode 100644 nswag.json create mode 100644 src/Services/Gitea/GiteaApiClient.Extension.cs create mode 100644 src/Services/Gitea/GiteaApiOptions.cs create mode 100644 src/Services/KeyCloak/IKeyCloakAuthProvider.cs create mode 100644 src/Services/KeyCloak/KeyCloakAuthOptions.cs create mode 100644 src/Services/KeyCloak/KeyCloakAuthProvider.cs diff --git a/Alchegos.Core.csproj b/Alchegos.Core.csproj index e620ce3..504f0e3 100644 --- a/Alchegos.Core.csproj +++ b/Alchegos.Core.csproj @@ -7,13 +7,15 @@ + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + - - - - ..\..\..\..\.nuget\packages\microsoft.extensions.options\9.0.2\lib\net9.0\Microsoft.Extensions.Options.dll - - - + + + diff --git a/nswag.json b/nswag.json new file mode 100644 index 0000000..5911a3e --- /dev/null +++ b/nswag.json @@ -0,0 +1,100 @@ +{ + "runtime": "Net80", + "defaultVariables": null, + "documentGenerator": { + "fromDocument": { + "url": "https://git.hangman-lab.top/swagger.v1.json", + "output": null, + "newLineBehavior": "Auto" + } + }, + "codeGenerators": { + "openApiToCSharpClient": { + "clientBaseClass": null, + "configurationClass": null, + "generateClientClasses": true, + "suppressClientClassesOutput": false, + "generateClientInterfaces": false, + "suppressClientInterfacesOutput": false, + "clientBaseInterface": null, + "injectHttpClient": true, + "disposeHttpClient": true, + "protectedMethods": [], + "generateExceptionClasses": true, + "exceptionClass": "ApiException", + "wrapDtoExceptions": true, + "useHttpClientCreationMethod": false, + "httpClientType": "System.Net.Http.HttpClient", + "useHttpRequestMessageCreationMethod": false, + "useBaseUrl": true, + "generateBaseUrlProperty": true, + "generateSyncMethods": false, + "generatePrepareRequestAndProcessResponseAsAsyncMethods": false, + "exposeJsonSerializerSettings": false, + "clientClassAccessModifier": "public", + "typeAccessModifier": "public", + "propertySetterAccessModifier": "", + "generateNativeRecords": false, + "generateContractsOutput": false, + "contractsNamespace": null, + "contractsOutputFilePath": null, + "parameterDateTimeFormat": "s", + "parameterDateFormat": "yyyy-MM-dd", + "generateUpdateJsonSerializerSettingsMethod": true, + "useRequestAndResponseSerializationSettings": false, + "serializeTypeInformation": false, + "queryNullValue": "", + "className": "GiteaApiClient", + "operationGenerationMode": "MultipleClientsFromOperationId", + "additionalNamespaceUsages": [], + "additionalContractNamespaceUsages": [], + "generateOptionalParameters": false, + "generateJsonMethods": false, + "enforceFlagEnums": false, + "parameterArrayType": "System.Collections.Generic.IEnumerable", + "parameterDictionaryType": "System.Collections.Generic.IDictionary", + "responseArrayType": "System.Collections.Generic.ICollection", + "responseDictionaryType": "System.Collections.Generic.IDictionary", + "wrapResponses": false, + "wrapResponseMethods": [], + "generateResponseClasses": true, + "responseClass": "SwaggerResponse", + "namespace": "Alchegos.Core.Services.Gitea", + "requiredPropertiesMustBeDefined": true, + "dateType": "System.DateTimeOffset", + "jsonConverters": null, + "anyType": "object", + "dateTimeType": "System.DateTimeOffset", + "timeType": "System.TimeSpan", + "timeSpanType": "System.TimeSpan", + "arrayType": "System.Collections.Generic.ICollection", + "arrayInstanceType": "System.Collections.ObjectModel.Collection", + "dictionaryType": "System.Collections.Generic.IDictionary", + "dictionaryInstanceType": "System.Collections.Generic.Dictionary", + "arrayBaseType": "System.Collections.ObjectModel.Collection", + "dictionaryBaseType": "System.Collections.Generic.Dictionary", + "classStyle": "Poco", + "jsonLibrary": "NewtonsoftJson", + "generateDefaultValues": true, + "generateDataAnnotations": true, + "excludedTypeNames": [], + "excludedParameterNames": [], + "handleReferences": false, + "generateImmutableArrayProperties": false, + "generateImmutableDictionaryProperties": false, + "jsonSerializerSettingsTransformationMethod": null, + "inlineNamedArrays": false, + "inlineNamedDictionaries": false, + "inlineNamedTuples": true, + "inlineNamedAny": false, + "generateDtoTypes": true, + "generateOptionalPropertiesAsNullable": false, + "generateNullableReferenceTypes": false, + "templateDirectory": null, + "serviceHost": null, + "serviceSchemes": null, + "output": "src/Services/Gitea/GiteaApiClient.cs", + "newLineBehavior": "Auto" + } + } +} \ No newline at end of file diff --git a/src/Services/Gitea/GiteaApiClient.Extension.cs b/src/Services/Gitea/GiteaApiClient.Extension.cs new file mode 100644 index 0000000..ecb3a47 --- /dev/null +++ b/src/Services/Gitea/GiteaApiClient.Extension.cs @@ -0,0 +1,19 @@ +using System.Net; +using Microsoft.Extensions.Options; + +namespace Alchegos.Core.Services.Gitea; + +public partial class GiteaApiClient +{ + private GiteaApiOptions Options; + + public GiteaApiClient(HttpClient client, IOptions options) + { + + _httpClient = client; + Options = options.Value; + BaseUrl = Options.BaseUrl; + _httpClient.DefaultRequestHeaders.Add("Authorization", $"token {Options.Token}"); + } + +} \ No newline at end of file diff --git a/src/Services/Gitea/GiteaApiOptions.cs b/src/Services/Gitea/GiteaApiOptions.cs new file mode 100644 index 0000000..de565c4 --- /dev/null +++ b/src/Services/Gitea/GiteaApiOptions.cs @@ -0,0 +1,7 @@ +namespace Alchegos.Core.Services.Gitea; + +public class GiteaApiOptions +{ + public string BaseUrl { get; set; } + public string Token { get; set; } +} diff --git a/src/Services/KeyCloak/IKeyCloakAuthProvider.cs b/src/Services/KeyCloak/IKeyCloakAuthProvider.cs new file mode 100644 index 0000000..aed3ea4 --- /dev/null +++ b/src/Services/KeyCloak/IKeyCloakAuthProvider.cs @@ -0,0 +1,6 @@ +namespace Alchegos.Core.Services.KeyCloak; + +public interface IKeyCloakAuthProvider +{ + Task GetTokenAsync(); +} \ No newline at end of file diff --git a/src/Services/KeyCloak/KeyCloakAuthOptions.cs b/src/Services/KeyCloak/KeyCloakAuthOptions.cs new file mode 100644 index 0000000..021773b --- /dev/null +++ b/src/Services/KeyCloak/KeyCloakAuthOptions.cs @@ -0,0 +1,11 @@ +namespace Alchegos.Core.Services.KeyCloak; + +public class KeyCloakAuthOptions +{ + public string Authority { get; set; } + public string ClientId { get; set; } + public string ClientSecret { get; set; } + public string UserName { get; set; } + public string Password { get; set; } + public string Scopes { get; set; } +} \ No newline at end of file diff --git a/src/Services/KeyCloak/KeyCloakAuthProvider.cs b/src/Services/KeyCloak/KeyCloakAuthProvider.cs new file mode 100644 index 0000000..cbea319 --- /dev/null +++ b/src/Services/KeyCloak/KeyCloakAuthProvider.cs @@ -0,0 +1,38 @@ +using System.Text.Json; +using Microsoft.Extensions.Options; + +namespace Alchegos.Core.Services.KeyCloak; + +public class KeyCloakAuthProvider : IKeyCloakAuthProvider +{ + private KeyCloakAuthOptions Options { get; set; } + private HttpClient Client { get; set; } + + public KeyCloakAuthProvider(IOptions options, HttpClient client) + { + Options = options.Value; + Client = client; + } + + public async Task GetTokenAsync() + { + string tokenEndpoint = $"{Options.Authority}/protocol/openid-connect/token"; + Console.WriteLine(tokenEndpoint); + Dictionary parameters = new Dictionary + { + {"grant_type", "password"}, + {"client_id", Options.ClientId}, + {"client_secret", Options.ClientSecret}, + {"username", Options.UserName}, + {"password", Options.Password}, + {"scope", Options.Scopes} + }; + FormUrlEncodedContent content = new FormUrlEncodedContent(parameters); + HttpResponseMessage response = await Client.PostAsync(tokenEndpoint, content); + response.EnsureSuccessStatusCode(); + string json = await response.Content.ReadAsStringAsync(); + using JsonDocument document = JsonDocument.Parse(json); + string token = document.RootElement.GetProperty("access_token").GetString(); + return $"Bearer {token}"; + } +} \ No newline at end of file