Skip to content

Commit

Permalink
Made Decoder, Serializer to accept Type. Added PayloadType to JwtAuth…
Browse files Browse the repository at this point in the history
…enticationOptions. (#375)

* Bumped version of JWT to 10.0.0-beta1
* Bumped version of JWT.Extensions.AspNetCore to 9.0.0-beta1
* Made methods on Decoder, Serializer non-generic, to accept Type rather than <T>
* Added PayloadType to JwtAuthenticationOptions
* Made DefaultIdentityFactory to use PayloadType rather than always Dictionary<string, string>
  • Loading branch information
abatishchev authored Feb 13, 2022
1 parent d4dee86 commit d7d76fb
Show file tree
Hide file tree
Showing 11 changed files with 227 additions and 56 deletions.
19 changes: 17 additions & 2 deletions src/JWT.Extensions.AspNetCore/Factories/DefaultIdentityFactory.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
Expand All @@ -11,7 +12,21 @@ public sealed class DefaultIdentityFactory : IIdentityFactory
private readonly IOptionsMonitor<JwtAuthenticationOptions> _options;

public DefaultIdentityFactory(IOptionsMonitor<JwtAuthenticationOptions> options) =>
_options = options;
_options = options ?? throw new ArgumentNullException(nameof(options));

IIdentity IIdentityFactory.CreateIdentity(Type type, object payload)
{
if (type is null)
throw new ArgumentNullException(nameof(type));
if (payload is null)
throw new ArgumentException(nameof(payload));

Type targetType = typeof(IDictionary<string, string>);
if (!targetType.IsAssignableFrom(type))
throw new ArgumentOutOfRangeException(nameof(type), $"Type {type} is not assignable to {targetType}");

return CreateIdentity((IDictionary<string, string>)payload);
}

/// <summary>
/// Creates user's identity from user's claims
Expand Down
16 changes: 14 additions & 2 deletions src/JWT.Extensions.AspNetCore/Factories/IIdentityFactory.cs
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
using System.Collections.Generic;
using System;
using System.Security.Principal;

namespace JWT.Extensions.AspNetCore.Factories
{
public interface IIdentityFactory
{
IIdentity CreateIdentity(IDictionary<string, string> payload);
/// <summary>
/// Creates <see cref="IIdentity" /> from the payload of the specified type.
/// </summary>
IIdentity CreateIdentity(Type type, object payload);
}

/// <summary>
/// Extension methods for <seealso cref="IIdentityFactory" />
///</summary>
public static class IdentityFactoryExtensions
{
public static IIdentity CreateIdentity<T>(this IIdentityFactory factory, T payload) =>
factory.CreateIdentity(typeof(T), payload);
}
}
10 changes: 5 additions & 5 deletions src/JWT.Extensions.AspNetCore/JWT.Extensions.AspNetCore.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
Expand All @@ -11,9 +11,9 @@
<Authors>Alexander Batishchev</Authors>
<PackageTags>jwt;json;asp.net;asp.net core;.net core;authorization</PackageTags>
<PackageLicense>MIT</PackageLicense>
<Version>8.2.0</Version>
<FileVersion>8.0.0.0</FileVersion>
<AssemblyVersion>7.0.0.0</AssemblyVersion>
<Version>9.0.0-beta1</Version>
<FileVersion>9.0.0.0</FileVersion>
<AssemblyVersion>9.0.0.0</AssemblyVersion>
<RootNamespace>JWT.Extensions.AspNetCore</RootNamespace>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
Expand Down Expand Up @@ -43,4 +43,4 @@
<ProjectReference Include="..\JWT\JWT.csproj" />
</ItemGroup>

</Project>
</Project>
5 changes: 2 additions & 3 deletions src/JWT.Extensions.AspNetCore/JwtAuthenticationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Encodings.Web;
using System.Threading.Tasks;
Expand Down Expand Up @@ -117,8 +116,8 @@ private AuthenticateResult GetAuthenticationResult(string header)

try
{
var payload = _jwtDecoder.DecodeToObject<Dictionary<string, string>>(token, this.Options.Keys, this.Options.VerifySignature);
var identity = _identityFactory.CreateIdentity(payload);
object payload = _jwtDecoder.DecodeToObject(this.Options.PayloadType, token, this.Options.Keys, this.Options.VerifySignature);
var identity = _identityFactory.CreateIdentity(this.Options.PayloadType, payload);
var ticket = _ticketFactory.CreateTicket(identity, this.Scheme);

return this.Options.OnSuccessfulTicket(this.Logger, ticket);
Expand Down
13 changes: 10 additions & 3 deletions src/JWT.Extensions.AspNetCore/JwtAuthenticationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using System;
using System;
using System.Collections.Generic;
using System.Security.Principal;
using JWT.Internal;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.Extensions.Logging;

Expand Down Expand Up @@ -70,5 +69,13 @@ public class JwtAuthenticationOptions : AuthenticationSchemeOptions
/// The default value is <c>true</c>.
/// </remarks>
public bool IncludeAuthenticationScheme { get; set; } = true;

/// <summary>
/// Type of the payload to deserialize to.
/// </summary>
/// <remarks>
/// The default value is <see cref="Dictionary{String, String}" />.
/// </remarks>
public Type PayloadType { get; set; } = typeof(Dictionary<string, string>);
}
}
34 changes: 26 additions & 8 deletions src/JWT/IJsonSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
namespace JWT
using System;

