Skip to content

Commit

Permalink
Added option to select serializer (#433)
Browse files Browse the repository at this point in the history
* Bumped all versions
* Renamed methods on JwtBuilder
* Added DefaultJsonSerializerFactory
* Added DelegateJsonSerializerFactory
* Updated tests

Co-authored-by: Markus Hartung <[email protected]>
Co-authored-by: Alexander Batishchev <[email protected]>
  • Loading branch information
3 people authored Sep 8, 2022
1 parent b387094 commit 2e2c9c0
Show file tree
Hide file tree
Showing 24 changed files with 250 additions and 98 deletions.
8 changes: 1 addition & 7 deletions src/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,8 @@
<Choose>
<When Condition="'$(TargetFramework)' == 'net462' OR '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'net6.0'">
<PropertyGroup>
<DefineConstants>$(DefineConstants);SYSTEM_TEXT_JSON</DefineConstants>
<DefineConstants>$(DefineConstants);MODERN_DOTNET</DefineConstants>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<DefineConstants>$(DefineConstants);NEWTONSOFT_JSON</DefineConstants>
</PropertyGroup>
</Otherwise>
</Choose>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>10.0.0-beta3</Version>
<Version>10.0.0-beta4</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT.Extensions.AspNetCore</RootNamespace>
Expand All @@ -30,8 +30,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Condition="$(DefineConstants.Contains(SYSTEM_TEXT_JSON))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Condition="$(DefineConstants.Contains(NEWTONSOFT_JSON))" Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization;dependenсy injection</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<Version>2.2.0-beta3</Version>
<Version>2.2.0-beta4</Version>
<FileVersion>2.0.0.0</FileVersion>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand All @@ -30,8 +30,8 @@

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.25" />
<PackageReference Condition="$(DefineConstants.Contains(SYSTEM_TEXT_JSON))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Condition="$(DefineConstants.Contains(NEWTONSOFT_JSON))" Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
using System;
using JWT.Algorithms;
using JWT.Internal;
using JWT.Serializers;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;

#if SYSTEM_TEXT_JSON
using JsonSerializer = JWT.Serializers.SystemTextSerializer;
#elif NEWTONSOFT_JSON
using JsonSerializer = JWT.Serializers.JsonNetSerializer;
#endif

namespace JWT
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddJwtEncoder(this IServiceCollection services)
{
services.TryAddSingleton<IJwtEncoder, JwtEncoder>();
services.TryAddSingleton<IJsonSerializer, JsonSerializer>();
services.TryAddSingleton<IJsonSerializerFactory, DefaultJsonSerializerFactory>();
services.TryAddSingleton<IJsonSerializer>(p => p.GetRequiredService<IJsonSerializerFactory>().Create());
services.TryAddSingleton<IBase64UrlEncoder, JwtBase64UrlEncoder>();

return services;
Expand All @@ -44,7 +40,8 @@ private static IServiceCollection AddJwtEncoder<TFactory>(this IServiceCollectio
public static IServiceCollection AddJwtDecoder(this IServiceCollection services)
{
services.TryAddSingleton<IJwtDecoder, JwtDecoder>();
services.TryAddSingleton<IJsonSerializer, JsonSerializer>();
services.TryAddSingleton<IJsonSerializerFactory, DefaultJsonSerializerFactory>();
services.TryAddSingleton<IJsonSerializer>(p => p.GetRequiredService<IJsonSerializerFactory>().Create());
services.TryAddSingleton<IJwtValidator, JwtValidator>();
services.TryAddSingleton<IBase64UrlEncoder, JwtBase64UrlEncoder>();
services.TryAddSingleton<IDateTimeProvider, UtcDatetimeProvider>();
Expand All @@ -60,4 +57,4 @@ public static IServiceCollection AddJwtDecoder<TFactory>(this IServiceCollection
return services.AddJwtDecoder();
}
}
}
}
7 changes: 3 additions & 4 deletions src/JWT/Algorithms/DelegateAlgorithmFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,15 @@ public DelegateAlgorithmFactory(Func<IJwtAlgorithm> algFactory) =>
/// Creates an instance of <see cref="DelegateAlgorithmFactory" /> with supplied algorithm.
/// </summary>
/// <exception cref="ArgumentNullException" />
public DelegateAlgorithmFactory(IJwtAlgorithm algorithm)
public DelegateAlgorithmFactory(IJwtAlgorithm algorithm) :
this(() => algorithm)
{
if (algorithm is null)
throw new ArgumentNullException(nameof(algorithm));

_algFactory = () => algorithm;
}

/// <inheritdoc />
public IJwtAlgorithm Create(JwtDecoderContext context) =>
_algFactory();
}
}
}
69 changes: 44 additions & 25 deletions src/JWT/Builder/JwtBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
using System.Linq;
using System.Reflection;
using JWT.Algorithms;

using JWT.Serializers;
using static JWT.Internal.EncodingHelper;
using static JWT.Serializers.JsonSerializerFactory;

