CodeLiturgy.Dashboard/BlueWest.Api/Users/Jwt/JwtFactory.cs

83 lines
2.9 KiB
C#
Raw Normal View History

2022-09-10 00:33:17 +03:00
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));
}
}
}