Skip to content
This repository has been archived by the owner on Nov 19, 2024. It is now read-only.

Commit

Permalink
Add worker sample with DI alternatives
Browse files Browse the repository at this point in the history
  • Loading branch information
leastprivilege committed Jul 27, 2022
1 parent e529ab7 commit e8a6f62
Show file tree
Hide file tree
Showing 10 changed files with 414 additions and 0 deletions.
7 changes: 7 additions & 0 deletions Duende.AccessTokenManagement.sln
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BlazorServer", "samples\Bla
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebJarJwt", "samples\WebJarJwt\WebJarJwt.csproj", "{C73469D2-5461-4E65-A1CE-6FE83B0FCA85}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerDI", "samples\WorkerDI\WorkerDI.csproj", "{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -60,6 +62,10 @@ Global
{C73469D2-5461-4E65-A1CE-6FE83B0FCA85}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C73469D2-5461-4E65-A1CE-6FE83B0FCA85}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C73469D2-5461-4E65-A1CE-6FE83B0FCA85}.Release|Any CPU.Build.0 = Release|Any CPU
{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{84AA3924-23EF-4E6B-91E9-6D9F9118AAFF} = {FC05DC37-5F54-4171-97F9-4AC2A64E3E14}
Expand All @@ -69,5 +75,6 @@ Global
{11D9707F-E9AB-47BC-82E0-699AA0C49211} = {0B14DE7B-43BD-4570-B6AB-37EDA32032FF}
{AB15F574-FDF0-4117-9E4F-9D35EEA65125} = {FC05DC37-5F54-4171-97F9-4AC2A64E3E14}
{C73469D2-5461-4E65-A1CE-6FE83B0FCA85} = {FC05DC37-5F54-4171-97F9-4AC2A64E3E14}
{22D7B959-CC06-4CDC-8A13-E51E2A94EEE5} = {FC05DC37-5F54-4171-97F9-4AC2A64E3E14}
EndGlobalSection
EndGlobal
63 changes: 63 additions & 0 deletions samples/WorkerDI/ClientAssertionService.cs
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 samples/WorkerDI/ClientCredentialsClientConfigureOptions.cs
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";
}
}
}
70 changes: 70 additions & 0 deletions samples/WorkerDI/Program.cs
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;
}

}
22 changes: 22 additions & 0 deletions samples/WorkerDI/TypedClient.cs
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");
}
}
16 changes: 16 additions & 0 deletions samples/WorkerDI/WorkerDI.csproj
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>
49 changes: 49 additions & 0 deletions samples/WorkerDI/WorkerHttpClient.cs
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);
}
}
}
58 changes: 58 additions & 0 deletions samples/WorkerDI/WorkerManual.cs
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);
}
}
}
Loading

0 comments on commit e8a6f62

Please sign in to comment.