11using System . Security . Claims ;
22using FreeRedis ;
33using Microsoft . EntityFrameworkCore ;
4+ using Microsoft . Extensions . Caching . Memory ;
45using Microsoft . Extensions . Options ;
56using Netcorext . Algorithms ;
67using Netcorext . Auth . Authorization . Models ;
@@ -24,17 +25,19 @@ public class CreateTokenHandler : IRequestHandler<CreateToken, Result<TokenResul
2425{
2526 private readonly IDispatcher _dispatcher ;
2627 private readonly DatabaseContext _context ;
28+ private readonly IMemoryCache _cache ;
2729 private readonly ISnowflake _snowflake ;
2830 private readonly JwtGenerator _jwtGenerator ;
2931 private readonly ISerializer _serializer ;
3032 private readonly RedisClient _redis ;
3133 private readonly ConfigSettings _config ;
3234 private readonly AuthOptions _authOptions ;
3335
34- public CreateTokenHandler ( IDispatcher dispatcher , DatabaseContextAdapter context , ISnowflake snowflake , JwtGenerator jwtGenerator , RedisClient redis , ISerializer serializer , IOptions < AuthOptions > authOptions , IOptions < ConfigSettings > config )
36+ public CreateTokenHandler ( IDispatcher dispatcher , DatabaseContextAdapter context , IMemoryCache cache , ISnowflake snowflake , JwtGenerator jwtGenerator , RedisClient redis , ISerializer serializer , IOptions < AuthOptions > authOptions , IOptions < ConfigSettings > config )
3537 {
3638 _dispatcher = dispatcher ;
3739 _context = context ;
40+ _cache = cache ;
3841 _snowflake = snowflake ;
3942 _jwtGenerator = jwtGenerator ;
4043 _serializer = serializer ;
@@ -74,6 +77,13 @@ private async Task<Result<TokenResult>> CreateClientCredentialsAsync(CreateToken
7477 ErrorDescription = Constants . OAuth . INVALID_REQUEST_ID_OR_SECRET_MESSAGE
7578 } ) ;
7679
80+ if ( _cache . Get < bool > ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + clientId ) )
81+ return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
82+ {
83+ Error = Constants . OAuth . ACCESS_DENIED ,
84+ ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
85+ } ) ;
86+
7787 var dsClient = _context . Set < Domain . Entities . Client > ( ) ;
7888
7989 var client = await dsClient . Include ( t => t . Roles )
@@ -88,11 +98,17 @@ private async Task<Result<TokenResult>> CreateClientCredentialsAsync(CreateToken
8898 } ) ;
8999
90100 if ( client . Disabled )
101+ {
102+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + client . Id , true , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
103+
91104 return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
92105 {
93106 Error = Constants . OAuth . ACCESS_DENIED ,
94107 ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
95108 } ) ;
109+ }
110+
111+
96112
97113 var secret = request . ClientSecret ! . Pbkdf2HashCode ( client . CreationDate . ToUnixTimeMilliseconds ( ) ) ;
98114
@@ -195,13 +211,27 @@ private async Task<Result<TokenResult>> CreatePasswordCredentialsAsync(CreateTok
195211 ErrorDescription = Constants . OAuth . UNAUTHORIZED_CLIENT_MESSAGE
196212 } ) ;
197213
214+ if ( _cache . Get < bool > ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + clientId ) )
215+ return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
216+ {
217+ Error = Constants . OAuth . ACCESS_DENIED ,
218+ ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
219+ } ) ;
220+
198221 if ( request . Username . IsEmpty ( ) || request . Password . IsEmpty ( ) )
199222 return Result < TokenResult > . InvalidInput . Clone ( new TokenResult
200223 {
201224 Error = Constants . OAuth . INVALID_REQUEST ,
202225 ErrorDescription = Constants . OAuth . INVALID_REQUEST_USERNAME_OR_PASSWORD_MESSAGE
203226 } ) ;
204227
228+ if ( _cache . Get < bool > ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + request . Username ! . ToUpper ( ) ) )
229+ return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
230+ {
231+ Error = Constants . OAuth . ACCESS_DENIED ,
232+ ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
233+ } ) ;
234+
205235 var dsClient = _context . Set < Domain . Entities . Client > ( ) ;
206236
207237 var client = await dsClient . FirstOrDefaultAsync ( t => t . Id == clientId , cancellationToken ) ;
@@ -214,11 +244,15 @@ private async Task<Result<TokenResult>> CreatePasswordCredentialsAsync(CreateTok
214244 } ) ;
215245
216246 if ( client . Disabled )
217- return Result < TokenResult > . Forbidden . Clone ( new TokenResult
218- {
219- Error = Constants . OAuth . ACCESS_DENIED ,
220- ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
221- } ) ;
247+ {
248+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + client . Id , true , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
249+
250+ return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
251+ {
252+ Error = Constants . OAuth . ACCESS_DENIED ,
253+ ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
254+ } ) ;
255+ }
222256
223257 var secret = request . ClientSecret ! . Pbkdf2HashCode ( client . CreationDate . ToUnixTimeMilliseconds ( ) ) ;
224258
@@ -243,11 +277,16 @@ private async Task<Result<TokenResult>> CreatePasswordCredentialsAsync(CreateTok
243277 } ) ;
244278
245279 if ( user . Disabled )
280+ {
281+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + user . Id , true , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
282+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + user . NormalizedUsername , true , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
283+
246284 return Result < TokenResult > . AccountIsDisabled . Clone ( new TokenResult
247285 {
248286 Error = Constants . OAuth . ACCESS_DENIED ,
249287 ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
250288 } ) ;
289+ }
251290
252291 var password = request . Password ! . Pbkdf2HashCode ( user . CreationDate . ToUnixTimeMilliseconds ( ) ) ;
253292
@@ -422,11 +461,15 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
422461 var client = await dsClient . FirstAsync ( t => t . Id == clientId , cancellationToken ) ;
423462
424463 if ( client . Disabled )
464+ {
465+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + client . Id , true , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
466+
425467 return Result < TokenResult > . Forbidden . Clone ( new TokenResult
426468 {
427469 Error = Constants . OAuth . ACCESS_DENIED ,
428470 ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
429471 } ) ;
472+ }
430473
431474 var secret = request . ClientSecret ! . Pbkdf2HashCode ( client . CreationDate . ToUnixTimeMilliseconds ( ) ) ;
432475
@@ -491,14 +534,21 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
491534
492535 try
493536 {
494- var ( verified , disabled , roles , hasPassword , emailConfirmed , phoneNumberConfirmed , label , allowedRefreshToken , tokenExpireSeconds , refreshTokenExpireSeconds , _) = await GetResourceExpireSecondsAsync ( resourceType , resourceId ! ) ;
537+ var ( resourceName , verified , disabled , roles , hasPassword , emailConfirmed , phoneNumberConfirmed , label , allowedRefreshToken , tokenExpireSeconds , refreshTokenExpireSeconds , _) = await GetResourceExpireSecondsAsync ( resourceType , resourceId ! ) ;
495538
496539 if ( disabled )
540+ {
541+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + resourceId , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
542+ _cache . Set ( ConfigSettings . CACHE_RESOURCE_DISABLED + ":" + resourceName . ToUpper ( ) , TimeSpan . FromMilliseconds ( _config . AppSettings . CacheResourceDisabledExpires ) ) ;
543+
497544 return Result < TokenResult > . Forbidden . Clone ( new TokenResult
498545 {
499546 Error = Constants . OAuth . ACCESS_DENIED ,
500547 ErrorDescription = Constants . OAuth . ACCESS_DENIED_MESSAGE
501548 } ) ;
549+ }
550+
551+
502552
503553 if ( request . Scope == "*" )
504554 scope = roles . Any ( ) ? roles . Select ( t => t . Id . ToString ( ) ) . Aggregate ( ( c , n ) => c + " " + n ) : null ;
@@ -607,7 +657,7 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
607657 }
608658 }
609659
610- private async Task < ( bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetResourceExpireSecondsAsync ( ResourceType resourceType , string resourceId )
660+ private async Task < ( string nameOrId , bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetResourceExpireSecondsAsync ( ResourceType resourceType , string resourceId )
611661 {
612662 return resourceType switch
613663 {
@@ -617,7 +667,7 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
617667 } ;
618668 }
619669
620- private async Task < ( bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetUserExpireSecondsAsync ( string resourceId )
670+ private async Task < ( string username , bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetUserExpireSecondsAsync ( string resourceId )
621671 {
622672 if ( resourceId . IsEmpty ( ) || ! long . TryParse ( resourceId , out var id ) ) throw new ArgumentException ( $ "Invalid { nameof ( resourceId ) } .") ;
623673
@@ -647,10 +697,10 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
647697 ? roles [ 0 ] . Name
648698 : null ;
649699
650- return ( entity . Verified , entity . Disabled , roles , ! entity . Password . IsEmpty ( ) , entity . EmailConfirmed , entity . PhoneNumberConfirmed , label , entity . AllowedRefreshToken , entity . TokenExpireSeconds , entity . RefreshTokenExpireSeconds , entity . CodeExpireSeconds ) ;
700+ return ( entity . Username , entity . Verified , entity . Disabled , roles , ! entity . Password . IsEmpty ( ) , entity . EmailConfirmed , entity . PhoneNumberConfirmed , label , entity . AllowedRefreshToken , entity . TokenExpireSeconds , entity . RefreshTokenExpireSeconds , entity . CodeExpireSeconds ) ;
651701 }
652702
653- private async Task < ( bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetClientExpireSecondsAsync ( string resourceId )
703+ private async Task < ( string id , bool Verified , bool Disabled , Role [ ] Roles , bool ? HasPassword , bool ? EmailConfirmed , bool ? PhoneNumberConfirmed , string ? Label , bool AllowedRefreshToken , int ? TokenExpireSeconds , int ? RefreshTokenExpireSeconds , int ? CodeExpireSeconds ) > GetClientExpireSecondsAsync ( string resourceId )
654704 {
655705 if ( resourceId . IsEmpty ( ) || ! long . TryParse ( resourceId , out var id ) ) throw new ArgumentException ( $ "Invalid { nameof ( resourceId ) } .") ;
656706
@@ -680,7 +730,7 @@ private async Task<Result<TokenResult>> CreateRefreshTokenAsync(CreateToken requ
680730 ? roles [ 0 ] . Name
681731 : null ;
682732
683- return ( false , entity . Disabled , roles , null , null , null , label , entity . AllowedRefreshToken , entity . TokenExpireSeconds , entity . RefreshTokenExpireSeconds , entity . CodeExpireSeconds ) ;
733+ return ( entity . Id . ToString ( ) , false , entity . Disabled , roles , null , null , null , label , entity . AllowedRefreshToken , entity . TokenExpireSeconds , entity . RefreshTokenExpireSeconds , entity . CodeExpireSeconds ) ;
684734 }
685735
686736 private Task < bool > IsValidAsync ( string grantType )
0 commit comments