개발자로 후회없는 삶 살기
캡스톤 디자인 PART.JWT 관리자 정책 변경 본문
서론
기존에 사용하던 JWT 정책이 변경되었고 다양한 정보를 JWT에 넣기로 했습니다. 그 과정을 기록합니다.
본론
- 관리자 권한 추가
@Enumerated(EnumType.STRING)
@Column(name = "roletype", length = 255, nullable = false)
private RoleType roleType;
학과 홈페이지 관리를 하는 관리자 분들은 관리자만의 기능을 수행할 수 있어야 합니다. 따라서 로그인 한 사용자가 권리자 권한이 있는지 없는지 검증하는 과정이 필요했습니다.
로직을 어떻게 할까? ✅
인터셉터를 사용해서 관리자가 아닌 학생이 관리자로 요청을 하면 바로 막아버리면 좋을 것 같다고 생각했습니다.
-> 1차 기존 인터셉터
그렇게 처음 만든 인터셉터는 위와 같습니다. 기존 JWT에는 학생 PK만 있어서 payload에서 id를 찾고 db에 검색해서 roleType을 검증하면 되겠다고 생각했습니다.
하지만 이 방식은 큰 문제가 있습니다. 🚨
이렇게 되면 모든 요청에 DB에 find하는 명령이 들어갑니다. 매 요청 마다 DB를 접근하게 되면 굉장한 부하가 발생할 것입니다.
-> 해결방식
토큰에 관리자인지 학생인지 정보를 추가합니다. 사실 토큰이나 세션은 로그아웃 하기 전에 계속 사용할 데이터인데 추가로 DB에서 가져올 필요까지는 없는 데이터를 저장할 용도도 있습니다. 지금같은 DB에 접근하기에는 애매한데 매 요청마다 그리고 로그아웃 하기 전까지 계속 필요한 데이터인 관리자 권한을 토큰에 저장하면 아주 좋을 것입니다!
- JWT PayLoad 추가
기존 access 토큰을 만드는 로직은 String으로 pk id를 받아서 subject로 넣는 것만 있었습니다.
private TokenResponseDto issueTokenDto(Long studentId, RoleType roleType) {
Map<String, Object> payload = createPayloadMap(studentId, roleType);
String accessToken = jwtTokenProvider.createToken(payload);
}
private Map<String, Object> createPayloadMap(Long studentId, RoleType roleType) {
Map<String, Object> payload = JwtTokenProvider.payloadBuilder()
.setSubject(String.valueOf(studentId))
.put(roleType.name())
.build();
return payload;
}
이제는 토큰에 저장할 PayloadMap을 만들고 id를 subject로 하고 로그인한 학생의 role을 put 하여 body에 저장합니다. 이렇게 하면 이후에 다른 정책이 추가되더라고 Map만 고치면 토큰에 다양한 정보를 추가할 수 있을 것입니다.
최종적으로 createToken 메서드에서 Map을 받고
accessToken을 만들 수 있습니다.
-> getRolePayLoad
public String getPayload(final String token) {
return tokenToJws(token)
.getBody()
.getSubject();
}
기존에는 getPayLoad로 로그인된 사용자인지 인증하기 위해 토큰에서 id를 꺼내는 getSubject 메서드가 있었습니다.
public String getRolePayload(final String token) {
return tokenToJws(token)
.getBody()
.get("role")
.toString();
}
이제는 토큰에서 role을 꺼내서 관리자 권한이 있는 유저인지 체크할 것입니다.
- 2차 최종 인터셉터
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
final String token = AuthorizationExtractor.extract(request);
String rolePayload = jwtTokenProvider.getRolePayload(token);
validateRoleType(rolePayload);
return true;
}
private static void validateRoleType(String rolePayload) {
if (RoleType.ADMIN != RoleType.valueOf(rolePayload)) {
throw new InvalidRoleTypeException();
}
}
바뀐 정책으로 인터셉터를 수정합니다. 토큰에서 role을 꺼내고 검증하여 DB에 접근하는 로직이 사라졌습니다.
-> 인터셉터 테스트
학생 권한으로 로그인 후
관리자 권한이 필요한 요청을 하면 관리자 권한이 없다고 예외가 발생합니다.
결론
이렇게 DB에 접근하던 로직을 없애고 토큰에 권한을 저장하였습니다. 실제 학생들이 사용할 서비스인데 매번 db에 find 했으면 과부하로 성능 문제가 있었을 것입니다. 이를 토큰으로 해결했고 토큰의 목적을 조금 더 확실히 이해하는 계기가 되었습니다.
'[대외활동] > [캡스톤 디자인]' 카테고리의 다른 글
[최적화] 졸업자 전체 조회 JPA 쿼리 튜닝 (0) | 2024.03.17 |
---|---|
[보안] RefreshToken, Redis 도입으로 성능 개선 및 탈취 당한 AccessToken 문제 방지 (0) | 2024.01.23 |
[보안] Jwt를 이용한 클라이언트 권한 인가 구현 (0) | 2023.08.02 |
캡스톤 디자인 PART.스프링 & 리액트 프로젝트 연동 (0) | 2023.07.22 |
캡스톤 디자인 PART.DB 모델링 변경사항 (0) | 2023.07.11 |