[Spring Cloud로 개발하는 MSA] User Microservice 인증 기능 구현

유호빈·2024년 3월 30일
0

MSA

목록 보기
6/10

인프런의 "Spring Cloud로 개발하는 마이크로서비스" 강의를 보고 작성되었습니다.
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%81%B4%EB%9D%BC%EC%9A%B0%EB%93%9C-%EB%A7%88%EC%9D%B4%ED%81%AC%EB%A1%9C%EC%84%9C%EB%B9%84%EC%8A%A4

이번 강의에는 로그인 기능을 구현하여 로그인하고, 로그인이 완료되면 response 헤더에 json 웹 토큰을 전달합니다. 그리고 이 토큰을 다른 서비스에서 API 호출 시 인증 여부를 확인하는 필터를 구현합니다.

1. 인증과 권한 기능

1) AuthenticationFilter 추가

RequestLogin

로그인 시 입력받는 이메일과 비밀번호를 저장합니다.

AuthenticationFilter

Security로 로그인 요청 시 작업을 처리하는 필터로, UsernamePasswordAuthenticationFilter를 상속받아 attemptAuthentication 메소드를 구현합니다.

로그인 api는 POST 형태로 request 파라미터로 받을 수 없어 request.getInputStream()로 로그인 시 입력한 이메일과 비밀번호로 RequestLogin으로 변환합니다.

UsernamePasswordAuthenticationtoken 으로 변경하여 AuthenticationManager에 인증 작업 처리를 요청합니다.

2) WebSecurity 수정

  • http.addFilter(getAuthenticationFilter(authenticationManager));

이 부분에서 사용자 요청에 대해 AuthenticationFilter를 거치도록 추가해줍니다.

  • AuthenticationManager 등록 시 UserDetailsService를 구현한 객체와 Password 인코딩에 사용한 passwordEncoder를 등록합니다.

UserDetailsService 의 loadUserByUsername을 통해 사용자가 입력한 name (프로젝트에서는 이메일), 비밀번호로 로그인 시 인증을 처리합니다.
이때, DB에 저장된 EncryptedPassword와 로그인 시 입력한 비밀번호를 encode 하여 비교합니다.

3) jwt 정보 application.yml에 추가

jwt에 사용할 토큰의 유효 시간 등의 정보를 application.yml에 추가하고 Environment 혹은 @Value로 사용합니다.

4) UserDetailsService

Security 설정에서 userDetailsService를 등록하기 위해 UserDetailsService 인터페이스를 구현합니다.

UserServiceImpl에서 loadUserByUsername() 메소드를 구현합니다.

findByEmail을 통해 DB에서 저장된 데이터를 가져와 Spring Security의 User 객체를 생성합니다. User객체는 입력 받은 사용자의 정보와 비교하는 데 사용됩니다.

2. routes 정보 변경

Gateway application.yml 수정

지금까지는 /user-service/** 의 Path로 api를 호출하면 user-service 에서 모든 Path를 포함하여 uri가 매핑되었는데, filters의 RewritePath를 통해 user-service를 지우고 뒤의 패턴만 전달될 수 있도록 변경 했습니다.

User Service Controller 변경

다음과 같이 RequestMapping 의 uri에서 /user-service가 삭제 가능합니다.

Postman 회원가입, 로그인

8000번 포트의 gateway를 사용해서 회원가입과 로그인이 잘 동작하는 모습입니다.

3. 로그인 처리 과정

1) 흐름

  1. 사용자가 로그인 요청 - 아이디와 비밀번호 입력

  2. AuthenticationFilter에서 처리 - UsernamePasswordAuthenticationToken 형태로 변경

  3. UserDetailsService를 구현한 클래스에서 loadUserByUsername 메소드 실행

  4. Repository에서 DB에 접근해 entity를 가져와 Security의 User 객체로 변경

  5. 인증이 성공적으로 완료되면 AuthenticationFilter의 successfulAuthentication 메소드 실행 - 이번 프로젝트에서는 이메일로 다시 저장된 유저의 userId 값을 가져와 JWT 생성

  6. 생성된 토큰을 response header 에 저장하여 반환

2) successfulAuthentication - 토큰 추가

AuthenticationFilter에서 인증 요청 완료 시 실행되는 메소드를 구현했습니다.
이때, DB에서 저장된 userId 값을 가져와 토큰에 담아 JWT 토큰을 생성합니다.
생성된 토큰과 userId을 reposnse 헤더에 담아 반환해 줍니다.

Postman을 통해 확인하면 응답 헤더에 token 과 userId 값을 확인할 수 있습니다.

4. 토큰 처리

1) jwt 방식 장점

전통적인 방식의 인증 시스템

  • 프론트와 백의 서버 간 세션 공유의 어려움
  • 모바일 애플리케이션에서는 세션과 쿠키를 사용하기 어려움

jwt 방식

인증 헤더 Authorization 에 사용

  • 장점
  1. Stateless - 클라이언트와 독립적으로 통신 가능
  2. 캐시 서버와 인증 처리 가능
  3. microservice 서버 간 세션 공유를 따로 하지 않고 토큰으로 공유 가능

2) Gateway에 토큰 처리 추가

Dependency 추가

AuthorizationHeaderFilter 추가

기존 필터와 같이 AbstractGatewayFilter를 상속받아 apply 메소드 를 구현했습니다.

사용자가 요청 시 헤더에 토큰을 담아서 전달하게 되면, Authorization 헤더에서 Bearer {token} 값을 받아 인증을 처리합니다.

isJwtValid 메소드를 작성해 토큰 값 유효성 검사를 진행했습니다.

Routes에 AuthorizationHeaderFilter 추가

로그인과 회원 가입 시에는 토큰 인증을 거치지 않아도 되기 때문에 제외하고 나머지 user-service 에서 호출하는 api는 AuthorizationHeaderFilter를 거쳐 인증이 필요하도록 추가했습니다.

Postman test

로그인, 회원 가입이 아닌 api 요청 시 토큰 값을 넣지 않으면 401 에러가 발생합니다.

헤더에 다음과 같이 토큰 값을 넣고 api 요청을 하면 정상적으로 동작하는 모습을 볼 수 있습니다.


profile
시작하자

0개의 댓글