7. 토큰 인증으로 클래스 진입하기
받은 토큰으로 클래스에 들어가보자.
채점 기준은 각 클래스마다 다를 것이다.
따라서 우리는 한 과제 당 한 클래스로 간주하고 생성하도록 했다.
각 클래스를 생성하고 채점 기준까지 작성하면 토큰이 생성되는데,
학생 입장에서 그 토큰으로 클래스에 들어가도록 하려면 어떻게 해야 할까?
토큰 입력 페이지는 이미 있다
그렇다면 토큰을 받아 이게 실제로 있는 토큰인지 검사하는 컴포넌트가 필요하다.
이 토큰이 있다면 해당 클래스로 이동시키고, 없다면 Home으로 리다이렉트하는 방법을 선택했다.
// file: 'index.d.ts'
export interface ClassroomProps {
token: string,
className: string,
instructor: string,
createDate: string,
}
// file: 'SectionClass.tsx'
function SectionClass(props: RouteComponentProps<RouteParamsProps>) {
...
const initial = {
token: "",
className: "",
instructor: "",
createDate: "",
};
const [classroom, setClassroom] = useState(initial);
const [valid, setValid] = useState(false);
useEffect(() => {
if (classroom === initial) {
const currentClassroomState = async (): Promise<ClassroomProps[]> => {
return await axios.get<ClassroomProps[]>('/api/token/')
.then((response) => {
return response.data
});
};
currentClassroomState()
.then(response => {
setClassroom(response.find(element => element.token === props.match.params.token) || initial);
if (response.find(element => element.token === props.match.params.token) === undefined) {
props.history.push('/');
alert("클래스가 없습니다.😅");
} else {
setValid(true);
}
})
.catch(response => {
props.history.push('/error');
})
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[classroom]);
...
classroom
상수를 hook으로 관리하도록 선언한다. 이 때 initial
로 초기화한다.
백엔드와 통신하여 index.d.ts
파일에서 정의한 ClassroomProps
인터페이스에 맞는 객체 배열을 가지고 온다.
currentClassroomState
함수는 axios.get
함수 실행 후 response.data
를 리턴한다.
이 함수를 실행시켜 나온 결과를 뒤져 이 페이지에 진입하기 위해 입력한 토큰이 있는지 찾는다.
response
가 ClassroomProps
배열이므로 find
함수를 통해 props
에서 가져온 토큰과 일치하는 것이 있는지 확인한다.
만약 없으면 (= undefined
라면) Home으로 리다이렉트시키며, 갑자기 이동되어 당황한 사용자를 위해 alert
를 표시한다.
있다면, valid
를 업데이트해 이후 컴포넌트를 렌더링한다.
클래스룸에서 어떤 기능이 필요할까?
이제 정상적으로 배포된 토큰을 입력하여 클래스룸에 진입했다.
그럼 학생들은 여기서 뭘 할까?
당연히 소스 파일을 넣어 채점을 하려고 할 것이다.
이전에 만들어 놓았덙 파일 전송 컴포넌트가 여기서 쓰이는 것!
// file: 'SectionClass.tsx'
return (
<>
<AppBar position="fixed" style= >
<Toolbar className={classesStyle.toolbar}>
<Link
variant="h3"
underline="none"
color="inherit"
className={classesStyle.title}
href="/"
>
<img src="/assets/logo.png" alt="logo" className={classesStyle.logo} />
</Link>
</Toolbar>
</AppBar>
<SectionLayout backgroundClassName={classesStyle.background} classes={classesLayout}>
{}
<img style= src={backgroundImage} alt="prioirty" />
<Typographic color="inherit" align="center" variant="h2" marked="center" className={classesStyle.h2}>
{classroom.className}
</Typographic>
<Typographic color="inherit" align="center" variant="h5" className={classesStyle.h5}>
opened by <b>{classroom.instructor}</b> on {classroom.createDate}
</Typographic>
<TextField
value={studentID}
onChange={handleChange}
label="학번"
variant="outlined"
style=
placeholder="학번 입력"
margin="normal"
/>
{valid &&
<FileTransfer name={classroom.token} id={studentID} onCreate={handleCreate} />
}
</SectionLayout>
<AppFooter />
</>
);
기존에는 다른 컴포넌트와 같이 Appbar
를 집어넣었는데, 뭔가 차별화를 주고 싶어서 투명하게 한 다음 로고를 왼쪽 상단에 집어넣었다.
로고는 Home으로 이동되도록 Link
컴포넌트를 걸어 주었는데, 훨씬 보기 편하다✨
정상적으로 진입한 클래스룸은 ClassroomProps
에 있는 정보가 다 있을 것이다.
타이틀로 클래스룸의 제목, 개설자 이름과 개설 날짜를 표시하여 학생들이 확인할 수 있도록 했다.
그 다음, 어떤 학생이 채점을 시도했는지 확인하기 위해 학번 입력 TextField
를 만들었고, 이는 채점 시 백엔드로 넘겨줄 것이다.
이전에 업데이트 해줬던 valid
를 이용해 파일 전송 컴포넌트 FileTransfer
를 렌더링하고
백엔드에 넘겨줄 parameter
를 위해 학번과 토큰을 넘겨준다.
채점이 됐을 때, 또는 실패했을 때를 알기 위해 onCreate
핸들링 함수 또한 넘겨줘야 한다.
그럼 이 핸들링 함수를 적절히 선언해보자.
// file: 'SectionClass.tsx'
...
const handleCreate = (status: boolean, grading: Object) => {
if (!status)
props.history.push('/error');
else
props.history.push({
pathname: `${props.match.url}/success`,
state: { detail: grading },
});
}
...
status
매개변수는 채점이 성공적으로 완료되었는지, 아니면 서버 상 오류가 있는지 확인하기 위한 것이다.
이 status
가 false
면 에러 페이지로 리다이렉트 되도록 했다.
채점이 성공적이었다면, 결과 페이지로 이동시키며, 채점 성적을 detail
로 넘겨준다.
이것이 우리가 SectionClass
의 props
로 RouteComponentProps<RouteParamsProps>
타입을 선언해준 이유다!
🔥 사실 이 부분을 찾기가 힘들었는데, props
를 단순히 어디로 이동시켜주는 건 상관없지만
state
에 매개변수를 같이 넘겨주려면 필요했다. 기억할 것!!
🔥 TroubleShooting & Review
Issue:
- 컴포넌트에서 매개변수와 핸들링 함수를 넘겨주는 건 익숙하지만
Route
를 이용해 매개변수까지 넘겨주는 것은 처음이었다. 채점 결과가 JSON 형식의 객체인데, 라우트를 통해 같이 넘겨줄 수 있다는 게 굉장히 신기하고 편하다!
Review
currentClassroomState
에서 작성한 코드가 조금 더러운 것 같다.find
를 두 번 해놨는데, 좀 더 깔끔하게 고쳐야겠다…- 이슈 등록해 놓은 사항이지만, reCAPTCHA 추가해야겠다.