티스토리 뷰

이번 포스팅에서는 완성된 예제를 가지고 하나하나 돌려보면서 동작과정을 알아보겠다.

완성된 예제는 깃허브링크에 있어 동작과정에서 놓친 코드가 있다면 참고하자. 

그리고 꼭 코드를 구현하고 어떻게 동작되는건지 이해가 가지 않을 때 이 포스팅을 참고하는 것이 좋다.

코드를 구현하는 포스팅은 여기로 가면 된다.

 

먼저 회원가입이다. 

 

localhost:8080/member/join에서 이메일과 닉네임, 나이, 비밀번호를 입력한다. 

Send를 누르면 만들어놓은 컨트롤러에서 저장을 한다. 

 

 

서비스로직은 다음과 같다.

 

 

먼저 Postman에서 요청한 DTO중에 이메일을 findByEmail로 DB에 비어있는지 확인한다.

비어있지 않다면 이미 가입한 계정이라는 뜻이기 때문에, 또 가입할 수 없게 처리한 것이다. 그리고 이메일은 고유한 값이어야 한다. 

비어있다면 저장한 후 USER권한을 주고 비밀번호를 암호화시킨다. 

한번 DB를 확인해보자.

 

 

값이 잘 저장된것을 볼 수 있다.

아직까진 스프링시큐리티가 관여하지 않았기 때문에 쉽게 이해할 수 있을 것이다.

다음으로 로그인이다. Postman에서 로그인 요청을 해보자. 

 

 

로그인은 이메일과 비밀번호를 입력한다.

Send를 누르면 역시 컨트롤러를 타고 갈까 ? 그렇지 않다. 

컨트롤러에 도착하기 전에 AuthenticationFilter가 요청 데이터를 가로챈다. 여기서부터 Spring Security가 동작한다. 

자세한 내용은 동작과정 포스팅을 참고하자. 

 

Spring Security 동작과정을 다 거치고 컨트롤러에 도착하게 된다. 

 

 

서비스로직은 다음과 같다.

 

 

먼저 로그인요청한 아이디가 DB에 있는지 확인한다. 만약 없다면 회원가입하지 않은 이메일입니다. 라는 예외를 날린다. 

그리고 로그인요청한 비밀번호와 DB에 있는 비밀번호를 확인한다. 

 

 

만약 이메일과 비밀번호가 같다면, 토큰을 생성해 반환한다. 

 

 

토큰을 생성할 때 잘 보자. 

 

member.getUsername은 이메일을 리턴한다. 

 

 

그리고 member.getRole().name()은 권한을 리턴한다. 

 

 

그럼 createToken을 자세히 봐보자.

 

 

먼저 클레임이라는 변수에 로그인 때 요청한 이메일과 권한을 넣어주었다. 

아까 로그인 요청한 데이터로 예를 들자면 email = test@gmail.com, role = ROLE_USER인 것이다. 

그리고 토큰을 발급한 시간과 유효시간, 어떤 암호화 알고리즘을 사용했는지를 넣어준다. 실제로 발급받은 토큰을 복호화시키면 다음과 같다. 

 

 

이렇게 로그인을 하고 한번 게시판 작성을 해보자. 

 

 

요청할 때 헤더에 토큰을 넣어주자. 

 

 

이렇게 하고 Send를 누르게 되면,

해당 컨트롤러로 가기 전에 제일 먼저 직접 커스텀한 JwtAuthenticationFilter가 가로챈다.

Spring Security는 분명 AuthenticationFilter가 제일 먼저 가로챈다 했는데 어떻게 된 일일까?

Spring Security는 기본적으로 쿠키 - 세션 방식을 지원하고 있지만 우리는 토큰을 이용할 것이기 때문에 AuthenticationFilter(실제로는 UsernamePasswordAuthenticationFilter) 보다 앞에 놔둔다. 

 

 

이렇게 해서 JwtAuthenticationFilter가 실행되는 것이다. 

그럼 JwtAuthenticationFilter를 자세하게 봐보자.

 

 

처음배울 때 doFilter와 doFilterInternal 차이가 헷갈려서 어려워했다.

차이는 doFilter는 파라미터의 request 자료형이 HttpServletRequest가 아닌것 밖에 모르겠는데, doFilter는 resolveToken을 통해 헤더에서 토큰값을 들고올 때 강제 형 변경을 해줘야 한다. 그래서 doFilter가 아닌 doFilterInternal을 사용하였다.

 

 

먼저 resolveToken을 통해 토큰을 들고 온다. (HttpServletRequest는 요청한 데이터이다)

 

 

resolveToken은 요청한 헤더에서 토큰을 꺼내오는 메서드이다. 

 

 

헤더에서 꺼내온 토큰을 가지고 유효성 검사를 진행한다. 

 

 

대충 만료시간이 다되었는지 확인하는 코드이다. 

 

 

이렇게 유효한 토큰이라면 Authentication객체를 생성해 토큰을 넣고 SecurityContext객체 안에 보관한다. 이 점은 기존 Spring Security와 똑같은 방식이다. 

 

 

getAuthentication 메서드를 자세히 보면 우리가 이전에 직접 구현한 customUserDetailsService에 토큰에 담겨있는 이메일을 파라미터로 넣어준다. 

 

 

getUserEmail은 토큰을 파싱해서 이메일을 반환하는 메서드이다. 

 

 

그렇게 토큰에서 받은 이메일로 DB에서 똑같은 이메일이 있는지 확인하고, 있으면 UserDetails 형태로 반환한다. 

UserDetails 형태로 반환하는 이유는 Spring Security는 UserDetails 객체를 통해 유저정보와 권한을 관리하기 때문이다.

Member는 UserDetails를 상속받았기 때문에 반환객체로 Member을 사용해도 상관없다. UserDetails의 구현체가 Member이기 때문이다. 

 

이렇게 해서 총 3가지를 반환하는데, 바로 아이디, 비밀번호, 권한이다. 

왜 비밀번호는 빈 값으로 하는 것일까 ? 처음 배울 때 loadUserByUsername을 보면서 의문점을 생각하면, 왜 비밀번호는 비교하지 않는거지 ? 였다. 비밀번호는 Spring Security에서 알아서 다 처리해준다고 한다. 

 

또 한가지 의문점이 있다.. SecurityContextHolder에 왜 담는지 모르겠다. 이 방식은 세션 방식인데, 토큰 방식에 사용하지 않을 SecurityContextHolder에 왜 넣는지 모르겠다. 나중에 한 번 알아봐야겠다. 

 

어쨋든, 이렇게 해서 회원가입과 로그인 동작 방식을 알아보았다. 

다음에는 더 확실하게 알고 써야겠다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday