From 4bbf686dc8dc4e037b4f1c774f2163902002dc92 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 18 Dec 2024 20:20:52 +0100 Subject: [PATCH 01/22] chore: update dependencies --- src/WART-Client/WART-Client.csproj | 2 +- src/WART-Tests/WART-Tests.csproj | 2 +- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 11b0635..bef0a81 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index ad6b507..d382240 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -19,7 +19,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index 4a6f538..b4a5560 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -8,7 +8,7 @@ - + From 34b3319e7c36c0d869c743e59ef7b10bd6aa6fb6 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sat, 28 Dec 2024 22:56:01 +0100 Subject: [PATCH 02/22] feat!: upgrade project to .NET 9 --- src/WART-Client/WART-Client.csproj | 2 +- src/WART-Core/WART-Core.csproj | 6 +++--- src/WART-Tests/WART-Tests.csproj | 4 ++-- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index bef0a81..265bef7 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net9.0 WART_Client WART_Client.Program false diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index ce614c7..b08965d 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 WART_Core true Francesco Del Re @@ -14,7 +14,7 @@ 4.0.0.0 4.0.0.0 - 5.3.4 + 5.4.0 icon.png README.md @@ -22,7 +22,7 @@ - + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index d382240..b4dadce 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 WART_Tests enable enable @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index b4a5560..26e4a94 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -1,7 +1,7 @@ - net8.0 + net9.0 WART_Api False false From 4ffc9397a7d40729f3d888f275bafd7f1ed5517b Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Thu, 9 Jan 2025 16:52:36 +0100 Subject: [PATCH 03/22] chore(deps): update dependencies to latest versions --- src/WART-Tests/WART-Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index b4dadce..f6e4b9f 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -11,14 +11,14 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 94a45c8086cd74c11232e6e2a7e60ab466272ca7 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sun, 12 Jan 2025 19:39:07 +0100 Subject: [PATCH 04/22] chore(deps): update dependencies to latest versions --- src/WART-Tests/WART-Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index f6e4b9f..225ef6d 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -19,7 +19,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From fde7807b825ccefc7d2b507c320b88ce4399ffe5 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 15 Jan 2025 13:00:36 +0100 Subject: [PATCH 05/22] chore: update packages to latest versions --- src/WART-Core/WART-Core.csproj | 4 ++-- src/WART-Tests/WART-Tests.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index b08965d..34d31fe 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index 225ef6d..e4fac37 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From dbe70242a5810bf6ebbdc75fc84554319a77e958 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 15 Jan 2025 13:00:47 +0100 Subject: [PATCH 06/22] chore: update packages to latest versions --- src/WART-Client/WART-Client.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 265bef7..ce82696 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -21,9 +21,9 @@ - - - + + + From cceeb8f4372d01ccb4c2f97514dcc11c4d2b44e4 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sat, 18 Jan 2025 15:24:50 +0100 Subject: [PATCH 07/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index ce82696..558a71c 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + From c253fc30b9477f1f65a239c5e65386333b2e5e53 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Fri, 24 Jan 2025 17:58:44 +0100 Subject: [PATCH 08/22] chore(deps): update dependencies to latest versions --- src/WART-Tests/WART-Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index e4fac37..378ef07 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -11,7 +11,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 08407053138cb6775f9ca5f7b4a90d19ad95dc4e Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Mon, 17 Feb 2025 01:17:13 +0100 Subject: [PATCH 09/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 8 ++++---- src/WART-Core/WART-Core.csproj | 4 ++-- src/WART-Tests/WART-Tests.csproj | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 558a71c..4d5d543 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -21,10 +21,10 @@ - - - - + + + + diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index 34d31fe..dd26ac3 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index 378ef07..9557123 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -15,11 +15,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + - + all runtime; build; native; contentfiles; analyzers; buildtransitive From c89428f0cfcf679ecbefa7f5b1a641cb562747f6 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sat, 22 Feb 2025 20:27:14 +0100 Subject: [PATCH 10/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 4d5d543..a3002c7 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + From ec12a98e81b2cecd9e78a79c3cec1011e1e6ecb6 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Mon, 3 Mar 2025 15:52:33 +0100 Subject: [PATCH 11/22] chore(deps): update dependencies to latest versions --- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index 26e4a94..572627c 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -8,7 +8,7 @@ - + From aa338a1afd8ea4c62f5da5c7be4a6c8b219b1ee6 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Mon, 10 Mar 2025 11:48:18 +0100 Subject: [PATCH 12/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index a3002c7..a9f7983 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + From 9436158e5c4ff8a7a3720249d67f7eced555227c Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sun, 16 Mar 2025 12:35:58 +0100 Subject: [PATCH 13/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 6 +++--- src/WART-Core/WART-Core.csproj | 4 ++-- src/WART-Tests/WART-Tests.csproj | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index a9f7983..bc1c54a 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -21,9 +21,9 @@ - - - + + + diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index dd26ac3..51d6eaa 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index 9557123..fe6309c 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 2dc0a5c5ae9e27493c5ed136bdc79646eab32521 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 19 Mar 2025 17:52:19 +0100 Subject: [PATCH 14/22] chore(deps): update dependencies to latest versions --- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index 572627c..d56f5f8 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -8,7 +8,7 @@ - + From 8eb6c69b7f97b2aeb8c36105dcf0ac5fea01a303 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sun, 23 Mar 2025 19:39:54 +0100 Subject: [PATCH 15/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index bc1c54a..4b975ab 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + From 69aba65c305f3213fdb5d3795fdd0177b2267aa1 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Tue, 1 Apr 2025 11:40:03 +0200 Subject: [PATCH 16/22] chore(deps): update dependencies to latest versions --- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index d56f5f8..2992af4 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -8,7 +8,7 @@ - + From 603a43633304b9fad191f25fd7235c7d9e070807 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 9 Apr 2025 13:52:37 +0200 Subject: [PATCH 17/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 8 ++++---- src/WART-Core/WART-Core.csproj | 4 ++-- src/WART-Tests/WART-Tests.csproj | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 4b975ab..03da621 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -21,10 +21,10 @@ - - - - + + + + diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index 51d6eaa..0b010b2 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index fe6309c..08f2334 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 1f6da010b3f398fd1ffe751e25f0f826cfc1f0fd Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Tue, 15 Apr 2025 00:24:11 +0200 Subject: [PATCH 18/22] chore(deps): update dependencies to latest versions --- src/WART-WebApiRealTime/WART-Api.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-WebApiRealTime/WART-Api.csproj b/src/WART-WebApiRealTime/WART-Api.csproj index 2992af4..792f9b1 100755 --- a/src/WART-WebApiRealTime/WART-Api.csproj +++ b/src/WART-WebApiRealTime/WART-Api.csproj @@ -8,7 +8,7 @@ - + From 06983d279b83da4e6c4b0ae5557a032b93117931 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Tue, 6 May 2025 11:48:22 +0200 Subject: [PATCH 19/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- src/WART-Tests/WART-Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index 03da621..fd55a91 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index 08f2334..a83ff79 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -19,7 +19,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 615ea4fcecca2807d4788f5dc656309af40237d2 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Wed, 14 May 2025 15:46:31 +0200 Subject: [PATCH 20/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 6 +++--- src/WART-Core/WART-Core.csproj | 4 ++-- src/WART-Tests/WART-Tests.csproj | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index fd55a91..b67b78f 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -21,9 +21,9 @@ - - - + + + diff --git a/src/WART-Core/WART-Core.csproj b/src/WART-Core/WART-Core.csproj index 0b010b2..4c3cbf6 100644 --- a/src/WART-Core/WART-Core.csproj +++ b/src/WART-Core/WART-Core.csproj @@ -22,8 +22,8 @@ - - + + diff --git a/src/WART-Tests/WART-Tests.csproj b/src/WART-Tests/WART-Tests.csproj index a83ff79..c9673cb 100644 --- a/src/WART-Tests/WART-Tests.csproj +++ b/src/WART-Tests/WART-Tests.csproj @@ -15,7 +15,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 9534b3cd369512d8d2777bb513b85612b97a9ea8 Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Sun, 18 May 2025 15:22:50 +0200 Subject: [PATCH 21/22] chore(deps): update dependencies to latest versions --- src/WART-Client/WART-Client.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/WART-Client/WART-Client.csproj b/src/WART-Client/WART-Client.csproj index b67b78f..b211044 100755 --- a/src/WART-Client/WART-Client.csproj +++ b/src/WART-Client/WART-Client.csproj @@ -24,7 +24,7 @@ - + From 2d2c56794096b7c3d6e6e88f26b4e206b010a0da Mon Sep 17 00:00:00 2001 From: Francesco Del Re Date: Tue, 20 May 2025 00:02:47 +0200 Subject: [PATCH 22/22] feat(signalr): add cookie-based authentication support --- README.md | 14 +- src/WART-Client/Program.cs | 27 +++- src/WART-Client/WartTestClientCookie.cs | 91 ++++++++++++ src/WART-Client/appsettings.json | 2 +- .../CookieApplicationBuilderExtension.cs | 22 +++ .../CookieServiceCollectionExtension.cs | 85 +++++++++++ .../Controllers/WartControllerCookie.cs | 19 +++ src/WART-Core/Enum/HubType.cs | 8 +- src/WART-Core/Hubs/WartHubCookie.cs | 16 ++ .../WartApplicationBuilderExtension.cs | 139 ++++++++++++------ .../WartServiceCollectionExtension.cs | 29 +++- .../Controllers/TestCookieController.cs | 126 ++++++++++++++++ src/WART-WebApiRealTime/Startup.cs | 18 ++- 13 files changed, 527 insertions(+), 69 deletions(-) create mode 100644 src/WART-Client/WartTestClientCookie.cs create mode 100644 src/WART-Core/Authentication/Cookie/CookieApplicationBuilderExtension.cs create mode 100644 src/WART-Core/Authentication/Cookie/CookieServiceCollectionExtension.cs create mode 100644 src/WART-Core/Controllers/WartControllerCookie.cs create mode 100644 src/WART-Core/Hubs/WartHubCookie.cs create mode 100644 src/WART-WebApiRealTime/Controllers/TestCookieController.cs diff --git a/README.md b/README.md index ece70ad..f986971 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ WART is a C# .NET library that enables you to extend any Web API controller and ## Features - Converts REST API calls into SignalR events, enabling real-time communication. -- Provides controllers (`WartController`, `WartControllerJwt`) for automatic SignalR event broadcasting. +- Provides controllers (`WartController`, `WartControllerJwt`, `WartControllerCookie`) for automatic SignalR event broadcasting. - Supports JWT authentication for SignalR hub connections. - Allows API exclusion from event broadcasting with `[ExcludeWart]` attribute. - Enables group-specific event dispatching with `[GroupWart("group_name")]`. @@ -134,6 +134,18 @@ hubConnection.On("Send", (data) => In the source code you can find a simple test client and WebApi project. +## Supported Authentication Modes + +The project supports three authentication modes for accessing the SignalR Hub: + +| Mode | Description | Hub Class | Required Middleware | +|--------------------------|---------------------------------------------------------------------------|----------------------|---------------------------| +| **No Authentication** | Open access without identity verification | `WartHub` | None | +| **JWT (Bearer Token)** | Authentication via JWT token in the `Authorization: Bearer ` header | `WartHubJwt` | `UseJwtMiddleware()` | +| **Cookie Authentication**| Authentication via HTTP cookies issued after login | `WartHubCookie` | `UseCookieMiddleware()` | + +> ⚙️ Authentication mode is selected through the `HubType` configuration in the application startup. + ### Excluding APIs from Event Propagation There might be scenarios where you want to exclude specific APIs from propagating events to connected clients. This can be particularly useful when certain endpoints should not trigger updates, notifications, or other real-time messages through SignalR. To achieve this, you can use a custom filter called `ExcludeWartAttribute`. By decorating the desired API endpoints with this attribute, you can prevent them from being included in the SignalR event propagation logic, for example: diff --git a/src/WART-Client/Program.cs b/src/WART-Client/Program.cs index bc83f57..aa1a7dd 100755 --- a/src/WART-Client/Program.cs +++ b/src/WART-Client/Program.cs @@ -22,16 +22,27 @@ private static async Task Main() Console.WriteLine($"Connecting to {wartHubUrl}"); - var auth = configuration["AuthenticationJwt"]; + var auth = configuration["AuthenticationType"] ?? "NoAuth"; - if (bool.Parse(auth)) + switch (auth.ToLowerInvariant()) { - var key = configuration["Key"]; - await WartTestClientJwt.ConnectAsync(wartHubUrl, key); - } - else - { - await WartTestClient.ConnectAsync(wartHubUrl); + default: + case "noauth": + { + await WartTestClient.ConnectAsync(wartHubUrl); + break; + } + case "jwt": + { + var key = configuration["Key"]; + await WartTestClientJwt.ConnectAsync(wartHubUrl, key); + break; + } + case "cookie": + { + await WartTestClientCookie.ConnectAsync(wartHubUrl); + break; + } } Console.WriteLine($"Connected to {wartHubUrl}"); diff --git a/src/WART-Client/WartTestClientCookie.cs b/src/WART-Client/WartTestClientCookie.cs new file mode 100644 index 0000000..9e692c6 --- /dev/null +++ b/src/WART-Client/WartTestClientCookie.cs @@ -0,0 +1,91 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using Microsoft.AspNetCore.Http.Connections; +using Microsoft.AspNetCore.SignalR.Client; +using System; +using System.Collections.Generic; +using System.Net; +using System.Net.Http; +using System.Text; +using System.Threading.Tasks; + +namespace WART_Client +{ + /// + /// A simple SignalR WART test client with Cookie authentication. + /// + public static class WartTestClientCookie + { + public static async Task ConnectAsync(string hubUrl) + { + try + { + var cookieContainer = new CookieContainer(); + var handler = new HttpClientHandler + { + CookieContainer = cookieContainer, + UseCookies = true, + AllowAutoRedirect = true + }; + + using var httpClient = new HttpClient(handler); + + var loginContent = new FormUrlEncodedContent(new[] + { + new KeyValuePair("username", "test_username"), + new KeyValuePair("password", "test_password") + }); + + var loginUri = new Uri(new Uri(hubUrl), "/api/TestCookie/login"); + var loginResponse = await httpClient.PostAsync(loginUri, loginContent); + loginResponse.EnsureSuccessStatusCode(); + + Console.WriteLine("Login successful. Connecting to SignalR..."); + + //var uri = new Uri(hubUrl); + //cookieContainer.Add(uri, new Cookie("WART.AuthCookie", "sample_value")); + + var hubConnection = new HubConnectionBuilder() + .WithUrl(hubUrl, options => + { + options.HttpMessageHandlerFactory = _ => handler; + options.Transports = HttpTransportType.WebSockets | + HttpTransportType.ServerSentEvents | + HttpTransportType.LongPolling; + }) + .WithAutomaticReconnect() + .Build(); + + hubConnection.On("Send", (data) => + { + Console.WriteLine(data); + Console.WriteLine($"Message size: {Encoding.UTF8.GetBytes(data).Length} bytes"); + Console.WriteLine(); + }); + + hubConnection.Closed += async (ex) => + { + Console.WriteLine($"Connection closed: {ex?.Message}"); + await Task.Delay(new Random().Next(0, 5) * 1000); + if (hubConnection != null) + await hubConnection.StartAsync(); + }; + + hubConnection.On("ConnectionFailed", (ex) => + { + Console.WriteLine($"Connection failed: {ex.Message}"); + return Task.CompletedTask; + }); + + await hubConnection.StartAsync(); + Console.WriteLine("SignalR connection started."); + } + catch (Exception e) + { + Console.WriteLine(e.Message); + } + + await Task.CompletedTask; + } + } +} \ No newline at end of file diff --git a/src/WART-Client/appsettings.json b/src/WART-Client/appsettings.json index 544e8d3..f990e0e 100644 --- a/src/WART-Client/appsettings.json +++ b/src/WART-Client/appsettings.json @@ -3,7 +3,7 @@ "Host": "localhost", "Port": "54644", "Hubname": "warthub", - "AuthenticationJwt": "true", + "AuthenticationType": "JWT", "Key": "dn3341fmcscscwe28419brhwbwgbss4t", "WartGroup": "SampleGroupName" } \ No newline at end of file diff --git a/src/WART-Core/Authentication/Cookie/CookieApplicationBuilderExtension.cs b/src/WART-Core/Authentication/Cookie/CookieApplicationBuilderExtension.cs new file mode 100644 index 0000000..667f578 --- /dev/null +++ b/src/WART-Core/Authentication/Cookie/CookieApplicationBuilderExtension.cs @@ -0,0 +1,22 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using Microsoft.AspNetCore.Builder; + +namespace WART_Core.Authentication.Cookie +{ + public static class CookieApplicationBuilderExtension + { + /// + /// Use Cookie authentication dependency to IApplicationBuilder. + /// + /// The IApplicationBuilder to configure the middleware pipeline. + /// + public static IApplicationBuilder UseCookieMiddleware(this IApplicationBuilder app) + { + app.UseAuthentication(); + app.UseAuthorization(); + + return app; + } + } +} \ No newline at end of file diff --git a/src/WART-Core/Authentication/Cookie/CookieServiceCollectionExtension.cs b/src/WART-Core/Authentication/Cookie/CookieServiceCollectionExtension.cs new file mode 100644 index 0000000..df778ca --- /dev/null +++ b/src/WART-Core/Authentication/Cookie/CookieServiceCollectionExtension.cs @@ -0,0 +1,85 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using System; +using System.IO; +using System.Linq; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.DataProtection; +using Microsoft.AspNetCore.HttpOverrides; +using Microsoft.AspNetCore.ResponseCompression; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using WART_Core.Hubs; +using WART_Core.Services; + +namespace WART_Core.Authentication.Cookie +{ + public static class CookieServiceCollectionExtension + { + /// + /// Adds Cookie authentication middleware to the service collection. + /// Configures the authentication parameters, SignalR settings, and response compression. + /// + /// The service collection to add the middleware to. + /// Optional path for the login redirect (default: /Account/Login). + /// Optional path for access denied redirect (default: /Account/Denied). + /// The updated service collection. + public static IServiceCollection AddCookieMiddleware( + this IServiceCollection services, + string loginPath = "/Account/Login", + string accessDeniedPath = "/Account/AccessDenied") + { + // Configure forwarded headers (support for reverse proxy) + services.Configure(options => + { + options.ForwardedHeaders = + ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + }); + + // Add logging support + services.AddLogging(configure => configure.AddConsole()); + + // Add Data Protection with key persistence + var keysPath = Path.Combine(AppContext.BaseDirectory, "keys"); + Directory.CreateDirectory(keysPath); + services.AddDataProtection() + .PersistKeysToFileSystem(new DirectoryInfo(keysPath)) + .SetApplicationName("WART_App"); + + // Configure cookie-based authentication + services.AddAuthentication("WartCookieAuth") + .AddCookie("WartCookieAuth", options => + { + options.LoginPath = loginPath; + options.AccessDeniedPath = accessDeniedPath; + options.Cookie.Name = "WART.AuthCookie"; + options.ExpireTimeSpan = TimeSpan.FromHours(1); + options.SlidingExpiration = true; + }); + + // Register WART event queue service + services.AddSingleton(); + + // Register the WART event worker for the cookie-authenticated hub + services.AddHostedService>(); + + // SignalR configuration + services.AddSignalR(options => + { + options.EnableDetailedErrors = true; + options.HandshakeTimeout = TimeSpan.FromSeconds(15); + options.KeepAliveInterval = TimeSpan.FromSeconds(15); + options.ClientTimeoutInterval = TimeSpan.FromSeconds(30); + }); + + // Compression for SignalR WebSocket/Binary transport + services.AddResponseCompression(opts => + { + opts.MimeTypes = ResponseCompressionDefaults.MimeTypes.Concat( + new[] { "application/octet-stream" }); + }); + + return services; + } + } +} \ No newline at end of file diff --git a/src/WART-Core/Controllers/WartControllerCookie.cs b/src/WART-Core/Controllers/WartControllerCookie.cs new file mode 100644 index 0000000..27473c1 --- /dev/null +++ b/src/WART-Core/Controllers/WartControllerCookie.cs @@ -0,0 +1,19 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using WART_Core.Hubs; + +namespace WART_Core.Controllers +{ + /// + /// The WART Controller with Cookie authentication + /// + public class WartControllerCookie : WartBaseController + { + public WartControllerCookie(IHubContext hubContext, ILogger logger) + : base(hubContext, logger) + { + } + } +} diff --git a/src/WART-Core/Enum/HubType.cs b/src/WART-Core/Enum/HubType.cs index c099237..2b407a0 100755 --- a/src/WART-Core/Enum/HubType.cs +++ b/src/WART-Core/Enum/HubType.cs @@ -11,9 +11,15 @@ public enum HubType /// Simple SignalR hub without authentication /// NoAuthentication, + /// /// SignalR hub with JWT authentication /// - JwtAuthentication + JwtAuthentication, + + /// + /// SignalR hub with Cookie authentication + /// + CookieAuthentication } } \ No newline at end of file diff --git a/src/WART-Core/Hubs/WartHubCookie.cs b/src/WART-Core/Hubs/WartHubCookie.cs new file mode 100644 index 0000000..7508a7e --- /dev/null +++ b/src/WART-Core/Hubs/WartHubCookie.cs @@ -0,0 +1,16 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.Logging; + +namespace WART_Core.Hubs +{ + /// + /// The WART SignalR hub with Cookie-based authentication. + /// + [Authorize] + public class WartHubCookie : WartHubBase + { + public WartHubCookie(ILogger logger) : base(logger) { } + } +} \ No newline at end of file diff --git a/src/WART-Core/Middleware/WartApplicationBuilderExtension.cs b/src/WART-Core/Middleware/WartApplicationBuilderExtension.cs index a40e5d8..d5fa39b 100755 --- a/src/WART-Core/Middleware/WartApplicationBuilderExtension.cs +++ b/src/WART-Core/Middleware/WartApplicationBuilderExtension.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using WART_Core.Authentication.Cookie; using WART_Core.Authentication.JWT; using WART_Core.Enum; using WART_Core.Hubs; @@ -47,22 +48,38 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app { app.UseRouting(); - if (hubType == HubType.NoAuthentication) + switch(hubType) { - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{DefaultHubName}"); - }); - } - else - { - app.UseJwtMiddleware(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{DefaultHubName}"); - }); + default: + case HubType.NoAuthentication: + { + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{DefaultHubName}"); + }); + break; + } + case HubType.JwtAuthentication: + { + app.UseJwtMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{DefaultHubName}"); + }); + break; + } + case HubType.CookieAuthentication: + { + app.UseCookieMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{DefaultHubName}"); + }); + break; + } } app.UseForwardedHeaders(); @@ -141,22 +158,38 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app app.UseRouting(); - if (hubType == HubType.NoAuthentication) + switch (hubType) { - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{hubName.Trim()}"); - }); - } - else - { - app.UseJwtMiddleware(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{hubName.Trim()}"); - }); + default: + case HubType.NoAuthentication: + { + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } + case HubType.JwtAuthentication: + { + app.UseJwtMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } + case HubType.CookieAuthentication: + { + app.UseCookieMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } } app.UseForwardedHeaders(); @@ -183,22 +216,38 @@ public static IApplicationBuilder UseWartMiddleware(this IApplicationBuilder app foreach (var hubName in hubNameList.Distinct()) { - if (hubType == HubType.NoAuthentication) + switch (hubType) { - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{hubName.Trim()}"); - }); - } - else - { - app.UseJwtMiddleware(); - app.UseEndpoints(endpoints => - { - endpoints.MapControllers(); - endpoints.MapHub($"/{hubName.Trim()}"); - }); + default: + case HubType.NoAuthentication: + { + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } + case HubType.JwtAuthentication: + { + app.UseJwtMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } + case HubType.CookieAuthentication: + { + app.UseCookieMiddleware(); + app.UseEndpoints(endpoints => + { + endpoints.MapControllers(); + endpoints.MapHub($"/{hubName.Trim()}"); + }); + break; + } } } diff --git a/src/WART-Core/Middleware/WartServiceCollectionExtension.cs b/src/WART-Core/Middleware/WartServiceCollectionExtension.cs index 52bbb27..4886c4b 100755 --- a/src/WART-Core/Middleware/WartServiceCollectionExtension.cs +++ b/src/WART-Core/Middleware/WartServiceCollectionExtension.cs @@ -7,6 +7,7 @@ using Microsoft.Extensions.Logging; using System; using System.Linq; +using WART_Core.Authentication.Cookie; using WART_Core.Authentication.JWT; using WART_Core.Enum; using WART_Core.Hubs; @@ -70,15 +71,27 @@ public static IServiceCollection AddWartMiddleware(this IServiceCollection servi public static IServiceCollection AddWartMiddleware(this IServiceCollection services, HubType hubType, string tokenKey = "") { // Check the hub type to determine if authentication is required. - if (hubType == HubType.NoAuthentication) + switch(hubType) { - // If no authentication is required, configure WART middleware without authentication. - services.AddWartMiddleware(); - } - else - { - // If authentication is required, configure JWT middleware for authentication. - services.AddJwtMiddleware(tokenKey); + default: + case HubType.NoAuthentication: + { + // If no authentication is required, configure WART middleware without authentication. + services.AddWartMiddleware(); + break; + } + case HubType.JwtAuthentication: + { + // If authentication is required, configure JWT middleware for authentication. + services.AddJwtMiddleware(tokenKey); + break; + } + case HubType.CookieAuthentication: + { + // If authentication is required, configure Cookie middleware for authentication. + services.AddCookieMiddleware(); + break; + } } return services; diff --git a/src/WART-WebApiRealTime/Controllers/TestCookieController.cs b/src/WART-WebApiRealTime/Controllers/TestCookieController.cs new file mode 100644 index 0000000..a632762 --- /dev/null +++ b/src/WART-WebApiRealTime/Controllers/TestCookieController.cs @@ -0,0 +1,126 @@ +// (c) 2025 Francesco Del Re +// This code is licensed under MIT license (see LICENSE.txt for details) +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Authentication; +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Logging; +using WART_Api.Entity; +using WART_Core.Controllers; +using WART_Core.Filters; +using WART_Core.Hubs; + +namespace WART_Api.Controllers +{ + /// + /// A simple controller example extended by the WartController with Cookie authentication. + /// + [ApiController] + [Route("api/[controller]")] + public class TestCookieController : WartControllerCookie + { + private static List Items = new List + { + new TestEntity { Id = 1, Param = "Item1" }, + new TestEntity { Id = 2, Param = "Item2" }, + new TestEntity { Id = 3, Param = "Item3" } + }; + + public TestCookieController(IHubContext messageHubContext, ILogger logger) : base(messageHubContext, logger) + { + } + + // Login endpoint: issues authentication cookie using "WartCookieAuth" scheme + [HttpPost("login")] + [ExcludeWart] // Exclude from event interception if using custom filters + public async Task Login([FromForm] string username, [FromForm] string password) + { + if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) + { + var claims = new List + { + new Claim(ClaimTypes.Name, username) + }; + + var identity = new ClaimsIdentity(claims, "WartCookieAuth"); + var principal = new ClaimsPrincipal(identity); + + await HttpContext.SignInAsync("WartCookieAuth", principal, new AuthenticationProperties + { + IsPersistent = true, + ExpiresUtc = DateTime.UtcNow.AddHours(1) + }); + + return Ok("Login successful."); + } + + return Unauthorized("Invalid credentials."); + } + + [HttpGet] + public IEnumerable Get() + { + return Items; + } + + [HttpGet("{id}")] + [ExcludeWart] + public ActionResult Get(int id) + { + var item = Items.FirstOrDefault(x => x.Id == id); + if (item == null) + { + return NotFound(); + } + return item; + } + + [HttpPost] + [GroupWart("SampleGroupName")] + public ActionResult Post([FromBody] TestEntity entity) + { + Items.Add(entity); + return entity; + } + + [HttpPatch("{id}")] + public ActionResult Patch(int id, [FromBody] TestEntity entity) + { + var item = Items.FirstOrDefault(x => x.Id == id); + if (item == null) + { + return NotFound(); + } + item.Param = entity.Param; + return item; + } + + [HttpPut("{id}")] + public ActionResult Put(int id, [FromBody] TestEntity entity) + { + var item = Items.FirstOrDefault(x => x.Id == id); + if (item == null) + { + return NotFound(); + } + item.Param = entity.Param; + return item; + } + + [HttpDelete("{id}")] + public ActionResult Delete(int id) + { + var item = Items.FirstOrDefault(x => x.Id == id); + if (item == null) + { + return NotFound(); + } + Items.Remove(item); + return item; + } + } +} \ No newline at end of file diff --git a/src/WART-WebApiRealTime/Startup.cs b/src/WART-WebApiRealTime/Startup.cs index 1c0e1bc..8a84660 100755 --- a/src/WART-WebApiRealTime/Startup.cs +++ b/src/WART-WebApiRealTime/Startup.cs @@ -28,10 +28,15 @@ public void ConfigureServices(IServiceCollection services) services.AddControllers(); // add the Wart middleware service extension - // default without authentication + + // default without authentication //services.AddWartMiddleware(); - // with authentication - services.AddWartMiddleware(hubType: HubType.JwtAuthentication, tokenKey: "dn3341fmcscscwe28419brhwbwgbss4t"); + + // with JWT authentication + //services.AddWartMiddleware(hubType: HubType.JwtAuthentication, tokenKey: "dn3341fmcscscwe28419brhwbwgbss4t"); + + // with Cookie authentication + services.AddWartMiddleware(hubType: HubType.CookieAuthentication); // Register the Swagger generator, defining 1 or more Swagger documents services.AddSwaggerGen(c => @@ -69,8 +74,11 @@ public void Configure(IApplicationBuilder app, IWebHostEnvironment env) // default without authentication //app.UseWartMiddleware(); - // with authentication - app.UseWartMiddleware(HubType.JwtAuthentication); + // with JWT authentication + //app.UseWartMiddleware(HubType.JwtAuthentication); + + // with Cookie authentication + app.UseWartMiddleware(HubType.CookieAuthentication); // multiple hub with authentication //var hubNameList = new List