This repository has been archived by the owner on Nov 19, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 70
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add worker sample with DI alternatives
- Loading branch information
1 parent
e529ab7
commit e8a6f62
Showing
10 changed files
with
414 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Threading.Tasks; | ||
using Duende.AccessTokenManagement; | ||
using IdentityModel; | ||
using IdentityModel.Client; | ||
using Microsoft.Extensions.Options; | ||
using Microsoft.IdentityModel.JsonWebTokens; | ||
using Microsoft.IdentityModel.Tokens; | ||
|
||
namespace WorkerService; | ||
|
||
public class ClientAssertionService : IClientAssertionService | ||
{ | ||
private readonly IOptionsSnapshot<ClientCredentialsClient> _options; | ||
|
||
private static string RsaKey = | ||
"{'d':'GmiaucNIzdvsEzGjZjd43SDToy1pz-Ph-shsOUXXh-dsYNGftITGerp8bO1iryXh_zUEo8oDK3r1y4klTonQ6bLsWw4ogjLPmL3yiqsoSjJa1G2Ymh_RY_sFZLLXAcrmpbzdWIAkgkHSZTaliL6g57vA7gxvd8L4s82wgGer_JmURI0ECbaCg98JVS0Srtf9GeTRHoX4foLWKc1Vq6NHthzqRMLZe-aRBNU9IMvXNd7kCcIbHCM3GTD_8cFj135nBPP2HOgC_ZXI1txsEf-djqJj8W5vaM7ViKU28IDv1gZGH3CatoysYx6jv1XJVvb2PH8RbFKbJmeyUm3Wvo-rgQ','dp':'YNjVBTCIwZD65WCht5ve06vnBLP_Po1NtL_4lkholmPzJ5jbLYBU8f5foNp8DVJBdFQW7wcLmx85-NC5Pl1ZeyA-Ecbw4fDraa5Z4wUKlF0LT6VV79rfOF19y8kwf6MigyrDqMLcH_CRnRGg5NfDsijlZXffINGuxg6wWzhiqqE','dq':'LfMDQbvTFNngkZjKkN2CBh5_MBG6Yrmfy4kWA8IC2HQqID5FtreiY2MTAwoDcoINfh3S5CItpuq94tlB2t-VUv8wunhbngHiB5xUprwGAAnwJ3DL39D2m43i_3YP-UO1TgZQUAOh7Jrd4foatpatTvBtY3F1DrCrUKE5Kkn770M','e':'AQAB','kid':'ZzAjSnraU3bkWGnnAqLapYGpTyNfLbjbzgAPbbW2GEA','kty':'RSA','n':'wWwQFtSzeRjjerpEM5Rmqz_DsNaZ9S1Bw6UbZkDLowuuTCjBWUax0vBMMxdy6XjEEK4Oq9lKMvx9JzjmeJf1knoqSNrox3Ka0rnxXpNAz6sATvme8p9mTXyp0cX4lF4U2J54xa2_S9NF5QWvpXvBeC4GAJx7QaSw4zrUkrc6XyaAiFnLhQEwKJCwUw4NOqIuYvYp_IXhw-5Ti_icDlZS-282PcccnBeOcX7vc21pozibIdmZJKqXNsL1Ibx5Nkx1F1jLnekJAmdaACDjYRLL_6n3W4wUp19UvzB1lGtXcJKLLkqB6YDiZNu16OSiSprfmrRXvYmvD8m6Fnl5aetgKw','p':'7enorp9Pm9XSHaCvQyENcvdU99WCPbnp8vc0KnY_0g9UdX4ZDH07JwKu6DQEwfmUA1qspC-e_KFWTl3x0-I2eJRnHjLOoLrTjrVSBRhBMGEH5PvtZTTThnIY2LReH-6EhceGvcsJ_MhNDUEZLykiH1OnKhmRuvSdhi8oiETqtPE','q':'0CBLGi_kRPLqI8yfVkpBbA9zkCAshgrWWn9hsq6a7Zl2LcLaLBRUxH0q1jWnXgeJh9o5v8sYGXwhbrmuypw7kJ0uA3OgEzSsNvX5Ay3R9sNel-3Mqm8Me5OfWWvmTEBOci8RwHstdR-7b9ZT13jk-dsZI7OlV_uBja1ny9Nz9ts','qi':'pG6J4dcUDrDndMxa-ee1yG4KjZqqyCQcmPAfqklI2LmnpRIjcK78scclvpboI3JQyg6RCEKVMwAhVtQM6cBcIO3JrHgqeYDblp5wXHjto70HVW6Z8kBruNx1AH9E8LzNvSRL-JVTFzBkJuNgzKQfD0G77tQRgJ-Ri7qu3_9o1M4'}"; | ||
|
||
private static SigningCredentials Credential = new (new JsonWebKey(RsaKey), "RS256"); | ||
|
||
public ClientAssertionService(IOptionsSnapshot<ClientCredentialsClient> options) | ||
{ | ||
_options = options; | ||
} | ||
|
||
public Task<ClientAssertion?> GetClientAssertionAsync(string clientName, ClientCredentialsTokenRequestParameters? parameters = null) | ||
{ | ||
if (clientName == "demo.jwt") | ||
{ | ||
var options = _options.Get(clientName); | ||
|
||
var descriptor = new SecurityTokenDescriptor | ||
{ | ||
Issuer = options.ClientId, | ||
Audience = options.TokenEndpoint, | ||
Expires = DateTime.UtcNow.AddMinutes(1), | ||
SigningCredentials = Credential, | ||
|
||
Claims = new Dictionary<string, object> | ||
{ | ||
{ JwtClaimTypes.JwtId, Guid.NewGuid().ToString() }, | ||
{ JwtClaimTypes.Subject, options.ClientId! }, | ||
{ JwtClaimTypes.IssuedAt, DateTime.UtcNow.ToEpochTime() } | ||
} | ||
}; | ||
|
||
var handler = new JsonWebTokenHandler(); | ||
var jwt = handler.CreateToken(descriptor); | ||
|
||
return Task.FromResult<ClientAssertion?>(new ClientAssertion | ||
{ | ||
Type = OidcConstants.ClientAssertionTypes.JwtBearer, | ||
Value = jwt | ||
}); | ||
} | ||
|
||
return Task.FromResult<ClientAssertion?>(null); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
samples/WorkerDI/ClientCredentialsClientConfigureOptions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using Duende.AccessTokenManagement; | ||
using IdentityModel.Client; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace WorkerService; | ||
|
||
public class ClientCredentialsClientConfigureOptions : IConfigureNamedOptions<ClientCredentialsClient> | ||
{ | ||
private readonly DiscoveryCache _cache; | ||
|
||
public ClientCredentialsClientConfigureOptions(DiscoveryCache cache) | ||
{ | ||
_cache = cache; | ||
} | ||
|
||
public void Configure(ClientCredentialsClient options) | ||
{ | ||
throw new System.NotImplementedException(); | ||
} | ||
|
||
public void Configure(string name, ClientCredentialsClient options) | ||
{ | ||
if (name == "demo.jwt") | ||
{ | ||
var disco = _cache.GetAsync().GetAwaiter().GetResult(); | ||
|
||
options.TokenEndpoint = disco.TokenEndpoint; | ||
options.ClientId = "m2m.short.jwt"; | ||
options.Scope = "api"; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Hosting; | ||
using Serilog; | ||
using System; | ||
using Duende.AccessTokenManagement; | ||
using IdentityModel.Client; | ||
using Microsoft.Extensions.Options; | ||
using Serilog.Sinks.SystemConsole.Themes; | ||
|
||
namespace WorkerService; | ||
|
||
public class Program | ||
{ | ||
public static void Main(string[] args) | ||
{ | ||
Log.Logger = new LoggerConfiguration() | ||
.MinimumLevel.Debug() | ||
.WriteTo.Console(theme: AnsiConsoleTheme.Code) | ||
.CreateLogger(); | ||
|
||
CreateHostBuilder(args).Build().Run(); | ||
} | ||
|
||
public static IHostBuilder CreateHostBuilder(string[] args) | ||
{ | ||
var host = Host.CreateDefaultBuilder(args) | ||
.UseSerilog() | ||
|
||
.ConfigureServices((services) => | ||
{ | ||
services.AddDistributedMemoryCache(); | ||
|
||
services.AddClientCredentialsTokenManagement(); | ||
services.AddSingleton(new DiscoveryCache("https://demo.duendesoftware.com")); | ||
services.AddSingleton<IConfigureOptions<ClientCredentialsClient>, ClientCredentialsClientConfigureOptions>(); | ||
|
||
// alternative way to add a client | ||
services.Configure<ClientCredentialsClient>("demo", client => | ||
{ | ||
client.TokenEndpoint = "https://demo.duendesoftware.com/connect/token"; | ||
|
||
client.ClientId = "m2m.short"; | ||
client.ClientSecret = "secret"; | ||
|
||
client.Scope = "api"; | ||
}); | ||
|
||
services.AddClientCredentialsHttpClient("client", "demo", client => | ||
{ | ||
client.BaseAddress = new Uri("https://demo.duendesoftware.com/api/"); | ||
}); | ||
|
||
services.AddHttpClient<TypedClient>(client => | ||
{ | ||
client.BaseAddress = new Uri("https://demo.duendesoftware.com/api/"); | ||
}) | ||
.AddClientCredentialsTokenHandler("demo"); | ||
|
||
services.AddTransient<IClientAssertionService, ClientAssertionService>(); | ||
|
||
//services.AddHostedService<WorkerManual>(); | ||
services.AddHostedService<WorkerManualJwt>(); | ||
//services.AddHostedService<WorkerHttpClient>(); | ||
//services.AddHostedService<WorkerTypedHttpClient>(); | ||
}); | ||
|
||
return host; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
||
using System.Net.Http; | ||
using System.Threading.Tasks; | ||
|
||
namespace WorkerService; | ||
|
||
public class TypedClient | ||
{ | ||
private readonly HttpClient _client; | ||
|
||
public TypedClient(HttpClient client) | ||
{ | ||
_client = client; | ||
} | ||
|
||
public async Task<string> CallApi() | ||
{ | ||
return await _client.GetStringAsync("test"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Worker"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>net6.0</TargetFramework> | ||
<Nullable>enable</Nullable> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Serilog.AspNetCore" Version="6.0.0" /> | ||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.21.0" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\src\Duende.AccessTokenManagement\Duende.AccessTokenManagement.csproj" /> | ||
</ItemGroup> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace WorkerService; | ||
|
||
public class WorkerHttpClient : BackgroundService | ||
{ | ||
private readonly ILogger<WorkerHttpClient> _logger; | ||
private readonly IHttpClientFactory _clientFactory; | ||
|
||
public WorkerHttpClient(ILogger<WorkerHttpClient> logger, IHttpClientFactory factory) | ||
{ | ||
_logger = logger; | ||
_clientFactory = factory; | ||
} | ||
|
||
protected override async Task ExecuteAsync(CancellationToken stoppingToken) | ||
{ | ||
await Task.Delay(2000, stoppingToken); | ||
|
||
while (!stoppingToken.IsCancellationRequested) | ||
{ | ||
Console.WriteLine("\n\n"); | ||
_logger.LogInformation("WorkerHttpClient running at: {time}", DateTimeOffset.Now); | ||
|
||
var client = _clientFactory.CreateClient("client"); | ||
var response = await client.GetAsync("test", stoppingToken); | ||
|
||
if (response.IsSuccessStatusCode) | ||
{ | ||
var content = await response.Content.ReadAsStringAsync(stoppingToken); | ||
_logger.LogInformation("API response: {response}", content); | ||
} | ||
else | ||
{ | ||
_logger.LogError("API returned: {statusCode}", response.StatusCode); | ||
} | ||
|
||
await Task.Delay(5000, stoppingToken); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
// Copyright (c) Brock Allen & Dominick Baier. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. | ||
|
||
using Microsoft.Extensions.Hosting; | ||
using Microsoft.Extensions.Logging; | ||
using System; | ||
using System.Net.Http; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Duende.AccessTokenManagement; | ||
using IdentityModel.Client; | ||
|
||
namespace WorkerService; | ||
|
||
public class WorkerManual : BackgroundService | ||
{ | ||
private readonly ILogger<WorkerManual> _logger; | ||
private readonly IHttpClientFactory _clientFactory; | ||
private readonly IClientCredentialsTokenManagementService _tokenManagementService; | ||
|
||
public WorkerManual(ILogger<WorkerManual> logger, IHttpClientFactory factory, IClientCredentialsTokenManagementService tokenManagementService) | ||
{ | ||
_logger = logger; | ||
_clientFactory = factory; | ||
_tokenManagementService = tokenManagementService; | ||
} | ||
|
||
protected override async Task ExecuteAsync(CancellationToken stoppingToken) | ||
{ | ||
await Task.Delay(3000, stoppingToken); | ||
|
||
while (!stoppingToken.IsCancellationRequested) | ||
{ | ||
Console.WriteLine("\n\n"); | ||
_logger.LogInformation("WorkerManual running at: {time}", DateTimeOffset.Now); | ||
|
||
var client = _clientFactory.CreateClient(); | ||
client.BaseAddress = new Uri("https://demo.duendesoftware.com/api/"); | ||
|
||
var token = await _tokenManagementService.GetAccessTokenAsync("demo"); | ||
client.SetBearerToken(token.AccessToken); | ||
|
||
var response = await client.GetAsync("test", stoppingToken); | ||
|
||
if (response.IsSuccessStatusCode) | ||
{ | ||
var content = await response.Content.ReadAsStringAsync(stoppingToken); | ||
_logger.LogInformation("API response: {response}", content); | ||
} | ||
else | ||
{ | ||
_logger.LogError("API returned: {statusCode}", response.StatusCode); | ||
} | ||
|
||
await Task.Delay(6000, stoppingToken); | ||
} | ||
} | ||
} |
Oops, something went wrong.