Spring 2주차. 심화과정 lv.2 과제를 진행했다. 저번주에 진행한 블로그 프로젝트에 JWT를 이용한 회원가입과 로그인을 구현하는 과제였는데 구현까지는 쉬운편이었으나 JWT의 정확한 메커니즘은 아직 확실하게는 이해하지 못했다. 오늘 TIL은 프로젝트 진행과정 중 겪은 문제점들을 정리해보겠다.
문제 : 아이디, 비밀번호에 제약조건을 걸어야 한다.
시도 및 해결 :
@Valid로 검색을 해서 해당 내용을 적용 시켜봤으나 처음엔 실패했다.
build.gradle의 dependancies에 @Valid에 관한 내용을 추가시키지 않아서 였다.
implementation 'org.springframework.boot:spring-boot-starter-validation'
을 적용해야 정상적으로 작동한다.
우선 적용은 RequestDto쪽에다 하면 되는데
@Getter
@Setter
public class SignupRequestDto {
@Pattern(regexp = "^[a-z0-9]{4,10}",
message = "유저 이름은 최소 4자 이상, 10자 이하이며 알파벳 소문자와 숫자만 사용해야 합니다.")
private String username;
@Pattern(regexp = "^[a-zA-Z0-9]{8,15}",
message = "비밀번호는 최소 8자 이상, 15자 이하이며 알파벳 대소문자와 숫자만 사용해야 합니다.")
private String password;
}
이런 식으로 @Pattern(regexp="제약조건(정규식)", message="위반시 출력 메세지")
로 구성해서 컬럼 위에다 달면 된다.
그리고 Controller의 변수 앞에다가 @Valid를 추가로 달아줘야 한다.
@PostMapping("/signup")
public MsgResponseDto signup(@RequestBody @Valid SignupRequestDto signupRequestDto) {
return userService.signup(signupRequestDto);
}
문제 : Postman으로 해당 프로젝트 테스트 구동을 하려는데 JWT 토큰을 제대로 인식하지 못했다.
시도 및 해결 : JWT 토큰 validation 과정에서 예외처리가 계속 되어서 해당 메서드를 계속 바꿔 봤으나 실패했다. 그래서 JWT에 대해 좀 더 공부해보니 같은 아이디라도 서버를 켤때마다 JWT 토큰의 값이 계속 바뀐다는 것을 알게되었다.
그래서 로그인시 Response의 Header로 오는 JWT 토큰 Authorization의 value값을 서버를 켤 때 마다 계속 바꿔서 적용하니 해결되었다.
알게된점 : 서버를 껐다 키면 같은 아이디라도 JWT 토큰의 값이 바뀐다. JWT의 값이 변하는 조건을 좀 더 알아보자.
이날 번거로웠던걸 환경변수 설정으로 해결했다.
Postman 오른쪽 구성에 가면 환경변수를 설정하는 곳이 있다.
로그인시 반환되는 JWT 토큰을 계속 복붙할 필요 없이 여기서 변수를 하나 만들고 로그인시 반환되는 토큰을 set as variable
로 설정하고 {{변수이름}}
을 써서 다른 곳에 활용하면 편하게 사용할 수 있다.
Controller에 JWT 적용할 때 파라미터 : 서버가 JWT 줄때는 HttpServletResponse response, 클라이언트가 request로 보낼때는 HttpServletRequest request로 받으면 된다.
Controller에서 파라미터에 @가 생략되어있으면 기본적으로 @ModelAttribute로 받는다.
서버가 JWT를 response에 넘겨 줄 때(login할 때) 반환값과 상관 없이
response.addHeader(JwtUtil.AUTHORIZATION_HEADER, jwtUtil.createToken(user.get().getUsername(), user.get().getRole()));
처럼 resonse.addHeader() 메서드만 실행해서 (key : AUTHORIZATION, value : JWT토큰) 붙여주면 된다.
ERD는 DB관점이다. 객체관점에서 보면 안된다. 상속관계 표현이 안되니 Timestamped같은건 테이블 따로 만들지말고 밑에 붙이는게 맞다.
그리고 DB상에서는 대소문자 구분이 안되니 snake_case로 써야한다.
String은 varchar, localdatetime은 date_time으로 DB에 맞는 용어를 써야 한다.
외래키는 다른 테이블의 기본키를 받아오니까 username이 아니라 userid를 받아온다.
토큰검증메서드처럼 중간에 private 메서드를 만들면 @Transactional은 필요 없다.
API 명세서는 실패한 케이스도 넣어주면 좋다.