namespace JWT
{
/// <summary>
/// Provides JSON Serialize and Deserialize. Allows custom serializers used.
/// Provides JSON Serialize and Deserialize. Allows custom serializers used.
/// </summary>
public interface IJsonSerializer
{
/// <summary>
/// Serialize an object to JSON string
/// Serializes an object to a JSON string.
/// </summary>
/// <param name="obj">object</param>
/// <param name="obj">The object to serialize.</param>
/// <returns>JSON string</returns>
string Serialize(object obj);

/// <summary>
/// Deserialize a JSON string to typed object.
/// Deserializes a JSON string to an object of specified type.
/// </summary>
/// <param name="type">The type of the object to deserialize to.</param>
/// <param name="json">The JSON string deserialize.</param>
/// <returns>Strongly-typed object.</returns>
object Deserialize(Type type, string json);
}

/// <summary>
/// Extension methods for <seealso cref="IJsonSerializer" />
///</summary>
public static class JsonSerializerExtensions
{
/// <summary>
/// Deserializes a JSON string to an object of specified type.
/// </summary>
/// <typeparam name="T">type of object</typeparam>
/// <typeparam name="T">The type of the object to deserialize to.</typeparam>
/// <param name="jsonSerializer">The JSON serializer instance.</param>
/// <param name="json">JSON string</param>
/// <returns>Strongly-typed object</returns>
T Deserialize<T>(string json);
/// <returns>Strongly-typed object.</returns>
public static T Deserialize<T>(this IJsonSerializer jsonSerializer, string json) =>
(T)jsonSerializer.Deserialize(typeof(T), json);
}
}
140 changes: 124 additions & 16 deletions src/JWT/IJwtDecoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,35 +55,35 @@ public interface IJwtDecoder

#endregion

#region T DecodeToObject<T>
#region DecodeToObject

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="type">The type to deserialize to.</param>
/// <param name="jwt">The JWT</param>
/// <returns>An object representing the payload</returns>
T DecodeToObject<T>(JwtParts jwt);
object DecodeToObject(Type type, JwtParts jwt);

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="type">The type to deserialize to.</param>
/// <param name="jwt">The JWT</param>
/// <param name="key">The key that was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
T DecodeToObject<T>(JwtParts jwt, byte[] key, bool verify);
object DecodeToObject(Type type, JwtParts jwt, byte[] key, bool verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="type">The type to deserialize to.</param>
/// <param name="jwt">The JWT</param>
/// <param name="keys">The keys which one of them was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
T DecodeToObject<T>(JwtParts jwt, byte[][] keys, bool verify);
object DecodeToObject(Type type, JwtParts jwt, byte[][] keys, bool verify);

#endregion
}
Expand Down Expand Up @@ -178,36 +178,42 @@ public static string Decode(this IJwtDecoder decoder, string token, string key,
/// <exception cref="ArgumentException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static string Decode(this IJwtDecoder decoder, string token, string[] keys, bool verify) =>
decoder.Decode(token, GetBytes(keys), verify);
decoder.Decode(token, keys is object ? GetBytes(keys) : null, verify);

#endregion

#region DecodeToObject

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// Given a JWT, decodes it and return the payload as a dictionary.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="decoder">The decoder instance</param>
/// <param name="token">The JWT</param>
/// <returns>An object representing the payload</returns>
public static T DecodeToObject<T>(this IJwtDecoder decoder, string token) =>
decoder.DecodeToObject<T>(new JwtParts(token));
public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decoder, string token) =>
decoder.DecodeToObject<Dictionary<string, object>>(token);

