SSO 로그아웃(RP-Initiated end_session) 구현 및 세션 쿠키 정리 보강

- BaronSSO.SignOutAsync: id_token_hint 기반 end_session 로그아웃 + 로컬 세션 정리
- SsoClient.LogoutAsync: end_session_endpoint 이동 후 post_logout 복귀를 WebView에서 가로채기
- BaronSSOOption.PostLogoutRedirectUri 추가
- LoginWindow: 쿠키 삭제를 ClearBrowsingDataAsync(완료 대기)로 변경해 재로그인 자동 SSO 통과 방지
- UserInfo: IsFamily/IsCenter 대소문자 무시 비교를 StringComparer로 수정(빌드 오류 해소)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-16 12:25:41 +09:00
parent 3de67f0052
commit 1c41230021
8 changed files with 101 additions and 57 deletions

View File

@@ -3,6 +3,8 @@ using BaronSoftware.Auth;
using BaronSoftware.Auth.Sample;
using System;
using System.Text;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Windows;
@@ -113,6 +115,7 @@ namespace BaronSoftware.SSO.Sample
sb.AppendLine($"UserId(sub) : {u.UUID}");
sb.AppendLine($"Name : {u.Name}");
sb.AppendLine($"Email : {u.Email}");
sb.AppendLine($"TenantIds : {string.Join(", ", u.AllTenantIds ?? Array.Empty<string>())}");
sb.AppendLine($"Last Auth Time : {u.LastAuthTime}");
sb.AppendLine($"Claims Start------------ \n ");
sb.AppendLine(string.Join("\n", u.Claims.Select(kv => $" {kv.Key}: {kv.Value}")));
@@ -123,15 +126,30 @@ namespace BaronSoftware.SSO.Sample
sb.AppendLine();
sb.AppendLine("==== token 엔드포인트 응답 (원본) ====");
sb.AppendLine(u.RawTokenResponse);
sb.AppendLine(PrettyJson(u.RawTokenResponse));
sb.AppendLine();
sb.AppendLine("==== userinfo 응답 ====");
sb.AppendLine(u.Raw);
sb.AppendLine(PrettyJson(u.Raw));
return sb.ToString();
}
private static readonly JsonSerializerOptions PrettyJsonOptions = new()
{
WriteIndented = true,
// 한글 등 비ASCII를 \uXXXX로 이스케이프하지 않고 그대로 표시
Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};
/// <summary>JSON 문자열을 들여쓰기(pretty) 형태로 변환. 파싱 실패 시 원본 반환.</summary>
private static string PrettyJson(string json)
{
if (string.IsNullOrWhiteSpace(json)) return json;
try { return JsonNode.Parse(json)?.ToJsonString(PrettyJsonOptions) ?? json; }
catch { return json; }
}
private async void TokenLoginBuggon_Click(object sender, RoutedEventArgs e) => await RunAsync("토큰 로그인", () => _license.SignInAsync(_license.CurrentUser.RefreshToken));
}
}