83 lines
2.9 KiB
C#
83 lines
2.9 KiB
C#
using System;
|
|
using System.IdentityModel.Tokens.Jwt;
|
|
using System.Security.Claims;
|
|
using System.Security.Principal;
|
|
using System.Threading.Tasks;
|
|
using Microsoft.Extensions.Options;
|
|
using static BlueWest.WebApi.Context.Users.Constants;
|
|
|
|
namespace BlueWest.WebApi.Context.Users;
|
|
|
|
public class JwtFactory : IJwtFactory
|
|
{
|
|
private readonly IJwtTokenHandler _jwtTokenHandler;
|
|
private readonly JwtIssuerOptions _jwtOptions;
|
|
|
|
public JwtFactory(IJwtTokenHandler jwtTokenHandler, IOptions<JwtIssuerOptions> jwtOptions)
|
|
{
|
|
_jwtTokenHandler = jwtTokenHandler;
|
|
_jwtOptions = jwtOptions.Value;
|
|
ThrowIfInvalidOptions(_jwtOptions);
|
|
}
|
|
|
|
public async Task<AccessToken> GenerateEncodedToken(string id, string userName)
|
|
{
|
|
var identity = GenerateClaimsIdentity(id, userName);
|
|
|
|
var claims = new[]
|
|
{
|
|
new Claim(JwtRegisteredClaimNames.Sub, userName),
|
|
new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
|
|
new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(_jwtOptions.IssuedAt).ToString(),
|
|
ClaimValueTypes.Integer64),
|
|
identity.FindFirst(JwtClaimIdentifiers.Rol),
|
|
identity.FindFirst(JwtClaimIdentifiers.Id)
|
|
};
|
|
|
|
// Create the JWT security token and encode it.
|
|
var jwt = new JwtSecurityToken(
|
|
_jwtOptions.Issuer,
|
|
_jwtOptions.Audience,
|
|
claims,
|
|
_jwtOptions.NotBefore,
|
|
_jwtOptions.Expiration,
|
|
_jwtOptions.SigningCredentials);
|
|
|
|
return new AccessToken(_jwtTokenHandler.WriteToken(jwt), (int)_jwtOptions.ValidFor.TotalSeconds);
|
|
}
|
|
|
|
private static ClaimsIdentity GenerateClaimsIdentity(string id, string userName)
|
|
{
|
|
return new ClaimsIdentity(new GenericIdentity(userName, "Token"), new[]
|
|
{
|
|
new Claim(JwtClaimIdentifiers.Id, id),
|
|
new Claim(JwtClaimIdentifiers.Rol, JwtClaims.ApiAccess)
|
|
});
|
|
}
|
|
|
|
/// <returns>Date converted to seconds since Unix epoch (Jan 1, 1970, midnight UTC).</returns>
|
|
private static long ToUnixEpochDate(DateTime date)
|
|
=> (long)Math.Round((date.ToUniversalTime() -
|
|
new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
|
|
.TotalSeconds);
|
|
|
|
private static void ThrowIfInvalidOptions(JwtIssuerOptions options)
|
|
{
|
|
if (options == null) throw new ArgumentNullException(nameof(options));
|
|
|
|
if (options.ValidFor <= TimeSpan.Zero)
|
|
{
|
|
throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor));
|
|
}
|
|
|
|
if (options.SigningCredentials == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials));
|
|
}
|
|
|
|
if (options.JtiGenerator == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator));
|
|
}
|
|
}
|
|
} |