feat #468: add permission setup wizard

This commit is contained in:
devmrko
2026-06-26 04:38:20 +09:00
parent 4961083f06
commit 3629c84861
4 changed files with 427 additions and 61 deletions

View File

@@ -12,68 +12,165 @@
<div class="alert alert-success" th:if="${message}" th:text="${message}"></div>
<section class="content-band">
<h2>권한 추가</h2>
<form method="post" action="/permissions" class="form-grid">
<div class="section-heading">
<h2>권한 추가 Wizard</h2>
<div class="wizard-progress" aria-label="권한 추가 단계">
<button class="wizard-step-indicator active" type="button" data-wizard-target="1">1 역할</button>
<button class="wizard-step-indicator" type="button" data-wizard-target="2">2 객체</button>
<button class="wizard-step-indicator" type="button" data-wizard-target="3">3 행 규칙</button>
<button class="wizard-step-indicator" type="button" data-wizard-target="4">4 컬럼</button>
<button class="wizard-step-indicator" type="button" data-wizard-target="5">5 검토</button>
</div>
</div>
<form method="post" action="/permissions" class="permission-wizard" data-permission-wizard>
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}">
<label>
역할
<select class="form-select" name="roleId" required>
<option th:each="role : ${roles}" th:value="${role.roleId()}" th:text="${role.roleName()}"></option>
</select>
</label>
<label>
보호 객체
<select class="form-select" name="objectRef" required>
<optgroup label="등록된 보호 객체">
<option th:each="object : ${objects}"
th:value="${'protected:' + object.objectId()}"
th:attr="data-columns=${#strings.listJoin(columnsByObject[object.objectId()], ',')}"
th:text="${object.displayName()}"></option>
</optgroup>
<optgroup label="DB 스키마 객체">
<option th:each="dbObject : ${dbObjects}"
th:value="${'db:' + dbObject.value()}"
th:text="${dbObject.label()}"></option>
</optgroup>
</select>
</label>
<label>
권한 효과
<select class="form-select" name="permissionEffect" required>
<option value="ALLOW">허용</option>
<option value="DENY">거부</option>
</select>
</label>
<div class="span-2">
<div class="field-block-title">행 규칙</div>
<div id="rowRuleList" class="rule-list">
<div class="rule-row">
<select class="form-select rule-column-select" name="ruleColumn">
<option value="">기본 컬럼</option>
<option value="DEPT_CODE">DEPT_CODE</option>
<option value="OWNER_EMP_NO">OWNER_EMP_NO</option>
<option value="DOC_ID">DOC_ID</option>
<option value="TITLE">TITLE</option>
</select>
<select class="form-select rule-type-select" name="ruleType">
<option value="ALL">ALL</option>
<option value="MY_DEPT">현재 사용자 부서</option>
<option value="SELF">현재 사용자 사번</option>
<option value="DEPT">지정 부서</option>
<option value="EMP_NO">지정 사번</option>
<option value="=">=</option>
<option value="!=">!=</option>
</select>
<input class="form-control" name="ruleValue" placeholder="비교 값">
<button class="btn btn-outline-secondary" type="button" data-rule-add>추가</button>
<aside class="wizard-summary" aria-live="polite">
<div>
<span>역할</span>
<strong data-wizard-summary="role">선택 전</strong>
</div>
<div>
<span>객체</span>
<strong data-wizard-summary="object">선택 전</strong>
</div>
<div>
<span>효과</span>
<strong data-wizard-summary="effect">ALLOW</strong>
</div>
<div>
<span>행 규칙</span>
<strong data-wizard-summary="rules">ALL</strong>
</div>
</aside>
<div class="wizard-panel active" data-wizard-step="1">
<div class="wizard-panel-heading">
<span class="wizard-step-number">1</span>
<div>
<h3>역할 선택</h3>
<p>권한을 부여하거나 거부할 역할을 선택합니다.</p>
</div>
</div>
<label>
역할
<select class="form-select" name="roleId" required>
<option th:each="role : ${roles}"
th:value="${role.roleId()}"
th:text="${role.roleName()}"
th:attr="data-max-sensitivity=${role.maxSensitivityLevel()}"></option>
</select>
</label>
<p class="wizard-hint">선택한 역할의 민감도 허용 상한도 preview에 반영됩니다.</p>
</div>
<div class="wizard-panel" data-wizard-step="2">
<div class="wizard-panel-heading">
<span class="wizard-step-number">2</span>
<div>
<h3>보호 객체 선택</h3>
<p>등록된 보호 객체 또는 DB 스키마 객체를 선택합니다.</p>
</div>
</div>
<label>
보호 객체
<select class="form-select" name="objectRef" required>
<optgroup label="등록된 보호 객체">
<option th:each="object : ${objects}"
th:value="${'protected:' + object.objectId()}"
th:attr="data-columns=${#strings.listJoin(columnsByObject[object.objectId()], ',')}"
th:text="${object.displayName()}"></option>
</optgroup>
<optgroup label="DB 스키마 객체">
<option th:each="dbObject : ${dbObjects}"
th:value="${'db:' + dbObject.value()}"
th:text="${dbObject.label()}"></option>
</optgroup>
</select>
</label>
<p class="wizard-hint">DB 스키마 객체를 선택하면 저장 시 보호 객체가 자동 등록됩니다.</p>
</div>
<div class="wizard-panel" data-wizard-step="3">
<div class="wizard-panel-heading">
<span class="wizard-step-number">3</span>
<div>
<h3>권한 효과와 행 규칙</h3>
<p>허용/거부 방향과 VPD 행 필터 조건을 설정합니다.</p>
</div>
</div>
<label>
권한 효과
<select class="form-select" name="permissionEffect" required>
<option value="ALLOW">허용</option>
<option value="DENY">거부</option>
</select>
</label>
<div>
<div class="field-block-title">행 규칙</div>
<div id="rowRuleList" class="rule-list">
<div class="rule-row">
<select class="form-select rule-column-select" name="ruleColumn">
<option value="">기본 컬럼</option>
<option value="DEPT_CODE">DEPT_CODE</option>
<option value="OWNER_EMP_NO">OWNER_EMP_NO</option>
<option value="DOC_ID">DOC_ID</option>
<option value="TITLE">TITLE</option>
</select>
<select class="form-select rule-type-select" name="ruleType">
<option value="ALL">ALL</option>
<option value="MY_DEPT">현재 사용자 부서</option>
<option value="SELF">현재 사용자 사번</option>
<option value="DEPT">지정 부서</option>
<option value="EMP_NO">지정 사번</option>
<option value="=">=</option>
<option value="!=">!=</option>
</select>
<input class="form-control" name="ruleValue" placeholder="비교 값">
<button class="btn btn-outline-secondary" type="button" data-rule-add>추가</button>
</div>
</div>
</div>
</div>
<div class="span-2">
<div class="field-block-title">컬럼 NULL 처리 예외</div>
<input class="form-control" name="visibleColumns" placeholder="CONTENTS">
<div class="wizard-panel" data-wizard-step="4">
<div class="wizard-panel-heading">
<span class="wizard-step-number">4</span>
<div>
<h3>컬럼 NULL 처리 예외</h3>
<p>redaction 대상 민감 컬럼 중 원문 표시를 허용할 컬럼을 입력합니다.</p>
</div>
</div>
<label>
NULL 처리 예외 컬럼
<input class="form-control" name="visibleColumns" placeholder="CONTENTS">
</label>
<p class="wizard-hint">쉼표로 여러 컬럼을 입력합니다. 비워두면 민감 컬럼은 NULL 처리 대상으로 남습니다.</p>
</div>
<div class="wizard-panel" data-wizard-step="5">
<div class="wizard-panel-heading">
<span class="wizard-step-number">5</span>
<div>
<h3>저장 전 검토</h3>
<p>저장될 권한과 예상 effective policy를 확인합니다.</p>
</div>
</div>
<div class="policy-preview" data-policy-preview>
<dl>
<div><dt>역할</dt><dd data-preview="role">-</dd></div>
<div><dt>민감도 상한</dt><dd data-preview="sensitivity">-</dd></div>
<div><dt>보호 객체</dt><dd data-preview="object">-</dd></div>
<div><dt>행 접근</dt><dd data-preview="rowPolicy">-</dd></div>
<div><dt>컬럼 정책</dt><dd data-preview="columnPolicy">-</dd></div>
</dl>
</div>
</div>
<div class="wizard-actions">
<button class="btn btn-outline-secondary" type="button" data-wizard-prev disabled>이전</button>
<button class="btn btn-outline-primary" type="button" data-wizard-next>다음</button>
<button class="btn btn-primary" type="submit" data-wizard-submit hidden>저장</button>
</div>
<button class="btn btn-primary" type="submit">저장</button>
</form>
</section>