66
77namespace SimpleAuthentication . JwtBearer ;
88
9- internal class JwtBearerService ( IOptions < JwtBearerSettings > jwtBearerSettingsOptions ) : IJwtBearerService
9+ /// <summary>
10+ /// Default implementation of <see cref="IJwtBearerService"/> that provides JWT Bearer token generation and validation.
11+ /// </summary>
12+ /// <param name="jwtBearerSettingsOptions">The JWT Bearer settings.</param>
13+ public class JwtBearerService ( IOptions < JwtBearerSettings > jwtBearerSettingsOptions ) : IJwtBearerService
1014{
11- private readonly JwtBearerSettings jwtBearerSettings = jwtBearerSettingsOptions . Value ;
15+ /// <summary>
16+ /// Gets the JWT Bearer settings used by this service.
17+ /// </summary>
18+ protected JwtBearerSettings JwtBearerSettings { get ; } = jwtBearerSettingsOptions ? . Value ?? throw new ArgumentNullException ( nameof ( jwtBearerSettingsOptions ) ) ;
1219
13- public Task < string > CreateTokenAsync ( string userName , IList < Claim > ? claims = null , string ? issuer = null , string ? audience = null , DateTime ? absoluteExpiration = null )
20+ /// <inheritdoc />
21+ public virtual Task < string > CreateTokenAsync ( string userName , IList < Claim > ? claims = null , string ? issuer = null , string ? audience = null , DateTime ? absoluteExpiration = null )
1422 {
23+ var now = DateTime . UtcNow ;
24+
25+ if ( absoluteExpiration . HasValue && absoluteExpiration . Value < now )
26+ {
27+ throw new ArgumentException ( "The expiration date must be greater than or equal to the current date and time." , nameof ( absoluteExpiration ) ) ;
28+ }
29+
1530 claims ??= [ ] ;
16- claims . Update ( jwtBearerSettings . NameClaimType , userName ) ;
31+ claims . Update ( JwtBearerSettings . NameClaimType , userName ) ;
1732 claims . Update ( JwtRegisteredClaimNames . Jti , Guid . NewGuid ( ) . ToString ( ) ) ;
1833
19- var now = DateTime . UtcNow ;
20-
2134 var securityTokenDescriptor = new SecurityTokenDescriptor ( )
2235 {
23- Subject = new ClaimsIdentity ( claims , jwtBearerSettings . SchemeName , jwtBearerSettings . NameClaimType , jwtBearerSettings . RoleClaimType ) ,
24- Issuer = issuer ?? jwtBearerSettings . Issuers ? . FirstOrDefault ( ) ,
25- Audience = audience ?? jwtBearerSettings . Audiences ? . FirstOrDefault ( ) ,
36+ Subject = new ClaimsIdentity ( claims , JwtBearerSettings . SchemeName , JwtBearerSettings . NameClaimType , JwtBearerSettings . RoleClaimType ) ,
37+ Issuer = issuer ?? JwtBearerSettings . Issuers ? . FirstOrDefault ( ) ,
38+ Audience = audience ?? JwtBearerSettings . Audiences ? . FirstOrDefault ( ) ,
2639 IssuedAt = now ,
27- NotBefore = now . Add ( - jwtBearerSettings . ClockSkew ) ,
28- Expires = absoluteExpiration ?? ( jwtBearerSettings . ExpirationTime . GetValueOrDefault ( ) > TimeSpan . Zero ? now . Add ( jwtBearerSettings . ExpirationTime ! . Value ) : DateTime . MaxValue ) ,
29- SigningCredentials = new SigningCredentials ( new SymmetricSecurityKey ( Encoding . UTF8 . GetBytes ( jwtBearerSettings . SecurityKey ) ) , jwtBearerSettings . Algorithm )
40+ NotBefore = now . Add ( - JwtBearerSettings . ClockSkew ) ,
41+ Expires = absoluteExpiration ?? ( JwtBearerSettings . ExpirationTime . GetValueOrDefault ( ) > TimeSpan . Zero ? now . Add ( JwtBearerSettings . ExpirationTime ! . Value ) : DateTime . MaxValue ) ,
42+ SigningCredentials = new SigningCredentials ( new SymmetricSecurityKey ( Encoding . UTF8 . GetBytes ( JwtBearerSettings . SecurityKey ) ) , JwtBearerSettings . Algorithm )
3043 } ;
3144
3245 var tokenHandler = new JsonWebTokenHandler ( ) ;
@@ -35,7 +48,8 @@ public Task<string> CreateTokenAsync(string userName, IList<Claim>? claims = nul
3548 return Task . FromResult ( token ) ;
3649 }
3750
38- public async Task < ClaimsPrincipal > ValidateTokenAsync ( string token , bool validateLifetime = true )
51+ /// <inheritdoc />
52+ public virtual async Task < ClaimsPrincipal > ValidateTokenAsync ( string token , bool validateLifetime = true )
3953 {
4054 var tokenHandler = new JsonWebTokenHandler ( ) ;
4155
@@ -46,23 +60,23 @@ public async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validat
4660
4761 var tokenValidationParameters = new TokenValidationParameters
4862 {
49- AuthenticationType = jwtBearerSettings . SchemeName ,
50- NameClaimType = jwtBearerSettings . NameClaimType ,
51- RoleClaimType = jwtBearerSettings . RoleClaimType ,
52- ValidateIssuer = jwtBearerSettings . Issuers ? . Any ( ) ?? false ,
53- ValidIssuers = jwtBearerSettings . Issuers ,
54- ValidateAudience = jwtBearerSettings . Audiences ? . Any ( ) ?? false ,
55- ValidAudiences = jwtBearerSettings . Audiences ,
63+ AuthenticationType = JwtBearerSettings . SchemeName ,
64+ NameClaimType = JwtBearerSettings . NameClaimType ,
65+ RoleClaimType = JwtBearerSettings . RoleClaimType ,
66+ ValidateIssuer = JwtBearerSettings . Issuers ? . Any ( ) ?? false ,
67+ ValidIssuers = JwtBearerSettings . Issuers ,
68+ ValidateAudience = JwtBearerSettings . Audiences ? . Any ( ) ?? false ,
69+ ValidAudiences = JwtBearerSettings . Audiences ,
5670 ValidateIssuerSigningKey = true ,
57- IssuerSigningKey = new SymmetricSecurityKey ( Encoding . UTF8 . GetBytes ( jwtBearerSettings . SecurityKey ) ) ,
71+ IssuerSigningKey = new SymmetricSecurityKey ( Encoding . UTF8 . GetBytes ( JwtBearerSettings . SecurityKey ) ) ,
5872 RequireExpirationTime = true ,
5973 ValidateLifetime = validateLifetime ,
60- ClockSkew = jwtBearerSettings . ClockSkew
74+ ClockSkew = JwtBearerSettings . ClockSkew
6175 } ;
6276
6377 var validationResult = await tokenHandler . ValidateTokenAsync ( token , tokenValidationParameters ) ;
6478
65- if ( ! validationResult . IsValid || validationResult . SecurityToken is not JsonWebToken jsonWebToken || jsonWebToken . Alg != jwtBearerSettings . Algorithm )
79+ if ( ! validationResult . IsValid || validationResult . SecurityToken is not JsonWebToken jsonWebToken || jsonWebToken . Alg != JwtBearerSettings . Algorithm )
6680 {
6781 throw new SecurityTokenException ( "Token is expired or invalid" , validationResult . Exception ) ;
6882 }
@@ -71,12 +85,13 @@ public async Task<ClaimsPrincipal> ValidateTokenAsync(string token, bool validat
7185 return principal ;
7286 }
7387
74- public async Task < string > RefreshTokenAsync ( string token , bool validateLifetime , DateTime ? absoluteExpiration = null )
88+ /// <inheritdoc />
89+ public virtual async Task < string > RefreshTokenAsync ( string token , bool validateLifetime , DateTime ? absoluteExpiration = null )
7590 {
7691 var principal = await ValidateTokenAsync ( token , validateLifetime ) ;
7792 var claims = ( principal . Identity as ClaimsIdentity ) ! . Claims . ToList ( ) ;
7893
79- var userName = claims . First ( c => c . Type == jwtBearerSettings . NameClaimType ) . Value ;
94+ var userName = claims . First ( c => c . Type == JwtBearerSettings . NameClaimType ) . Value ;
8095 var issuer = claims . FirstOrDefault ( c => c . Type == JwtRegisteredClaimNames . Iss ) ? . Value ;
8196 var audience = claims . FirstOrDefault ( c => c . Type == JwtRegisteredClaimNames . Aud ) ? . Value ;
8297
0 commit comments