/// <summary>
/// Given a JWT, decodes it and return the payload as a dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="token">The JWT</param>
/// <param name="key">The key that was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decoder, string token) =>
decoder.DecodeToObject<Dictionary<string, object>>(token);

public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decoder, string token, string key, bool verify) =>
decoder.DecodeToObject(token, GetBytes(key), verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as a dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="token">The JWT</param>
/// <param name="keys">The keys provided which one of them was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decoder, string token, string[] keys, bool verify) =>
decoder.DecodeToObject(token, GetBytes(keys), verify);
decoder.DecodeToObject(token, keys is object ? GetBytes(keys) : null, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as a dictionary.
Expand Down Expand Up @@ -237,10 +243,112 @@ public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decode
public static IDictionary<string, object> DecodeToObject(this IJwtDecoder decoder, string token, byte[][] keys, bool verify) =>
decoder.DecodeToObject<Dictionary<string, object>>(new JwtParts(token), keys, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as a dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="type">The type to deserialize to.</param>
/// <param name="token">The JWT</param>
/// <param name="key">The key that was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
/// <exception cref = "ArgumentException" />
/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="InvalidTokenPartsException" />
public static object DecodeToObject(this IJwtDecoder decoder, Type type, string token, byte[] key, bool verify) =>
decoder.DecodeToObject(type, new JwtParts(token), key, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as a dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="type">The type to deserialize to.</param>
/// <param name="token">The JWT</param>
/// <param name="keys">The keys that were used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>A string containing the JSON payload</returns>
/// <exception cref="ArgumentException" />
/// <exception cref="ArgumentOutOfRangeException" />
/// <exception cref="InvalidTokenPartsException" />
public static object DecodeToObject(this IJwtDecoder decoder, Type type, string token, byte[][] keys, bool verify) =>
decoder.DecodeToObject(type, new JwtParts(token), keys, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as an dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="type">The type to deserialize to.</param>
/// <param name="token">The JWT</param>
/// <param name="key">The key that was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
/// <exception cref="ArgumentException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static object DecodeToObject(this IJwtDecoder decoder, Type type, string token, string key, bool verify) =>
decoder.DecodeToObject(token, GetBytes(key), verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as an dictionary.
/// </summary>
/// <param name="decoder">The decoder instance</param>
/// <param name="type">The type to deserialize to.</param>
/// <param name="token">The JWT</param>
/// <param name="keys">The key which one of them was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
/// <exception cref="ArgumentException" />
/// <exception cref="ArgumentOutOfRangeException" />
public static object DecodeToObject(this IJwtDecoder decoder, Type type, string token, string[] keys, bool verify) =>
decoder.DecodeToObject(type, token, keys is object ? GetBytes(keys) : null, verify);

#endregion

#region DecodeToObject<T>

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to deserialize to.</typeparam>
/// <param name="decoder">The decoder instance</param>
/// <param name="jwt">The JWT</param>
/// <returns>An object representing the payload</returns>
public static T DecodeToObject<T>(this IJwtDecoder decoder, JwtParts jwt) =>
(T)decoder.DecodeToObject(typeof(T), jwt);

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to deserialize to.</typeparam>
/// <param name="decoder">The decoder instance</param>
/// <param name="jwt">The JWT</param>
/// <param name="key">The key that was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
public static T DecodeToObject<T>(this IJwtDecoder decoder, JwtParts jwt, byte[] key, bool verify) =>
(T)decoder.DecodeToObject(typeof(T), jwt, key, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to deserialize to.</typeparam>
/// <param name="decoder">The decoder instance</param>
/// <param name="jwt">The JWT</param>
/// <param name="keys">The keys which one of them was used to sign the JWT</param>
/// <param name="verify">Whether to verify the signature (default is true)</param>
/// <returns>An object representing the payload</returns>
public static T DecodeToObject<T>(this IJwtDecoder decoder, JwtParts jwt, byte[][] keys, bool verify) =>
(T)decoder.DecodeToObject(typeof(T), jwt, keys, verify);

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
/// <typeparam name="T">The type to return</typeparam>
/// <param name="decoder">The decoder instance</param>
/// <param name="token">The JWT</param>
/// <returns>An object representing the payload</returns>
public static T DecodeToObject<T>(this IJwtDecoder decoder, string token) =>
decoder.DecodeToObject<T>(new JwtParts(token));

/// <summary>
/// Given a JWT, decodes it and return the payload as an object.
/// </summary>
Expand Down
Loading

0 comments on commit d7d76fb

Please sign in to comment.