정상·오류·권한 결정표
75분 안팎
학습 목표
로그인 여부와 자원 소유자의 조합별 기대 결과를 정합니다.
개념
여러 조건의 우선순위를 드러냅니다
회원 A가 프로필을 수정할 수 있는지 판단할 때 로그인 여부만으로 결과를 정하면 B의 정보까지 바꿀 수 있습니다. 본인 여부만 보면 세션이 만료된 요청을 통과시킬 수 있습니다. 결정표는 여러 조건을 열로 놓고 조합마다 기대 행동을 정하는 도구입니다. 한 조건을 따로 확인하는 테스트와 조건들이 함께 나타나는 테스트를 구별해, 거절 이유와 저장 효과를 빠뜨리지 않도록 돕습니다.
이번 교육용 계약은 authenticated, owner, exists 세 가지 참·거짓 조건을 사용합니다. authenticated는 유효한 인증 상태, owner는 요청자가 대상의 소유자라는 조건, exists는 대상 회원이 있다는 조건입니다. Boolean 세 개의 조합은 여덟 개입니다. 이는 이번 모델의 조합 수이며 실제 제품의 권한 종류를 전부 표현하는 것은 아닙니다. 관리자나 탈퇴 상태가 추가되면 표의 조건과 사례도 다시 검토합니다.
판정 순서도 계약입니다
계약 v2에서 인증이 없으면 나머지 조건과 관계없이 AUTH_REQUIRED를 출력합니다. 인증은 있지만 본인이 아니면 FORBIDDEN입니다. 인증과 본인 조건이 맞지만 대상이 없으면 NOT_FOUND입니다. 세 조건이 모두 맞으면 ALLOW입니다. 이 이름은 설계 연습의 의미 표식이며 HTTP 코드가 아닙니다. 인증되지 않은 요청에 대상 존재 여부를 먼저 노출하지 않는 순서를 이번 예제의 약속으로 사용합니다.
대상이 없는 타인 요청에서 NOT_FOUND와 FORBIDDEN 중 무엇을 먼저 보여 줄지는 제품마다 계약이 필요합니다. 이번 실습은 본인 여부를 앞에 확인한다고 정했으므로 FORBIDDEN입니다. 이 선택을 보편적인 API 설계 규칙으로 암기하지 않습니다. 실제 팀에서 순서가 없으면 보안과 사용자 경험의 영향을 질문으로 남겨 합의합니다. QA가 실행 결과를 본 다음 기대 순서를 바꾸는 것은 독립적인 기준을 잃는 행동입니다.
표에는 000·001·010·011이 AUTH_REQUIRED, 100·101이 FORBIDDEN, 110이 NOT_FOUND, 111이 ALLOW라고 씁니다. 자리 순서는 인증·본인·존재입니다. 숫자가 작다고 중요도가 낮은 것은 아닙니다. 같은 결과의 행을 묶을 때는 결과에 영향을 주지 않는 조건을 대시로 표시할 수 있지만, 처음에는 여덟 행을 펼쳐 우선순위가 제대로 반영되는지 읽습니다.
안내와 데이터 효과를 함께 적습니다
ALLOW 행은 본인 프로필 수정과 재조회 일치를 확인합니다. AUTH_REQUIRED는 로그인 필요 안내와 회원 무변경, FORBIDDEN은 접근 거절과 타인 정보 비노출 및 무변경을 확인합니다. NOT_FOUND는 대상 없음 안내와 새 회원 미생성을 확인합니다. 판정 단어가 맞아도 다른 회원을 바꾸었다면 제품 테스트는 실패입니다. 브라우저의 계산 연습은 판정만 다루지만 미션의 기대 결과에는 화면과 저장 상태를 함께 씁니다.
정상·오류·권한이라는 유형은 사례를 찾기 위한 분류입니다. 권한 거절을 기대했다면 거절은 올바른 제품 결과입니다. 오류 유형이라고 테스트를 실패로 표시하지 않습니다. 설계 단계의 status planned와 나중 실행 단계의 실제 비교 결과를 분리합니다. 유형이 하나라도 존재한다는 검사 결과만으로 거절 조건을 충분히 확인했다고 말할 수는 없습니다. 같은 유형 안에 대상과 인증 상태가 다양하게 포함되는지 사람 리뷰가 필요합니다.
요청자의 A ID와 대상 B ID는 서로 다른 합성 계정으로 명시합니다. target을 바꿨는데 입력 문장에는 계속 본인이라고 적으면 사례가 모순됩니다. 사전 조건에는 A의 유효 세션, B의 존재와 이전 닉네임을 적고 입력에는 대상 B와 변경할 이름을 적습니다. 결과에는 B 닉네임이 이전 값으로 남는다는 비교를 둡니다. 실제 계정의 비밀번호나 토큰을 수집하지 않고 필요한 상태를 합성 자료로 설명합니다.
결정표를 계산 코드로 옮깁니다
브라우저 입력은 [[false,true,true],[true,false,true]]처럼 Boolean 세 개씩 담은 배열입니다. false를 문자열 "false"로 쓰지 않습니다. JavaScript에서 비어 있지 않은 문자열은 조건식에서 참으로 취급될 수 있어 잘못된 판정을 만듭니다. JSON.parse는 JSON 입력을 구조로 읽는 기능이며 뒤 모듈에서 자세히 배웁니다. 지금은 배열의 첫째 값이 인증, 둘째가 본인, 셋째가 존재라는 계약을 보고 판단을 고칩니다.
판정 함수는 앞에서 정한 순서대로 거절 조건을 반환하고 마지막에 ALLOW를 반환합니다. exists를 첫 줄에 놓으면 비인증·없는 대상의 결과가 바뀝니다. 각 조건의 의미가 맞아도 순서가 틀릴 수 있다는 점을 따라하기에서 비교합니다. 입력 배열이 비어 있으면 출력도 없습니다. 한 행을 읽을 때 세 조건과 판정 한 개를 함께 기록하고, 테스트가 실패하면 해당 행의 조합을 먼저 표에서 찾습니다.
SyntaxError와 Unexpected token은 JSON 괄호나 따옴표, 쉼표를 읽지 못한 상황일 수 있습니다. 오류 메시지의 위치를 보고 입력이 JSON인지 확인합니다. 실행은 끝났지만 FORBIDDEN 대신 ALLOW가 나온다면 입력 형식보다는 빠진 권한 분기를 검토합니다. 출력 줄 수가 다르면 행을 하나씩 처리하는 반복 부분을 확인합니다. 서로 다른 원인의 실패를 한꺼번에 권한 결함이라고 기록하지 않습니다.
축소할 때 잃는 범위를 설명합니다
같은 결과의 행을 한 사례로 합치면 실행 비용을 줄일 수 있지만 조건 우선순위 오류를 덜 구별하게 됩니다. 예를 들어 비인증·대상 존재 한 사례만 남기면 비인증·대상 없음에서 정보가 노출되는 분기를 놓칠 수 있습니다. 이번 실습은 여덟 행을 모두 확인하고 미션에 그대로 연결합니다. 이후 위험 기반 선택에서는 제외하는 조합과 그 근거를 기록하며 표 자체를 지우지 않습니다.
가입의 중복 여부와 빈 입력도 결정표 후보가 되지만, 두 문제가 동시에 있을 때 안내 우선순위는 아직 확정하지 않았습니다. 길이 오류만 확인하려는 사례는 이메일을 유효·고유하게 고정합니다. 여러 오류를 한 사례에 묶고 아무 오류나 나오면 통과로 처리하면 규칙 누락을 숨깁니다. 합의된 단일 거절 사례와 미합의 다중 오류 사례를 구분해 리뷰표의 보류 항목에 남깁니다.
완성한 표를 소리 내어 읽으며 인증 실패 행에 타인 데이터가 노출되지 않는지, 타인 행에 저장이 발생하지 않는지 질문합니다. 결과를 맞힌 이유가 현재 구현이 그렇게 출력해서가 아니라 계약의 인증→본인→존재 순서라면 독립적인 기대값이 마련된 것입니다. 함수 문법 자체보다 그 함수가 어떤 표를 표현하는지 설명하는 연습이 이 레슨의 중심입니다.
따라하기
여덟 조합의 표 만들기
인증·본인·존재 순서의 0과 1을 출력합니다. 숫자는 표 표시이고 실습 입력은 Boolean입니다.
for (let n=0;n<8;n++) console.log(n.toString(2).padStart(3,'0'));실행 결과
000 001 010 011 100 101 110 111
판정 순서 구현
인증부터 확인한 판정을 출력합니다. 여덟 행을 직접 작성한 표와 대조합니다.
function decide(a,o,e){if(!a)return 'AUTH_REQUIRED';if(!o)return 'FORBIDDEN';if(!e)return 'NOT_FOUND';return 'ALLOW';}
for(let n=0;n<8;n++){const a=!!(n&4),o=!!(n&2),e=!!(n&1);console.log(n.toString(2).padStart(3,'0'),decide(a,o,e));}실행 결과
000 AUTH_REQUIRED 001 AUTH_REQUIRED 010 AUTH_REQUIRED 011 AUTH_REQUIRED 100 FORBIDDEN 101 FORBIDDEN 110 NOT_FOUND 111 ALLOW
잘못된 우선순위 비교
존재를 먼저 확인하는 함수와 계약 함수의 차이를 한 조합으로 확인합니다.
const a=false,o=false,e=false;
const wrong=!e?'NOT_FOUND':!a?'AUTH_REQUIRED':!o?'FORBIDDEN':'ALLOW';
const agreed=!a?'AUTH_REQUIRED':!o?'FORBIDDEN':!e?'NOT_FOUND':'ALLOW';
console.log('wrong',wrong);console.log('agreed',agreed);실행 결과
wrong NOT_FOUND agreed AUTH_REQUIRED
권한 사례에 상태 관찰 추가
미션 결정표 여덟 행을 채우고 허용에는 본인 수정·재조회, 거절에는 무변경을 적습니다. 타인 요청은 비노출도 확인하며 HTTP 코드는 적지 않습니다.
확인 문제
실습
JSON 배열의 각 행 [authenticated, owner, exists]를 읽습니다. 값은 Boolean입니다. 인증 실패 AUTH_REQUIRED, 타인 FORBIDDEN, 본인이지만 대상 없음 NOT_FOUND, 모두 참 ALLOW 순서로 판정해 한 줄씩 출력합니다. 빈 배열에는 출력하지 않습니다. HTTP 코드를 출력하지 않습니다.
모범 답안
const fs=require('fs');
const rows=JSON.parse(fs.readFileSync(0,'utf8'));
function decide(a,o,e){if(!a)return 'AUTH_REQUIRED';if(!o)return 'FORBIDDEN';if(!e)return 'NOT_FOUND';return 'ALLOW';}
for(const [a,o,e] of rows)console.log(decide(a,o,e));
더 읽기
면접 질문
- 가입 폼의 테스트 조건을 정하는 과정을 설명해 주시면 됩니다.