0722 프론트엔드 실무 심화 (5/N): 권한 기반 UI, 라우팅 보호와 접근 제어 설계
✅ 1. 프론트엔드 권한 처리란 무엇인가?
- 프론트엔드 권한 처리는 로그인한 사용자의 역할과 권한에 따라 화면, 메뉴, 버튼, 페이지 접근을 다르게 보여주는 작업입니다.
- 관리자 페이지에서는 모든 사용자가 같은 기능을 보면 안 됩니다.
- 상담 담당자, 상품 관리자, 마케터, 조회 전용 관리자, 최고 관리자가 할 수 있는 일이 다르기 때문입니다.
관리자 로그인
↓
내 정보/권한 조회
↓
메뉴 노출 제어
↓
페이지 접근 제어
↓
버튼/액션 노출 제어
↓
API 호출 시 백엔드 권한 재검사
➕ 1-1. 권한 처리가 중요한 이유
- 권한 없는 관리자가 민감한 데이터를 보면 안 됩니다.
- 실수로 주문, 상담, 상품, 배너를 수정하지 못하게 해야 합니다.
- 엑셀 다운로드처럼 개인정보가 포함될 수 있는 기능은 더 강하게 제한해야 합니다.
- 관리자별 업무 범위를 명확히 나눌 수 있습니다.
- 운영 실수와 보안 사고를 줄일 수 있습니다.
프론트에서 버튼만 숨김
↓
사용자가 API URL을 직접 호출
↓
백엔드 권한 검사가 없으면 작업 성공
결론:
프론트 권한 처리는 UX
백엔드 권한 검사가 실제 보안
- 프론트 권한 처리는 사용자가 헷갈리지 않게 하는 역할이고, 진짜 보안은 백엔드에서 막아야 합니다.
✅ 2. 인증과 인가의 차이
- 인증(Authentication)은 사용자가 누구인지 확인하는 것입니다.
- 인가(Authorization)는 그 사용자가 특정 작업을 할 수 있는지 판단하는 것입니다.
| 구분 | 의미 | 예시 |
|---|
| 인증 | 로그인 여부 확인 | 관리자 로그인 |
| 인가 | 권한 확인 | 엑셀 다운로드 가능 여부 |
| 역할 | 사용자 그룹 | SUPER_ADMIN, ADMIN, MANAGER |
| 권한 | 구체적인 작업 가능 여부 | CONSULT_UPDATE, EXCEL_DOWNLOAD |
➕ 2-1. 예시
인증:
이 사용자가 로그인한 관리자인가?
인가:
이 관리자가 상품을 수정할 수 있는가?
이 관리자가 엑셀을 다운로드할 수 있는가?
이 관리자가 다른 관리자 계정을 만들 수 있는가?
- 로그인했다고 모든 관리자 기능을 쓸 수 있는 것은 아닙니다.
- 관리자 페이지에서는 인증과 인가를 반드시 구분해야 합니다.
✅ 3. Role 기반 권한과 Permission 기반 권한
- 권한 설계는 크게 Role 기반과 Permission 기반으로 나눌 수 있습니다.
➕ 3-1. Role 기반
SUPER_ADMIN
ADMIN
MANAGER
MARKETER
VIEWER
- 역할별로 사용할 수 있는 기능을 정합니다.
- 구조가 단순해서 작은 서비스에 적합합니다.
➕ 3-2. Permission 기반
CONSULT_READ
CONSULT_UPDATE
ORDER_READ
ORDER_UPDATE
PRODUCT_CREATE
PRODUCT_UPDATE
BANNER_UPDATE
EXCEL_DOWNLOAD
ADMIN_MANAGE
- 작업 단위로 권한을 세밀하게 나눕니다.
- 복잡하지만 역할이 많아질수록 유연합니다.
➕ 3-3. 현실적인 추천
초기:
Role 기반으로 시작
서비스가 커짐:
Role + Permission 조합
예시:
ADMIN 역할은 여러 permission 묶음
특정 관리자에게 일부 permission만 추가
- 처음부터 너무 복잡한 권한 시스템을 만들 필요는 없습니다.
- 하지만 엑셀 다운로드, 관리자 생성, 권한 변경 같은 위험 기능은 별도 권한으로 분리하는 것이 좋습니다.
✅ 4. 관리자 역할 예시
| 역할 | 설명 |
|---|
SUPER_ADMIN | 전체 관리자, 계정/권한/설정 관리 가능 |
ADMIN | 일반 운영 관리자, 상담/주문/상품 관리 가능 |
MANAGER | 상담/주문 일부 처리 가능 |
MARKETER | 유입 통계, 광고 성과 조회 중심 |
VIEWER | 조회만 가능 |
➕ 4-1. 역할별 기능 예시
| 기능 | SUPER_ADMIN | ADMIN | MANAGER | MARKETER | VIEWER |
|---|
| 상담 목록 조회 | 가능 | 가능 | 가능 | 제한 | 가능 |
| 상담 상태 변경 | 가능 | 가능 | 담당 건만 | 불가 | 불가 |
| 주문 상태 변경 | 가능 | 가능 | 제한 | 불가 | 불가 |
| 상품 수정 | 가능 | 가능 | 불가 | 불가 | 불가 |
| 배너 수정 | 가능 | 가능 | 불가 | 불가 | 불가 |
| 유입 통계 조회 | 가능 | 가능 | 제한 | 가능 | 가능 |
| 엑셀 다운로드 | 가능 | 가능 | 제한 | 마스킹 통계만 | 불가 |
| 관리자 계정 생성 | 가능 | 불가 | 불가 | 불가 | 불가 |
- 이런 표를 먼저 만들어두면 프론트와 백엔드 권한 기준을 맞추기 쉽습니다.
✅ 5. 프론트엔드에서 권한 정보를 어디서 가져올까?
- 권한 정보는 보통 로그인 후
me API에서 가져옵니다.
- 토큰 안에 role이 들어있더라도, 화면에서는 서버에서 최신 사용자 정보를 조회하는 방식이 안전합니다.
➕ 5-1. me API 응답 예시
{
"id": 3,
"name": "신동준",
"email": "admin@example.com",
"role": "ADMIN",
"permissions": [
"CONSULT_READ",
"CONSULT_UPDATE",
"PRODUCT_UPDATE",
"EXCEL_DOWNLOAD"
]
}
➕ 5-2. TanStack Query로 관리자 정보 조회
const meQuery = useQuery({
queryKey: ['auth', 'me'],
queryFn: () => authApi.getMe(),
staleTime: 1000 * 60 * 5,
});
- 로그인한 관리자 정보는 여러 화면에서 필요합니다.
- 전역 상태로 복사하기보다
useMe() 같은 hook으로 감싸서 쓰면 관리가 쉽습니다.
✅ 6. useMe Hook
- 관리자 정보 조회를 화면마다 직접 작성하면 반복됩니다.
useMe hook으로 감싸두면 권한 체크와 로딩 처리를 통일할 수 있습니다.
export function useMe() {
return useQuery({
queryKey: ['auth', 'me'],
queryFn: () => authApi.getMe(),
staleTime: 1000 * 60 * 5,
retry: false,
});
}
➕ 6-1. 사용 예시
function AdminHeader() {
const { data: me, isLoading } = useMe();
if (isLoading) {
return <span>관리자 정보를 불러오는 중...</span>;
}
return <span>{me?.name}님</span>;
}
useMe는 관리자 메뉴, 권한 버튼, 페이지 보호에서 모두 재사용됩니다.
- 로그인 만료 처리는 공통 API client interceptor와 함께 처리하면 좋습니다.
✅ 7. 권한 체크 유틸 함수
- 권한 체크 로직이 컴포넌트마다 흩어지면 유지보수가 어렵습니다.
- 공통 유틸 함수로 관리하는 것이 좋습니다.
➕ 7-1. Permission 타입
export type Permission =
| 'CONSULT_READ'
| 'CONSULT_UPDATE'
| 'ORDER_READ'
| 'ORDER_UPDATE'
| 'PRODUCT_UPDATE'
| 'BANNER_UPDATE'
| 'EXCEL_DOWNLOAD'
| 'ADMIN_MANAGE';
➕ 7-2. hasPermission 함수
export function hasPermission(
userPermissions: Permission[] | undefined,
requiredPermission: Permission,
) {
if (!userPermissions) {
return false;
}
return userPermissions.includes(requiredPermission);
}
➕ 7-3. 여러 권한 체크
export function hasAnyPermission(
userPermissions: Permission[] | undefined,
requiredPermissions: Permission[],
) {
if (!userPermissions) {
return false;
}
return requiredPermissions.some((permission) =>
userPermissions.includes(permission),
);
}
- 권한 판단 기준은 한 곳에 모아야 합니다.
- 그래야 권한명이 바뀌거나 정책이 바뀌어도 수정 범위가 줄어듭니다.
✅ 8. Role 체크 유틸 함수
- Permission까지 세밀하게 나누지 않은 초기 서비스라면 role 기준으로도 충분할 수 있습니다.
export type AdminRole =
| 'SUPER_ADMIN'
| 'ADMIN'
| 'MANAGER'
| 'MARKETER'
| 'VIEWER';
export function hasRole(
userRole: AdminRole | undefined,
allowedRoles: AdminRole[],
) {
if (!userRole) {
return false;
}
return allowedRoles.includes(userRole);
}
➕ 8-1. 사용 예시
const canManageAdmins = hasRole(me?.role, ['SUPER_ADMIN']);
- Role 체크는 단순합니다.
- 하지만 “ADMIN은 상품 수정 가능하지만 엑셀 다운로드는 불가” 같은 예외가 많아지면 Permission 기반이 더 적합합니다.
✅ 9. 권한 기반 메뉴 노출
- 관리자 사이드바 메뉴는 권한에 따라 다르게 보여야 합니다.
- 접근할 수 없는 메뉴를 계속 보여주면 사용자가 혼란스러워집니다.
➕ 9-1. 메뉴 정의 예시
const adminMenus = [
{
label: '상담 관리',
href: '/admin/consults',
requiredPermission: 'CONSULT_READ',
},
{
label: '주문 관리',
href: '/admin/orders',
requiredPermission: 'ORDER_READ',
},
{
label: '상품 관리',
href: '/admin/products',
requiredPermission: 'PRODUCT_UPDATE',
},
{
label: '배너 관리',
href: '/admin/banners',
requiredPermission: 'BANNER_UPDATE',
},
{
label: '관리자 관리',
href: '/admin/admins',
requiredPermission: 'ADMIN_MANAGE',
},
] as const;
➕ 9-2. 메뉴 필터링
const visibleMenus = adminMenus.filter((menu) =>
hasPermission(me?.permissions, menu.requiredPermission),
);
- 메뉴 정의와 권한 조건을 한 곳에서 관리하면 편합니다.
- 단, 메뉴를 숨겼다고 백엔드 API 권한 검사를 생략하면 안 됩니다.
✅ 10. 권한 기반 버튼 노출
- 관리자 테이블의 액션 버튼도 권한에 따라 달라져야 합니다.
➕ 10-1. 상담 테이블 액션 예시
const canUpdateConsult = hasPermission(
me?.permissions,
'CONSULT_UPDATE',
);
return (
<div>
<button type="button" onClick={openDetail}>
상세
</button>
{canUpdateConsult && (
<button type="button" onClick={openStatusModal}>
상태 변경
</button>
)}
</div>
);
➕ 10-2. 숨김과 비활성화 기준
| 방식 | 적합한 상황 |
|---|
| 숨김 | 사용자가 알 필요 없는 기능 |
| 비활성화 | 기능은 보이지만 현재 조건상 불가 |
| 권한 없음 안내 | 권한 요청이 필요한 기능 |
권한 자체가 없음:
버튼 숨김
권한은 있지만 현재 상태에서 불가:
버튼 disabled + 이유 안내
예:
DONE 상태라 더 이상 변경 불가
- 권한 없음과 상태상 불가능은 구분해서 보여주는 것이 좋습니다.
✅ 11. 페이지 접근 보호
- 메뉴만 숨기는 것으로는 부족합니다.
- 사용자가 URL을 직접 입력해 접근할 수 있기 때문에 페이지 단위 보호가 필요합니다.
➕ 11-1. ProtectedRoute 개념
페이지 진입
↓
로그인 여부 확인
↓
권한 확인
↓
가능하면 페이지 렌더링
↓
불가능하면 로그인/권한 없음 페이지로 이동
➕ 11-2. React Router 예시
type ProtectedRouteProps = {
requiredPermission?: Permission;
children: React.ReactNode;
};
function ProtectedRoute({
requiredPermission,
children,
}: ProtectedRouteProps) {
const { data: me, isLoading, isError } = useMe();
if (isLoading) {
return <PageLoading />;
}
if (isError || !me) {
return <Navigate to="/admin/login" replace />;
}
if (
requiredPermission &&
!hasPermission(me.permissions, requiredPermission)
) {
return <ForbiddenPage />;
}
return <>{children}</>;
}
➕ 11-3. 사용 예시
<ProtectedRoute requiredPermission="PRODUCT_UPDATE">
<AdminProductPage />
</ProtectedRoute>
- 페이지 접근 보호는 사용자 경험과 보안 보조 역할입니다.
- 실제 API 권한은 백엔드에서 반드시 다시 확인해야 합니다.
✅ 12. Next.js에서 라우팅 보호
- Next.js를 사용한다면 middleware, server component, client guard 등을 조합할 수 있습니다.
- 구조에 따라 달라지지만 기본 원칙은 같습니다.
➕ 12-1. 보호해야 하는 경로
/admin
/admin/consults
/admin/orders
/admin/products
/admin/banners
/admin/settings
➕ 12-2. 클라이언트 Guard 예시
function AdminPageGuard({
requiredPermission,
children,
}: {
requiredPermission?: Permission;
children: React.ReactNode;
}) {
const { data: me, isLoading, isError } = useMe();
if (isLoading) {
return <PageLoading />;
}
if (isError || !me) {
redirect('/admin/login');
}
if (
requiredPermission &&
!hasPermission(me.permissions, requiredPermission)
) {
return <ForbiddenPage />;
}
return <>{children}</>;
}
- Next.js에서는 서버/클라이언트 렌더링 방식에 따라 구현이 달라질 수 있습니다.
- 중요한 것은 “로그인 전 화면 깜빡임”과 “권한 없는 화면 노출”을 최소화하는 것입니다.
✅ 13. 로그인 만료 처리
- 관리자 페이지에서 로그인 만료는 흔한 상황입니다.
- 토큰이 만료되면 사용자를 로그인 페이지로 보내거나, 재로그인 모달을 보여줘야 합니다.
➕ 13-1. API Client Interceptor 흐름
API 요청
↓
401 응답
↓
토큰 만료 판단
↓
로그아웃 처리
↓
로그인 페이지 이동
↓
안내 메시지 표시
➕ 13-2. 에러 메시지
로그인 시간이 만료되었습니다.
다시 로그인해 주세요.
➕ 13-3. 주의할 점
401을 무조건 서버 장애로 보여주지 않기
무한 refresh token 재시도 방지
로그아웃 후 민감한 캐시 데이터 제거
관리자 정보 query cache 제거
- 로그인 만료 처리는 화면마다 따로 하지 말고 공통 API client에서 처리하는 것이 좋습니다.
✅ 14. 권한 없음 페이지
- 권한이 없는 페이지에 접근했을 때는 명확한 안내가 필요합니다.
- 빈 화면이나 404로 처리하면 사용자가 혼란스러워집니다.
➕ 14-1. 권한 없음 메시지
이 페이지에 접근할 권한이 없습니다.
필요한 경우 최고 관리자에게 권한을 요청해 주세요.
➕ 14-2. 제공하면 좋은 버튼
이전 페이지로 돌아가기
대시보드로 이동
로그아웃
➕ 14-3. 주의할 점
- “이 기능은 SUPER_ADMIN만 가능합니다”처럼 내부 권한 구조를 너무 자세히 노출할 필요는 없습니다.
- 관리자 내부 서비스라면 어느 정도 안내해도 되지만, 외부 사용자에게는 최소 정보만 보여주는 것이 좋습니다.
✅ 15. 권한과 데이터 범위
- 권한은 “기능 사용 가능 여부”만이 아닙니다.
- 어떤 데이터를 볼 수 있는지도 권한의 일부입니다.
➕ 15-1. 예시
SUPER_ADMIN:
전체 상담 조회 가능
ADMIN:
전체 상담 조회 가능
MANAGER:
본인 담당 상담만 조회 가능
MARKETER:
개인정보 마스킹된 유입 통계만 조회 가능
VIEWER:
조회만 가능, 다운로드 불가
➕ 15-2. 프론트에서 고려할 것
담당자 필터 노출 여부
전체 데이터 보기 버튼 노출 여부
전화번호 마스킹 표시
엑셀 다운로드 버튼 제한
통계 상세 drill-down 제한
- 데이터 범위 제한은 반드시 백엔드 쿼리에서 처리해야 합니다.
- 프론트에서만 필터링하면 API 응답에는 이미 데이터가 내려온 것이기 때문에 보안상 위험합니다.
✅ 16. 개인정보 마스킹 UI
- 관리자 권한에 따라 개인정보 표시 수준이 달라질 수 있습니다.
- 전화번호, 이름, 이메일, 주소, 상담 메모는 특히 조심해야 합니다.
➕ 16-1. 권한별 표시 예시
| 권한 | 전화번호 표시 |
|---|
| SUPER_ADMIN | 01012345678 |
| ADMIN | 01012345678 |
| MANAGER | 010****5678 또는 담당 건만 전체 |
| MARKETER | 마스킹 |
| VIEWER | 마스킹 |
➕ 16-2. 프론트 표시 예시
<span>{consult.phone}</span>
- 여기서 중요한 점은 프론트가 직접 마스킹하는 것보다, 백엔드가 권한에 맞게 마스킹된 값을 내려주는 것이 더 안전하다는 점입니다.
- 프론트에는 이미 전체 전화번호가 내려왔는데 화면에서만 가리는 방식은 보안상 부족합니다.
✅ 17. 엑셀 다운로드 권한
- 엑셀 다운로드는 개인정보 대량 유출 위험이 있기 때문에 특별히 강하게 봐야 합니다.
- 목록 조회 권한과 엑셀 다운로드 권한은 분리하는 것이 좋습니다.
➕ 17-1. 권한 분리 예시
CONSULT_READ:
상담 목록 조회 가능
CONSULT_EXPORT:
상담 목록 엑셀 다운로드 가능
CONSULT_EXPORT_UNMASKED:
마스킹 없는 엑셀 다운로드 가능
➕ 17-2. 프론트 UI 기준
권한 없음:
엑셀 다운로드 버튼 숨김
권한 있음:
현재 필터 조건 기준 다운로드
민감정보 포함:
Confirm으로 안내
다운로드 요청 후:
ExportJob 생성 안내
➕ 17-3. Confirm 메시지 예시
현재 검색 조건에 해당하는 상담 내역을 엑셀로 생성하시겠습니까?
파일에는 개인정보가 포함될 수 있으므로 다운로드 및 공유에 주의해 주세요.
- 엑셀 다운로드는 관리자 작업 이력에도 남기는 것이 좋습니다.
✅ 18. 권한 기반 API 에러 처리
- 프론트에서 권한 버튼을 숨겨도 API에서 403이 올 수 있습니다.
- 권한 변경, 로그인 만료, 다른 기기 로그인, 백엔드 정책 변경 등으로 화면 상태와 서버 권한이 달라질 수 있기 때문입니다.
➕ 18-1. 403 처리 기준
목록 조회 403:
권한 없음 페이지 또는 안내
버튼 액션 403:
토스트 또는 모달로 권한 없음 안내
엑셀 다운로드 403:
다운로드 권한이 없다는 안내
관리자 관리 403:
대시보드로 이동 유도
➕ 18-2. 메시지 예시
이 작업을 수행할 권한이 없습니다.
필요한 경우 최고 관리자에게 권한을 요청해 주세요.
- 403을 일반 서버 오류로 처리하면 안 됩니다.
- 권한 문제는 권한 문제로 정확히 알려주는 것이 좋습니다.
✅ 19. 권한 변경 후 캐시 갱신
- 관리자 권한이 변경되면 프론트의
me 정보도 갱신되어야 합니다.
- 그렇지 않으면 화면에는 버튼이 남아 있는데 API는 403을 반환하는 상황이 생깁니다.
➕ 19-1. 권한 변경 후 처리
queryClient.invalidateQueries({
queryKey: ['auth', 'me'],
});
➕ 19-2. 관리자가 다른 관리자의 권한을 수정한 경우
queryClient.invalidateQueries({
queryKey: ['admin', 'admins'],
});
- 내 권한이 바뀌었는지 확인하려면
me query를 갱신해야 합니다.
- 관리자 목록을 수정했다면 관리자 목록 query도 갱신해야 합니다.
✅ 20. 권한 기준 문서화
- 권한은 코드로만 두면 나중에 헷갈립니다.
- 역할별 권한 표를 문서로 남겨야 합니다.
➕ 20-1. 문서에 넣을 것
역할 목록
권한 목록
역할별 가능 기능
데이터 범위
개인정보 마스킹 기준
엑셀 다운로드 가능 여부
관리자 생성/수정 가능 여부
백엔드 Guard 기준
프론트 메뉴/버튼 노출 기준
➕ 20-2. 문서 예시
## 관리자 권한 정책
### 역할
- SUPER_ADMIN: 전체 관리
- ADMIN: 일반 운영 관리
- MANAGER: 상담/주문 일부 처리
- MARKETER: 유입 통계 조회
- VIEWER: 조회 전용
### 주요 권한
| 권한 | 설명 |
|---|---|
| CONSULT_READ | 상담 목록 조회 |
| CONSULT_UPDATE | 상담 상태 변경 |
| CONSULT_EXPORT | 상담 엑셀 다운로드 |
| PRODUCT_UPDATE | 상품 수정 |
| ADMIN_MANAGE | 관리자 계정 관리 |
### 개인정보 표시
- SUPER_ADMIN/ADMIN: 담당 업무 범위 내 전체 표시
- MANAGER: 담당 건만 전체 표시
- MARKETER/VIEWER: 마스킹 표시
### 주의사항
- 프론트 메뉴/버튼 숨김은 UX 목적
- 실제 권한 검사는 백엔드 Guard에서 처리
- 엑셀 다운로드는 작업 이력 저장 필수
- 권한 문서는 운영자와 대표에게 설명하기에도 좋습니다.
- 나중에 관리자 역할이 늘어날 때 기준이 됩니다.
✅ 21. 프론트 권한 처리에서 자주 하는 실수
➕ 21-1. 프론트만 믿는 실수
버튼 숨김
↓
API 권한 검사 없음
↓
직접 호출하면 작업 가능
- 이건 보안 사고입니다.
- 백엔드 Guard나 middleware에서 반드시 막아야 합니다.
➕ 21-2. 권한 조건이 여러 곳에 흩어짐
if (me.role === 'ADMIN' || me.role === 'SUPER_ADMIN') {
}
- 이런 코드가 여러 화면에 반복되면 정책 변경 시 모두 수정해야 합니다.
hasPermission, canUpdateConsult, canDownloadExcel 같은 함수로 모으는 것이 좋습니다.
➕ 21-3. 권한 없음과 데이터 없음을 혼동
권한 없음:
조회할 수 없는 데이터
데이터 없음:
조회 권한은 있지만 조건에 맞는 데이터 없음
- 둘은 메시지가 달라야 합니다.
- 권한 없음은 403, 데이터 없음은 Empty 상태입니다.
➕ 21-4. 개인정보를 프론트에서만 마스킹
백엔드:
전체 전화번호 내려줌
프론트:
화면에서만 010****5678로 표시
문제:
브라우저 devtools나 네트워크 탭에서 전체 전화번호 확인 가능
- 권한별 개인정보 마스킹은 백엔드 응답 단계에서 처리하는 것이 안전합니다.
✅ 22. 실무 체크리스트
➕ 22-1. 인증 체크리스트
- 관리자 로그인 여부를 확인하는가?
- 로그인 만료 시 로그인 페이지로 이동하는가?
- 401 응답을 공통 처리하는가?
- 로그아웃 시 민감한 query cache를 제거하는가?
me API로 최신 관리자 정보를 가져오는가?
- 관리자 정보 로딩 중 화면 깜빡임을 최소화했는가?
- 토큰을 로그에 남기지 않는가?
- 로그인 만료 메시지가 사용자에게 명확한가?
➕ 22-2. 인가 체크리스트
- 페이지별 requiredPermission이 정의되어 있는가?
- 메뉴 노출이 권한에 따라 달라지는가?
- 버튼 액션이 권한에 따라 제한되는가?
- 권한 없음 페이지가 있는가?
- API 403 응답을 권한 문제로 처리하는가?
- 권한 조건이 공통 함수로 관리되는가?
- 권한 변경 후
me query를 갱신하는가?
- 백엔드에서도 같은 권한을 검사하는가?
➕ 22-3. 개인정보/엑셀 체크리스트
- 개인정보 표시 기준이 권한별로 정의되어 있는가?
- 백엔드 응답에서 마스킹이 적용되는가?
- 엑셀 다운로드 권한이 목록 조회 권한과 분리되어 있는가?
- 엑셀 다운로드 전 Confirm이 있는가?
- 다운로드 파일에 개인정보가 포함될 수 있음을 안내하는가?
- 엑셀 다운로드 이력이 저장되는가?
- 권한 없는 사용자가 다운로드 API를 직접 호출해도 막히는가?
- 마케터/조회 전용 계정은 민감정보를 볼 수 없게 되어 있는가?
➕ 22-4. 문서화 체크리스트
- 역할별 권한 표가 있는가?
- Permission 목록이 문서화되어 있는가?
- 메뉴 노출 기준이 정리되어 있는가?
- 버튼 액션 기준이 정리되어 있는가?
- 개인정보 마스킹 기준이 정리되어 있는가?
- 엑셀 다운로드 기준이 정리되어 있는가?
- 백엔드 Guard와 프론트 권한 조건이 같은 정책을 바라보는가?
- 권한 정책 변경 시 문서와 코드가 함께 수정되는가?
✅ 23. AI를 활용해 권한 기반 UI를 설계할 때 질문법
- AI에게 권한 기반 UI를 설계시킬 때는 역할, 권한, 메뉴, 버튼, 데이터 범위, 개인정보 표시 기준, 백엔드 권한 검사 여부를 함께 알려줘야 합니다.
- “권한 처리 어떻게 해?”라고만 하면 너무 일반적인 답변이 나옵니다.
➕ 23-1. 좋은 질문 예시
React + TanStack Query 기반 관리자 페이지에서 권한 기반 UI와 라우팅 보호를 설계하고 싶어.
상황:
1. 관리자 역할은 SUPER_ADMIN, ADMIN, MANAGER, MARKETER, VIEWER가 있음
2. 권한은 CONSULT_READ, CONSULT_UPDATE, CONSULT_EXPORT, PRODUCT_UPDATE, BANNER_UPDATE, ADMIN_MANAGE가 있음
3. 로그인 후 me API에서 role과 permissions를 가져옴
4. 상담 관리, 주문 관리, 상품 관리, 배너 관리, 관리자 관리 메뉴가 있음
5. VIEWER는 조회만 가능하고 상태 변경/엑셀 다운로드는 불가
6. MARKETER는 유입 통계는 볼 수 있지만 개인정보는 마스킹되어야 함
7. 엑셀 다운로드는 별도 권한이 필요하고 Confirm을 띄워야 함
8. 권한 없는 페이지 접근 시 ForbiddenPage를 보여주고 싶음
9. 실제 보안은 백엔드 Guard에서 다시 검사함
요청:
- me API 기반 권한 상태 관리
- useMe hook 구조
- hasPermission/hasRole 유틸
- 메뉴 노출 기준
- 버튼 노출/disabled 기준
- ProtectedRoute 구조
- 401/403 처리 기준
- 개인정보 마스킹 UI 기준
- 엑셀 다운로드 권한 UX
- 권한 정책 문서 템플릿
을 실무 기준으로 정리해줘.
➕ 23-2. AI 답변 검증 기준
- 프론트 버튼 숨김을 실제 보안으로 착각하지 않는가?
- 백엔드 권한 검사를 반드시 언급하는가?
- 로그인 여부와 권한 여부를 구분하는가?
- Role과 Permission의 차이를 설명하는가?
- 메뉴, 페이지, 버튼, 데이터 범위를 나눠서 설계하는가?
- 개인정보 마스킹을 백엔드 응답 기준으로 처리하라고 하는가?
- 401과 403 UI 처리를 구분하는가?
- 현재 서비스 규모에 맞게 과하게 복잡하지 않은가?
📌 요약
- 프론트엔드 권한 처리는 로그인한 관리자 역할과 권한에 따라 메뉴, 페이지, 버튼, 데이터 표시를 다르게 보여주는 작업입니다.
- 인증은 사용자가 누구인지 확인하는 것이고, 인가는 그 사용자가 특정 기능이나 데이터에 접근할 수 있는지 판단하는 것입니다.
- 작은 서비스는 Role 기반으로 시작해도 되지만, 엑셀 다운로드, 관리자 계정 관리, 개인정보 표시처럼 위험한 기능은 Permission으로 분리하는 것이 좋습니다.
- 로그인한 관리자 정보는
me API로 조회하고, useMe hook으로 감싸서 메뉴, 버튼, 페이지 보호에서 재사용하면 좋습니다.
- 메뉴와 버튼은 권한에 따라 숨기거나 비활성화할 수 있지만, 실제 보안은 백엔드 Guard/API 권한 검사에서 반드시 처리해야 합니다.
- 권한 없는 페이지 접근은 ForbiddenPage로 안내하고, 로그인 만료인 401과 권한 부족인 403은 UI 처리를 구분해야 합니다.
- 데이터 범위도 권한의 일부입니다. MANAGER는 담당 건만 보고, MARKETER는 마스킹된 통계만 보는 식으로 설계할 수 있습니다.
- 개인정보 마스킹은 프론트에서만 처리하면 네트워크 응답에 원본이 남기 때문에, 백엔드가 권한에 맞게 마스킹된 값을 내려주는 것이 안전합니다.
- 엑셀 다운로드는 목록 조회보다 더 위험한 기능이므로 별도 권한, Confirm, 작업 이력 저장이 필요합니다.
- 권한 정책은 코드뿐 아니라 역할별 권한 표, 개인정보 표시 기준, 엑셀 다운로드 기준까지 문서화해야 운영 중 혼란을 줄일 수 있습니다.