클라이언트 생성/수정 흐름 및 관련 UI 개선:
- 클라이언트 등록/수정 URL 구조 리팩토링 (myapikey → clients) - 로그인 직후 클라이언트 미보유 사용자 대상 추가 안내 팝업 - 클라이언트 Secret 조회 및 관련 2FA 단계 로직 개선
This commit is contained in:
@@ -25,7 +25,7 @@
|
||||
<div class="detail-wrap">
|
||||
<!-- Title Bar -->
|
||||
<div class="board-header">
|
||||
<h2 class="board-title">인증키 정보</h2>
|
||||
<h2 class="board-title">클라이언트 정보</h2>
|
||||
<span class="board-desc">등록된 앱의 상세 정보를 확인할 수 있습니다.</span>
|
||||
</div>
|
||||
|
||||
@@ -188,11 +188,11 @@
|
||||
|
||||
<!-- Bottom Navigation Actions -->
|
||||
<div class="dt-actions" style="justify-content: flex-end; gap: 11px; margin-top: 30px;">
|
||||
<a th:href="@{/myapikey}" class="dt-btn-gray">목록</a>
|
||||
<a th:href="@{/clients}" class="dt-btn-gray">목록</a>
|
||||
<button type="button" sec:authorize="hasRole('ROLE_API_KEY_REQUEST')" class="dt-btn-red"
|
||||
th:data-client-id="${apiKey.clientid}" onclick="deleteApiKeyFromButton(this)">API 이용 해지</button>
|
||||
<a sec:authorize="hasRole('ROLE_API_KEY_REQUEST')" class="dt-btn-blue"
|
||||
th:href="@{/myapikey/modify/step1(clientId=${apiKey.clientid})}">수정</a>
|
||||
th:href="@{/clients/modify/step1(clientId=${apiKey.clientid})}">변경 신청</a>
|
||||
</div>
|
||||
|
||||
</div><!-- /detail-wrap -->
|
||||
@@ -218,43 +218,48 @@
|
||||
);
|
||||
}
|
||||
|
||||
// Show password prompt for viewing client secret (최초 1회 노출 + 서버측 물리 삭제)
|
||||
// Client Secret 조회 진입 — 확인 후 조회 (본인 확인은 step-up 2FA)
|
||||
function showPasswordPrompt() {
|
||||
customPopups.showPasswordInput({
|
||||
title: 'Client Secret 조회',
|
||||
message: '보안을 위해 비밀번호를 입력해주세요.<br>조회 즉시 값은 영구 삭제됩니다.',
|
||||
onConfirm: function (password) {
|
||||
$.ajax({
|
||||
url: /*[[@{/myapikey/credential/reveal-secret}]]*/ '/myapikey/credential/reveal-secret',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ clientId: CREDENTIAL_CLIENT_ID, password: password }),
|
||||
headers: {
|
||||
'X-XSRF-TOKEN': /*[[${_csrf.token}]]*/ 'token'
|
||||
}
|
||||
}).done(function (response) {
|
||||
if (response.success) {
|
||||
customPopups.hidePasswordInput();
|
||||
|
||||
// 서버가 반환한 secret을 화면에 1회 주입
|
||||
$('#revealedSecretValue').text(response.secret);
|
||||
$('#revealedSecretCopyBtn').attr('data-secret', response.secret).data('secret', response.secret);
|
||||
|
||||
$('#hiddenSecretBox').hide();
|
||||
$('#revealedSecretBox').fadeIn(300);
|
||||
} else if (response.alreadyRevealed) {
|
||||
customPopups.hidePasswordInput();
|
||||
showLostKeyGuide();
|
||||
} else {
|
||||
customPopups.showPasswordError(response.message || '비밀번호가 일치하지 않습니다.');
|
||||
}
|
||||
}).fail(function () {
|
||||
customPopups.showPasswordError('오류가 발생했습니다. 다시 시도해주세요.');
|
||||
});
|
||||
},
|
||||
onCancel: function () {
|
||||
// User cancelled - do nothing
|
||||
customPopups.showConfirm(
|
||||
'Client Secret은 <strong>지금 한 번만</strong> 조회할 수 있으며,<br>조회 즉시 값은 <strong>영구 삭제</strong>됩니다.<br><br>조회하시겠습니까?',
|
||||
function (confirmed) {
|
||||
if (!confirmed) {
|
||||
return;
|
||||
}
|
||||
doRevealSecret();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Secret 조회 요청 (step-up 필요 시 2FA 후 동일 요청 재시도)
|
||||
function doRevealSecret() {
|
||||
$.ajax({
|
||||
url: /*[[@{/clients/credential/reveal-secret}]]*/ '/clients/credential/reveal-secret',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ clientId: CREDENTIAL_CLIENT_ID }),
|
||||
headers: {
|
||||
'X-XSRF-TOKEN': /*[[${_csrf.token}]]*/ 'token'
|
||||
}
|
||||
}).done(function (response) {
|
||||
if (response.success) {
|
||||
// 서버가 반환한 secret을 화면에 1회 주입
|
||||
$('#revealedSecretValue').text(response.secret);
|
||||
$('#revealedSecretCopyBtn').attr('data-secret', response.secret).data('secret', response.secret);
|
||||
|
||||
$('#hiddenSecretBox').hide();
|
||||
$('#revealedSecretBox').fadeIn(300);
|
||||
} else if (response.alreadyRevealed) {
|
||||
showLostKeyGuide();
|
||||
} else {
|
||||
customPopups.showAlert(response.message || 'Client Secret 조회에 실패했습니다.');
|
||||
}
|
||||
}).fail(function (jqXHR) {
|
||||
if (isStepUpRequired(jqXHR)) {
|
||||
requireStepUp('/clients/credential/reveal-secret', function () { doRevealSecret(); });
|
||||
return;
|
||||
}
|
||||
customPopups.showAlert('오류가 발생했습니다. 다시 시도해주세요.');
|
||||
});
|
||||
}
|
||||
|
||||
@@ -307,7 +312,7 @@
|
||||
$('.loading-overlay').show();
|
||||
|
||||
$.ajax({
|
||||
url: /*[[@{/myapikey/api_key_delete}]]*/ '/myapikey/api_key_delete',
|
||||
url: /*[[@{/clients/api_key_delete}]]*/ '/clients/api_key_delete',
|
||||
type: 'POST',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ clientId: clientId }),
|
||||
@@ -320,11 +325,11 @@
|
||||
return;
|
||||
}
|
||||
customPopups.showAlert(response.msg || 'API Key가 삭제되었습니다.', function () {
|
||||
window.location.href = /*[[@{/myapikey}]]*/ '/myapikey';
|
||||
window.location.href = /*[[@{/clients}]]*/ '/clients';
|
||||
});
|
||||
}).fail(function (jqXHR, textStatus, errorThrown) {
|
||||
if (isStepUpRequired(jqXHR)) {
|
||||
requireStepUp('/myapikey/api_key_delete', function () { doDeleteApiKey(clientId); });
|
||||
requireStepUp('/clients/api_key_delete', function () { doDeleteApiKey(clientId); });
|
||||
return;
|
||||
}
|
||||
customPopups.showAlert('API 삭제 요청 중 오류가 발생했습니다: ' + errorThrown);
|
||||
|
||||
Reference in New Issue
Block a user