91 lines
7.1 KiB
XML
91 lines
7.1 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="1126" height="300" viewBox="0 0 1126 300" role="img" aria-labelledby="diagram-title diagram-description">
|
|
<title id="diagram-title">로그인 후 요청에서 달라지는 네 인증 경계</title>
|
|
<desc id="diagram-description">왼쪽부터 AP1 SPA direct, AP2 token mediator, AP3 BFF, AP4 edge forward-auth를 읽는다. 각 항목은 브라우저가 보내는 입력, 중간 계층의 변환, 보호 자원이 실제로 받는 credential, 브라우저가 받는 출력을 같은 순서로 보여 준다. AP1과 AP2는 브라우저가 Bearer JWT로 API를 직접 호출하고, AP3는 BFF가 Bearer JWT를 조립하며, AP4는 Nginx가 인증 결과를 identity header와 internal token으로 바꾼다.</desc>
|
|
<metadata>{"techviz":{"spec_version":"1.1","id":"four-pattern-request-boundaries","profile":"comparison"},"source_context":{"document":"document.md","document_sha256":"df4d1a604c74e756672b5b40510abfedb8c67b39af280a5f51985ea9972f5371","anchor":{"kind":"marker","value":"four-pattern-request-boundaries","line":114}},"evidence_policy":"Each factual element cites source lines or is marked assumption.","diagram_only":true}</metadata>
|
|
<defs>
|
|
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
|
<path d="M 0 0 L 10 5 L 0 10 z" />
|
|
</marker>
|
|
<style>
|
|
:root { color-scheme: light; }
|
|
text { font-family: Inter, Pretendard, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; fill: #111827; }
|
|
.canvas { fill: #ffffff; }
|
|
.group-box { fill: #ffffff; stroke: #9ca3af; stroke-width: 1.4; stroke-dasharray: 7 5; }
|
|
.group-label-bg { fill: #ffffff; }
|
|
.group-label { font-size: 13px; font-weight: 650; fill: #374151; }
|
|
.edge { fill: none; stroke: #374151; stroke-width: 1.8; stroke-linejoin: round; stroke-linecap: round; marker-end: url(#arrow); }
|
|
.edge.style-dashed, .edge.semantic-dashed, .edge.assumption { stroke-dasharray: 7 5; }
|
|
.edge.style-dotted { stroke-dasharray: 2 5; }
|
|
.edge.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.edge.emphasis-muted { stroke: #9ca3af; }
|
|
.edge.emphasis-warning, .edge.kind-failure, .edge.kind-error { stroke: #dc2626; stroke-width: 2.2; }
|
|
.edge-label-bg { fill: #ffffff; }
|
|
.edge-label { font-size: 12px; font-weight: 560; text-anchor: middle; }
|
|
.node-shape { fill: #ffffff; stroke: #4b5563; stroke-width: 1.7; }
|
|
.node-shape.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-shape.emphasis-muted { stroke: #9ca3af; fill: #f9fafb; }
|
|
.node-shape.emphasis-warning { stroke: #d97706; stroke-width: 2; fill: #fffdf5; }
|
|
.node-shape.kind-database, .node-shape.kind-datastore, .node-shape.kind-storage { fill: #f8fafc; }
|
|
.node-shape.kind-queue, .node-shape.kind-event, .node-shape.kind-topic { fill: #fafafa; }
|
|
.node-shape.assumption { stroke-dasharray: 4 4; }
|
|
.storage-bottom, .controller-divider { fill: none; stroke: #4b5563; stroke-width: 1.4; }
|
|
.controller-led { fill: #4b5563; }
|
|
.actor-symbol { fill: none; stroke: #4b5563; stroke-width: 1.8; stroke-linecap: round; }
|
|
.actor-symbol.emphasis-primary { stroke: #2563eb; stroke-width: 2.2; }
|
|
.node-label { font-size: 14px; font-weight: 650; text-anchor: middle; }
|
|
.node-role { font-size: 10px; letter-spacing: 0.04em; text-anchor: middle; fill: #6b7280; }
|
|
.node-detail-divider { stroke: #d1d5db; stroke-width: 1; }
|
|
.node-detail { font-size: 11px; fill: #374151; }
|
|
.assumption-badge { font-size: 9px; font-weight: 700; fill: #92400e; }
|
|
.failure-mark { stroke: #dc2626; stroke-width: 4; stroke-linecap: round; }
|
|
.lifeline { stroke: #9ca3af; stroke-width: 1.2; stroke-dasharray: 5 5; }
|
|
.timeline-axis { stroke: #374151; stroke-width: 1.8; marker-end: url(#arrow); }
|
|
.timeline-stem { stroke: #6b7280; stroke-width: 1.3; }
|
|
.timeline-marker { fill: #ffffff; stroke: #374151; stroke-width: 1.7; }
|
|
.timeline-marker.primary { fill: #2563eb; stroke: #2563eb; }
|
|
.timeline-marker.warning { fill: #dc2626; stroke: #dc2626; }
|
|
.timeline-label { font-size: 13px; font-weight: 650; text-anchor: middle; }
|
|
.timeline-detail { font-size: 11px; fill: #4b5563; text-anchor: middle; }
|
|
</style>
|
|
</defs>
|
|
<rect class="canvas" width="1126" height="300" />
|
|
<g id="node-ap1">
|
|
<rect class="node-shape kind-concept emphasis-primary role-option" data-evidence="90-101,107-109" x="45.0" y="45.0" width="220.0" height="142.0" rx="7" />
|
|
<text class="node-label" x="155.0" y="82.0">AP1 · SPA direct</text>
|
|
<line class="node-detail-divider" x1="59.0" y1="103.0" x2="251.0" y2="103.0" />
|
|
<text class="node-detail" x="61.0" y="120.0">입력 · Bearer access token</text>
|
|
<text class="node-detail" x="61.0" y="136.0">변환 · 없음</text>
|
|
<text class="node-detail" x="61.0" y="152.0">자원 · 동일 Bearer JWT</text>
|
|
<text class="node-detail" x="61.0" y="168.0">출력 · /api/me JSON</text>
|
|
</g>
|
|
<g id="node-ap2">
|
|
<rect class="node-shape kind-concept emphasis-normal role-option" data-evidence="90-101,107-110" x="317.0" y="45.0" width="220.0" height="142.0" rx="7" />
|
|
<text class="node-label" x="427.0" y="82.0">AP2 · token mediator</text>
|
|
<line class="node-detail-divider" x1="331.0" y1="103.0" x2="523.0" y2="103.0" />
|
|
<text class="node-detail" x="333.0" y="120.0">입력 · session 뒤 Bearer</text>
|
|
<text class="node-detail" x="333.0" y="136.0">변환 · access JSON 반환</text>
|
|
<text class="node-detail" x="333.0" y="152.0">자원 · browser-created JWT</text>
|
|
<text class="node-detail" x="333.0" y="168.0">출력 · token JSON + /api/me</text>
|
|
</g>
|
|
<g id="node-ap3">
|
|
<rect class="node-shape kind-concept emphasis-normal role-option" data-evidence="90-101,107-111" x="589.0" y="45.0" width="220.0" height="142.0" rx="7" />
|
|
<text class="node-label" x="699.0" y="82.0">AP3 · BFF</text>
|
|
<line class="node-detail-divider" x1="603.0" y1="103.0" x2="795.0" y2="103.0" />
|
|
<text class="node-detail" x="605.0" y="120.0">입력 · AP3_SESSION</text>
|
|
<text class="node-detail" x="605.0" y="136.0">변환 · BFF Bearer 생성</text>
|
|
<text class="node-detail" x="605.0" y="152.0">자원 · BFF Bearer JWT</text>
|
|
<text class="node-detail" x="605.0" y="168.0">출력 · 중계된 JSON</text>
|
|
</g>
|
|
<g id="node-ap4">
|
|
<rect class="node-shape kind-concept emphasis-normal role-option" data-evidence="90-101,107-112" x="861.0" y="45.0" width="220.0" height="142.0" rx="7" />
|
|
<text class="node-label" x="971.0" y="73.0">AP4 · edge</text>
|
|
<text class="node-label" x="971.0" y="91.0">forward-auth</text>
|
|
<line class="node-detail-divider" x1="875.0" y1="112.0" x2="1067.0" y2="112.0" />
|
|
<text class="node-detail" x="877.0" y="129.0">입력 · AP4_SESSION</text>
|
|
<text class="node-detail" x="877.0" y="145.0">변환 · auth 결과 투영</text>
|
|
<text class="node-detail" x="877.0" y="161.0">자원 · identity + internal</text>
|
|
<text class="node-detail" x="877.0" y="177.0">출력 · /edge/me JSON</text>
|
|
</g>
|
|
</svg>
|