1- using System . Net . Http . Headers ;
2- using System . Security . Claims ;
3- using Certify . Client ;
1+ using Certify . Client ;
42using Certify . Models . Hub ;
53using Microsoft . AspNetCore . Authentication . JwtBearer ;
64using Microsoft . AspNetCore . Authorization ;
75using Microsoft . AspNetCore . Mvc ;
6+ using Microsoft . Extensions . Caching . Memory ;
87
98namespace Certify . Server . Hub . Api . Controllers
109{
@@ -19,17 +18,22 @@ public partial class AuthController : ApiControllerBase
1918 private readonly ICertifyInternalApiClient _client ;
2019 private IConfiguration _config ;
2120
21+ private readonly IMemoryCache _memoryCache ;
22+
2223 /// <summary>
2324 /// Controller for Auth operations
2425 /// </summary>
2526 /// <param name="logger"></param>
2627 /// <param name="client"></param>
2728 /// <param name="config"></param>
28- public AuthController ( ILogger < AuthController > logger , ICertifyInternalApiClient client , IConfiguration config )
29+ /// <param name="memoryCache"></param>
30+ public AuthController ( ILogger < AuthController > logger , ICertifyInternalApiClient client , IConfiguration config , IMemoryCache memoryCache )
2931 {
3032 _logger = logger ;
3133 _client = client ;
3234 _config = config ;
35+
36+ _memoryCache = memoryCache ;
3337 }
3438
3539 /// <summary>
@@ -44,6 +48,15 @@ public async Task<IActionResult> CheckAuthStatus()
4448 return await Task . FromResult ( new OkResult ( ) ) ;
4549 }
4650
51+ private void CacheRefreshToken ( string userId , string refreshToken )
52+ {
53+ var refreshTokenExpiryMinutes = int . Parse ( _config [ "JwtSettings:refreshTokenExpirationInMinutes" ] ?? "600" ) ;
54+
55+ var expiry = new TimeSpan ( 0 , refreshTokenExpiryMinutes , 0 ) ;
56+
57+ _memoryCache . Set ( "RefreshToken_" + refreshToken , userId , expiry ) ;
58+ }
59+
4760 /// <summary>
4861 /// Perform login using username and password
4962 /// </summary>
@@ -65,13 +78,26 @@ public async Task<IActionResult> Login(AuthRequest login)
6578
6679 var jwt = new Hub . Api . Services . JwtService ( _config ) ;
6780
81+ var refreshToken = jwt . GenerateRefreshToken ( ) ;
82+
83+ CacheRefreshToken ( validation . SecurityPrincipal . Id , refreshToken ) ;
84+
85+ var jwtExpiryMinutes = double . Parse ( _config [ "JwtSettings:authTokenExpirationInMinutes" ] ?? "20" ) ;
86+ var newJwt = jwt . GenerateSecurityToken ( validation . SecurityPrincipal . Id , jwtExpiryMinutes ) ;
87+
88+ var authContext = new AuthContext
89+ {
90+ UserId = validation . SecurityPrincipal . Id ,
91+ Token = newJwt
92+ } ;
93+
6894 var authResponse = new AuthResponse
6995 {
7096 Detail = "OK" ,
71- AccessToken = jwt . GenerateSecurityToken ( validation . SecurityPrincipal . Id , double . Parse ( _config [ "JwtSettings:authTokenExpirationInMinutes" ] ?? "20" ) ) ,
72- RefreshToken = jwt . GenerateRefreshToken ( ) ,
97+ AccessToken = newJwt ,
98+ RefreshToken = refreshToken ,
7399 SecurityPrincipal = validation . SecurityPrincipal ,
74- RoleStatus = await _client . GetSecurityPrincipalRoleStatus ( validation . SecurityPrincipal . Id , CurrentAuthContext )
100+ RoleStatus = await _client . GetSecurityPrincipalRoleStatus ( validation . SecurityPrincipal . Id , authContext )
75101 } ;
76102
77103 // TODO: Refresh token should be stored or hashed for later use
@@ -91,56 +117,57 @@ public async Task<IActionResult> Login(AuthRequest login)
91117 }
92118
93119 /// <summary>
94- /// Refresh users current auth token
120+ /// Refresh users current auth token using refresh token
95121 /// </summary>
96122 /// <param name="refreshToken"></param>
97123 /// <returns></returns>
98- [ Authorize ( AuthenticationSchemes = JwtBearerDefaults . AuthenticationScheme ) ]
124+ [ AllowAnonymous ]
99125 [ HttpPost ]
100126 [ Route ( "refresh" ) ]
101127 [ ProducesResponseType ( typeof ( AuthResponse ) , StatusCodes . Status200OK ) ]
102128 public async Task < IActionResult > Refresh ( string refreshToken )
103129 {
104- var authToken = AuthenticationHeaderValue . Parse ( Request . Headers [ "Authorization" ] ! ) . Parameter ;
105-
106- if ( string . IsNullOrEmpty ( authToken ) )
107- {
108- return Unauthorized ( ) ;
109- }
110-
111130 try
112131 {
113132 // validate token and issue new one
114- var jwt = new Hub . Api . Services . JwtService ( _config ) ;
133+ if ( _memoryCache . TryGetValue ( "RefreshToken_" + refreshToken , out string ? userId ) )
134+ {
135+ // we have a valid refresh token, refresh and auth user
115136
116- var claimsIdentity = await jwt . ClaimsIdentityFromTokenAsync ( authToken , false ) ;
117- var userId = claimsIdentity . FindFirst ( ClaimTypes . Sid ) ? . Value ;
137+ var spList = await _client . GetSecurityPrincipals ( CurrentAuthContext ) ;
138+ var sp = spList . Single ( s => s . Id == userId ) ;
118139
119- if ( userId == null )
120- {
121- return Unauthorized ( ) ;
122- }
140+ var jwtExpiryMinutes = double . Parse ( _config [ "JwtSettings:authTokenExpirationInMinutes" ] ?? "20" ) ;
141+ var jwt = new Hub . Api . Services . JwtService ( _config ) ;
142+ var newJwt = jwt . GenerateSecurityToken ( sp . Id , jwtExpiryMinutes ) ;
123143
124- var newJwtToken = jwt . GenerateSecurityToken ( userId , double . Parse ( _config [ "JwtSettings:authTokenExpirationInMinutes" ] ?? "20" ) ) ;
125- var newRefreshToken = jwt . GenerateRefreshToken ( ) ;
144+ // invalidate old refresh token and store new one
145+ var newRefreshToken = jwt . GenerateRefreshToken ( ) ;
126146
127- // invalidate old refresh token and store new one
128- // DeleteRefreshToken(username, refreshToken);
129- // SaveRefreshToken(username, newRefreshToken);
147+ CacheRefreshToken ( sp . Id , newRefreshToken ) ;
130148
131- var spList = await _client . GetSecurityPrincipals ( CurrentAuthContext ) ;
132- var sp = spList . Single ( s => s . Id == userId ) ;
149+ var authContext = new AuthContext
150+ {
151+ UserId = sp . Id ,
152+ Token = newJwt
153+ } ;
133154
134- var authResponse = new AuthResponse
135- {
136- Detail = "OK" ,
137- AccessToken = newJwtToken ,
138- RefreshToken = newRefreshToken ,
139- SecurityPrincipal = sp ,
140- RoleStatus = await _client . GetSecurityPrincipalRoleStatus ( userId , CurrentAuthContext )
141- } ;
155+ var authResponse = new AuthResponse
156+ {
157+ Detail = "OK" ,
158+ AccessToken = newJwt ,
159+ RefreshToken = newRefreshToken ,
160+ SecurityPrincipal = sp ,
161+ RoleStatus = await _client . GetSecurityPrincipalRoleStatus ( sp . Id , authContext )
162+ } ;
142163
143- return Ok ( authResponse ) ;
164+ return Ok ( authResponse ) ;
165+ }
166+ else
167+ {
168+ // no valid refresh token found
169+ return Unauthorized ( ) ;
170+ }
144171 }
145172 catch
146173 {
0 commit comments