💡 .java를 클릭시 관련 커밋으로 이동💡
/auth/loginPage
state 생성 → state로 url 생성( 인가 코드 요청하여 URL 빌더로 생성 ) → OAuthService의 loginPage 함수를 통해 로그인 페이지 생성후 리턴 → JsonResult로 리턴
@Slf4j
@RequiredArgsConstructor
@RequestMapping("/auth")
@RestController
public class AuthController {
private final AuthService authService;
private final OAuthService oAuthService;
private final LoginStateService loginStateService;
@ApiResponse(responseCode = "200", description = "로그인페이지 요청 성공", content = @Content(schema = @Schema(implementation = AuthLoginPageResponse.class)))
@GetMapping("/loginPage")
public JsonResult<List<AuthLoginPageResponse>> loginPage() {
String loginState = loginStateService.generateLoginState();
// OAuth 사용하여 각 플랫폼의 로그인 페이지 URL을 가져와서 state 주입
List<AuthLoginPageResponse> loginPages = oAuthService.loginPage(loginState);
return JsonResult.successOf(loginPages);
}
}
- loginStateService를 통해 고유한 loginState를 생성한다. 이 state는 CSRF 공격을 방지하는 데 사용되며, OAuth 인증 요청에 포함된다.
- oAuthService를 사용하여 지원하는 각 OAuth 플랫폼의 로그인 페이지 URL을 가져온다. 이 URL은 각 플랫폼을 통한 인증을 시작할 수 있게 해주며, 각각의 state 값을 포함시킨다.
- 메소드는 JsonResult 형태로 로그인 페이지 URL 목록을 반환한다. 이 클래스는 API 응답을 표준화하는 데 사용된다.
@Slf4j
@Service
@RequiredArgsConstructor
public class LoginStateService {
private final LoginStateRepository loginStateRepository;
// Login State 생성
public String generateLoginState() {
LoginState loginState = LoginState.builder()
.build();
LoginState savedLoginState = loginStateRepository.save(loginState);
log.info(">>>> [ Login State 생성 ] {}", savedLoginState);
return savedLoginState.getState().toString();
}
// Login State 검증
public boolean isValidLoginState(String loginState) {
UUID uuid;
// UUID 형식이 아닐 경우 예외처리
try {
uuid = UUID.fromString(loginState);
} catch (IllegalArgumentException e) {
log.warn(">>>> {} : {}", loginState, ExceptionMessage.LOGINSTATE_INVALID_VALUE);
throw new LoginStateException(ExceptionMessage.LOGINSTATE_INVALID_VALUE);
}
// 객체를 Redis에서 조회후 없는 경우 예외 처리
LoginState findLoginState = loginStateRepository.findById(uuid)
.orElseThrow(() -> {
log.warn(">>>> {} : {}", loginState, ExceptionMessage.LOGINSTATE_NOT_FOUND);
throw new LoginStateException(ExceptionMessage.LOGINSTATE_NOT_FOUND);
});
// 사용한 LoginState는 삭제
loginStateRepository.deleteById(uuid);
return true;
}
}
- 로그인 상태 (LoginState) 객체를 생성하고, 이를 Redis에 저장한다. Redis는 빠른 데이터 접근 속도와 함께 만료 기능을 제공하므로, 로그인 상태를 임시 저장하는 용도로 적합한다.
- 저장된 state는 OAuth 인증 요청에 사용된다.
- 생성된 state를 반환한다.
- 주어진 loginState의 유효성을 검증한다. 이는 UUID 형식을 기준으로 검증하며, 형식에 맞지 않는 경우 IllegalArgumentException을 발생시키고, LoginStateException을 통해 오류를 처리한다.
- Redis에서 state를 조회하여 존재하지 않으면 예외를 발생시키고, 존재한다면 사용 후 삭제한다. 이 과정은 state의 일회성을 보장한다.
@Getter
@ToString
@Builder
@RedisHash(value = "state", timeToLive = 60 * 3) // 3분
public class LoginState {
@Id
private String state; // state 검증
}
public interface LoginStateRepository extends CrudRepository<LoginState, UUID> {
}
1. 실제 state 생성확인
2. state 삭제 주석 추가하여 저장 확인
3. test 로직으로 확인
4. 삭제 확인
테스트
@SpringBootTest
class LoginStateTest {
@Autowired
private LoginStateRepository loginStateRepository;
@AfterEach // 테스트 후 데이터 삭제
void tearDown() {
loginStateRepository.deleteAll();
}
@Test
@DisplayName("LoginState 저장")
void redisLoginStateSave() {
// given
LoginState savedEntity = loginStateRepository.save(LoginState.builder()
.build());
// when
Optional<LoginState> byId = loginStateRepository.findById(UUID.fromString(savedEntity.getState()));
// then
UUID stateAsUUID = UUID.fromString(byId.get().getState());
assertThat(stateAsUUID).isInstanceOf(UUID.class);
}
@Test
@DisplayName("LoginState 삭제")
void redisLoginStateDelete() {
// given
LoginState savedEntity = loginStateRepository.save(LoginState.builder()
.build());
loginStateRepository.deleteById(UUID.fromString(savedEntity.getState()));
// when
Optional<LoginState> findLoginState = loginStateRepository.findById(UUID.fromString(savedEntity.getState()));
// then
assertThat(findLoginState.isEmpty()).isTrue();
}
}
'Project > 깃터디 (gitudy)' 카테고리의 다른 글
[깃터디/Auth] 회원 정보 조회 구현 (0) | 2024.05.10 |
---|---|
[깃터디/Auth] 로그아웃 요청 구현 (0) | 2024.05.10 |
[깃터디/Auth] OAuth2 Login 구현 (0) | 2024.05.10 |
[깃터디] OAuth 2.0 (0) | 2024.05.10 |
[깃터디] JWT Json web token (0) | 2024.05.06 |
댓글