namespace JWT.Builder
{
Expand All @@ -19,7 +18,8 @@ public sealed class JwtBuilder
private IJwtDecoder _decoder;
private IJwtValidator _validator;

private IJsonSerializer _serializer = CreateSerializer();
private IJsonSerializerFactory _jsonSerializerFactory = new DefaultJsonSerializerFactory();

private IBase64UrlEncoder _urlEncoder = new JwtBase64UrlEncoder();
private IDateTimeProvider _dateTimeProvider = new UtcDateTimeProvider();
private ValidationParameters _valParams = ValidationParameters.Default;
Expand Down Expand Up @@ -75,9 +75,23 @@ public JwtBuilder AddClaim(string name, object value)
/// Sets JWT serializer.
/// </summary>
/// <returns>Current builder instance</returns>
public JwtBuilder WithSerializer(IJsonSerializer serializer)
public JwtBuilder WithJsonSerializer(IJsonSerializer serializer) =>
WithJsonSerializerFactory(new DelegateJsonSerializerFactory(serializer));

/// <summary>
/// Sets JWT serializer.
/// </summary>
/// <returns>Current builder instance</returns>
public JwtBuilder WithJsonSerializer(Func<IJsonSerializer> factory) =>
WithJsonSerializerFactory(new DelegateJsonSerializerFactory(factory));

/// <summary>
/// Sets JWT serializer factory.
/// </summary>
/// <returns>Current builder instance</returns>
public JwtBuilder WithJsonSerializerFactory(IJsonSerializerFactory jsonSerializerFactory)
{
_serializer = serializer;
_jsonSerializerFactory = jsonSerializerFactory;
return this;
}

Expand Down Expand Up @@ -321,55 +335,60 @@ private void TryCreateEncoder()
{
if (_algorithm is null && _algFactory is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtEncoder)}. Call {nameof(WithAlgorithm)}.");
if (_serializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtEncoder)}. Call {nameof(WithSerializer)}");

var jsonSerializer = _jsonSerializerFactory.Create();
if (jsonSerializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtEncoder)}. Call {nameof(WithJsonSerializer)}");
if (_urlEncoder is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtEncoder)}. Call {nameof(WithUrlEncoder)}.");

if (_algorithm is object)
_encoder = new JwtEncoder(_algorithm, _serializer, _urlEncoder);
_encoder = new JwtEncoder(_algorithm, jsonSerializer, _urlEncoder);
else if (_algFactory is object)
_encoder = new JwtEncoder(_algFactory, _serializer, _urlEncoder);
_encoder = new JwtEncoder(_algFactory, jsonSerializer, _urlEncoder);
}

private void TryCreateDecoder()
{
TryCreateValidator();

if (_serializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithSerializer)}.");
var jsonSerializer = _jsonSerializerFactory.Create();
if (jsonSerializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithJsonSerializer)}.");
if (_urlEncoder is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithUrlEncoder)}.");

if (_algorithm is object)
_decoder = new JwtDecoder(_serializer, _validator, _urlEncoder, _algorithm);
_decoder = new JwtDecoder(jsonSerializer, _validator, _urlEncoder, _algorithm);
else if (_algFactory is object)
_decoder = new JwtDecoder(_serializer, _validator, _urlEncoder, _algFactory);
_decoder = new JwtDecoder(jsonSerializer, _validator, _urlEncoder, _algFactory);
else if (!_valParams.ValidateSignature)
_decoder = new JwtDecoder(_serializer, _urlEncoder);
_decoder = new JwtDecoder(jsonSerializer, _urlEncoder);
}

private void TryCreateDecoderForHeader()
{
if (_serializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithSerializer)}.");
var jsonSerializer = _jsonSerializerFactory.Create();
if (jsonSerializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithJsonSerializer)}.");
if (_urlEncoder is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtDecoder)}. Call {nameof(WithUrlEncoder)}.");

_decoder = new JwtDecoder(_serializer, _urlEncoder);
_decoder = new JwtDecoder(jsonSerializer, _urlEncoder);
}

private void TryCreateValidator()
{
if (_validator is object)
return;

if (_serializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtValidator)}. Call {nameof(WithSerializer)}.");
var jsonSerializer = _jsonSerializerFactory.Create();
if (jsonSerializer is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtValidator)}. Call {nameof(WithJsonSerializer)}.");
if (_dateTimeProvider is null)
throw new InvalidOperationException($"Can't instantiate {nameof(JwtValidator)}. Call {nameof(WithDateTimeProvider)}.");

_validator = new JwtValidator(_serializer, _dateTimeProvider, _valParams);
_validator = new JwtValidator(jsonSerializer, _dateTimeProvider, _valParams);
}

