11using System ;
2- using System . Collections . Generic ;
2+ using System . Linq ;
33using System . IdentityModel . Tokens . Jwt ;
4+ using System . Text . Encodings . Web ;
45using System . Text . Json ;
6+ using System . Text . Unicode ;
57using System . Threading . Tasks ;
68using HwProj . APIGateway . API . Lti . Configuration ;
79using HwProj . APIGateway . API . Lti . Services ;
@@ -25,12 +27,12 @@ ILtiKeyService ltiKeyService
2527 [ AllowAnonymous ]
2628 public async Task < IActionResult > OnDeepLinkingReturnAsync ( [ FromForm ] IFormCollection form )
2729 {
28- if ( ! form . ContainsKey ( "JWT" ) )
30+ if ( ! form . TryGetValue ( "JWT" , out var jwtValue ) )
2931 {
3032 return BadRequest ( "Missing JWT parameter" ) ;
3133 }
3234
33- string tokenString = form [ "JWT" ] ! ;
35+ var tokenString = jwtValue . ToString ( ) ;
3436 var handler = new JwtSecurityTokenHandler ( ) ;
3537
3638 if ( ! handler . CanReadToken ( tokenString ) )
@@ -48,78 +50,87 @@ public async Task<IActionResult> OnDeepLinkingReturnAsync([FromForm] IFormCollec
4850 }
4951
5052 var signingKeys = await ltiKeyService . GetKeysAsync ( tool . JwksEndpoint ) ;
53+ JwtSecurityToken validatedToken ;
5154
5255 try
5356 {
5457 handler . ValidateToken ( tokenString , new TokenValidationParameters
5558 {
5659 ValidateIssuer = true ,
57- ValidIssuer = unverifiedToken . Issuer ,
58-
60+ ValidIssuer = tool . issuer ,
5961 ValidateAudience = true ,
6062 ValidAudience = ltiPlatformOptions . Value . Issuer ,
61-
6263 ValidateLifetime = true ,
6364 ClockSkew = TimeSpan . FromMinutes ( 5 ) ,
64-
6565 ValidateIssuerSigningKey = true ,
6666 IssuerSigningKeys = signingKeys
67- } , out var validatedToken ) ;
67+ } , out var secToken ) ;
68+
69+ validatedToken = ( JwtSecurityToken ) secToken ;
6870 }
6971 catch ( Exception ex )
7072 {
7173 return BadRequest ( $ "Token signature validation failed: { ex . Message } ") ;
7274 }
7375
7476 const string itemsClaimName = "https://purl.imsglobal.org/spec/lti-dl/claim/content_items" ;
75-
76- var resultList = new List < object > ( ) ;
7777
78- if ( unverifiedToken . Payload . TryGetValue ( itemsClaimName , out var itemsObject ) )
79- {
80- var jsonString = itemsObject . ToString ( ) ;
81- if ( ! string . IsNullOrEmpty ( jsonString ) )
82- {
83- using var doc = JsonDocument . Parse ( jsonString ) ;
84- if ( doc . RootElement . ValueKind == JsonValueKind . Array )
85- {
86- foreach ( var rawItem in doc . RootElement . EnumerateArray ( ) )
87- {
88- resultList . Add ( rawItem . Clone ( ) . ToString ( ) ) ;
89- }
90- }
91- }
92- }
78+ var itemsClaims = validatedToken . Claims
79+ . Where ( c => c . Type == itemsClaimName )
80+ . Select ( c => c . Value )
81+ . ToList ( ) ;
9382
94- if ( resultList . Count == 0 )
83+ if ( itemsClaims . Count == 0 )
9584 {
9685 return Content ( "<script>window.close();</script>" , "text/html" ) ;
9786 }
9887
99- var responsePayloadJson = JsonSerializer . Serialize ( resultList ) ;
88+ string safeJsonPayload ;
89+ var options = new JsonSerializerOptions
90+ {
91+ Encoder = JavaScriptEncoder . Create ( UnicodeRanges . All )
92+ } ;
93+
94+ if ( itemsClaims . Count == 1 )
95+ {
96+ var singleParsed = JsonSerializer . Deserialize < JsonElement > ( itemsClaims [ 0 ] ) ;
97+
98+ safeJsonPayload = singleParsed . ValueKind == JsonValueKind . Array ?
99+ JsonSerializer . Serialize ( singleParsed , options ) : JsonSerializer . Serialize ( new [ ] { singleParsed } , options ) ;
100+ }
101+ else
102+ {
103+ var elements = itemsClaims
104+ . Select ( v => JsonSerializer . Deserialize < JsonElement > ( v ) )
105+ . ToList ( ) ;
106+ safeJsonPayload = JsonSerializer . Serialize ( elements , options ) ;
107+ }
100108
101- // language=html
102109 var htmlResponse = $@ "
103110 <!DOCTYPE html>
104111 <html>
105112 <head><title>Processing LTI Return...</title></head>
106- <body>
107- <p>Задача выбрана. Возвращаемся в HwProj...</p>
113+ <body
114+ <script type=""application/json"" id=""lti-payload"">
115+ { safeJsonPayload }
116+ </script>
117+
108118 <script>
109- var payload = { responsePayloadJson } ;
110-
111- function sendAndClose() {{
119+ try {{
120+ var payloadElement = document.getElementById('lti-payload');
121+ var payload = JSON.parse(payloadElement.textContent);
122+
112123 if (window.opener) {{
113124 window.opener.postMessage({{
114- type: 'LTI_DEEP_LINK_SUCCESS', // Уникальный тип события, который слушает ваш React/Angular
125+ type: 'LTI_DEEP_LINK_SUCCESS',
115126 payload: payload
116- }}, '*'); // В продакшене вместо '*' лучше указать домен HwProj
127+ }}, '*'); // В продакшене заменить '*' на конкретный домен
117128 }}
118-
129+ }} catch (e) {{
130+ console.error('Ошибка обработки данных LTI:', e);
131+ }} finally {{
119132 window.close();
120133 }}
121-
122- sendAndClose();
123134 </script>
124135 </body>
125136 </html>" ;
0 commit comments