private void EnsureCanEncode()
Expand All @@ -382,7 +401,7 @@ private void EnsureCanEncode()
throw new InvalidOperationException(
"Can't encode a token. Check if you have called all of the following methods:" + Environment.NewLine +
$"-{nameof(WithAlgorithm)}" + Environment.NewLine +
$"-{nameof(WithSerializer)}" + Environment.NewLine +
$"-{nameof(WithJsonSerializer)}" + Environment.NewLine +
$"-{nameof(WithUrlEncoder)}.");
}
}
Expand All @@ -396,7 +415,7 @@ private void EnsureCanDecode()
{
throw new InvalidOperationException(
"Can't decode a token. Check if you have called all of the following methods:" + Environment.NewLine +
$"-{nameof(WithSerializer)}" + Environment.NewLine +
$"-{nameof(WithJsonSerializer)}" + Environment.NewLine +
$"-{nameof(WithValidator)}" + Environment.NewLine +
$"-{nameof(WithUrlEncoder)}.");
}
Expand All @@ -411,7 +430,7 @@ private void EnsureCanDecodeHeader()
{
throw new InvalidOperationException(
"Can't decode a token header. Check if you have called all of the following methods:" + Environment.NewLine +
$"-{nameof(WithSerializer)}" + Environment.NewLine +
$"-{nameof(WithJsonSerializer)}" + Environment.NewLine +
$"-{nameof(WithUrlEncoder)}.");
}
}
Expand All @@ -421,7 +440,7 @@ private void EnsureCanDecodeHeader()
/// </summary>
private bool CanEncode() =>
(_algorithm is object || _algFactory is object) &&
_serializer is object &&
_jsonSerializerFactory is object &&
_urlEncoder is object &&
_jwt.Payload is object;

Expand All @@ -444,7 +463,7 @@ private bool CanDecodeHeader()
if (_urlEncoder is null)
return false;

if (_serializer is null)
if (_jsonSerializerFactory is null)
return false;

return true;
Expand Down
4 changes: 2 additions & 2 deletions src/JWT/Builder/JwtHeader.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#if SYSTEM_TEXT_JSON
#if MODERN_DOTNET
using JsonProperty = System.Text.Json.Serialization.JsonPropertyNameAttribute;
#elif NEWTONSOFT_JSON
#else
using Newtonsoft.Json;
#endif

Expand Down
6 changes: 3 additions & 3 deletions src/JWT/JWT.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<Authors>Alexander Batishchev, John Sheehan, Michael Lehenbauer</Authors>
<PackageTags>jwt;json;authorization</PackageTags>
<PackageLicenseExpression>CC0-1.0</PackageLicenseExpression>
<Version>10.0.0-beta6</Version>
<Version>10.0.0-beta7</Version>
<FileVersion>10.0.0.0</FileVersion>
<AssemblyVersion>10.0.0.0</AssemblyVersion>
<RootNamespace>JWT</RootNamespace>
Expand All @@ -38,8 +38,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Condition="$(DefineConstants.Contains(SYSTEM_TEXT_JSON))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Condition="$(DefineConstants.Contains(NEWTONSOFT_JSON))" Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Condition="$(DefineConstants.Contains(MODERN_DOTNET))" Include="System.Text.Json" Version="6.0.4" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.3' OR '$(TargetFramework)' == 'netstandard2.0'">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if SYSTEM_TEXT_JSON
#if MODERN_DOTNET
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down
19 changes: 19 additions & 0 deletions src/JWT/Serializers/DefaultJsonSerializerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
namespace JWT.Serializers
{
public sealed class DefaultJsonSerializerFactory : IJsonSerializerFactory
{
private readonly IJsonSerializer _jsonSerializer;

public DefaultJsonSerializerFactory()
{
#if MODERN_DOTNET
_jsonSerializer = new SystemTextSerializer();
#else
_jsonSerializer = new JsonNetSerializer();
#endif
}

public IJsonSerializer Create() =>
_jsonSerializer;
}
}
29 changes: 29 additions & 0 deletions src/JWT/Serializers/DelegateJsonSerializerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;

namespace JWT.Serializers
{
internal sealed class DelegateJsonSerializerFactory : IJsonSerializerFactory
{
private readonly Func<IJsonSerializer> _factory;

public DelegateJsonSerializerFactory(IJsonSerializer jsonSerializer) :
this(() => jsonSerializer)
{
if (jsonSerializer is null)
throw new ArgumentNullException(nameof(jsonSerializer));
}

public DelegateJsonSerializerFactory(IJsonSerializerFactory factory) :
this(() => factory.Create())
{
if (factory is null)
throw new ArgumentNullException(nameof(factory));
}

public DelegateJsonSerializerFactory(Func<IJsonSerializer> factory) =>
_factory = factory ?? throw new ArgumentNullException(nameof(factory));

public IJsonSerializer Create() =>
_factory();
}
}
7 changes: 7 additions & 0 deletions src/JWT/Serializers/IJsonSerializerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace JWT.Serializers
{
public interface IJsonSerializerFactory
{
IJsonSerializer Create();
}
}
4 changes: 1 addition & 3 deletions src/JWT/Serializers/JsonNetSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#if NEWTONSOFT_JSON
using System;
using System;
using System.IO;
using System.Text;
using Newtonsoft.Json;
Expand Down Expand Up @@ -61,4 +60,3 @@ public object Deserialize(Type type, string json)
}
}
}
#endif
Loading

0 comments on commit 2e2c9c0

Please sign in to comment.