내 서비스 만드는 삽질기2
front는 react로, 소셜 로그인을 이용한 자체 서비스를 만들어보기로 했다.
react를 빨리 습득하기 위해 ebook의 힘을 빌렸다.
소셜 로그인을 구현하는 겸 시큐리티 공부도 쌓기 위해 인터넷 강의도 함께 했다.(https://inf.run/NWbk)
보통의 react + spring의 flow는 아래의 이미지와 같았다.
하지만 리액트쪽 코드 구현을 최소한으로 하기 위해 나의 소셜 로그인 플로우의 큰 틀은 다음과 같다.
1. backend에서 oauth2 기반 로그인 구현
2. front에서 backend의 oauth2 로그인 호출
3. 로그인 성공 시 front로 redirect
이미지로 도식화하면 아래와 같다.
그리하여 지금까지 만든것
1. Front (react) - google 로그인, todo crud
2. Back (java) - 소셜 로그인 연동, jwt 토큰 생성/검증, todo API
3. Devops - ecr, ecs, codepipe라인을 통한 backend ci/cd
시연 동영상
그리하여 만들어진것
할 것
1. frontend 동작 시 바로 반응하도록 코드 수정
2. refresh 토큰의 위치는 어디에? refresh 어떻게 할 것인지
3. aws에 react ci/cd 작업
4. dev/prod 환경설정 분리
5. 소셜 로그인을 localhost가 아닌 실제 api에서 동작하도록 수정
6. form login 추가
7. 소셜 로그인 추가 (네이버)
어려웠던 것
0. 리액트 익히기
1. cors 설정 (추후 포스팅)
2. 수정api의 method는 patch? put?
3. websecurityconfigureradapter deprecated (https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter 를 참고하여 해결)
4. RESTFUL API SPEC (추후 포스팅)
해결하지 못한 문제
1. aop에서 설정한 Authentication은 controller에서 @AuthenticationPrincipal로 받아지지 않는 이유?
@Around(value = "@annotation(com.nullnull.mybodyrecord.aop.Api)")
public Object execute(ProceedingJoinPoint joinPoint) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
try {
String bearerToken = parseBearerToken(request);
Jws<Claims> jwt = Jwts.parserBuilder().setSigningKey(getSigninKey(SECRET_KEY))
.require("type", JwtTokenTypeEnum.ACCESS.getValue())
.build().parseClaimsJws(bearerToken);
Long idx = Long.parseLong(jwt.getBody().getSubject());
// SecurityContext emptyContext = SecurityContextHolder.createEmptyContext();
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(idx, null, AuthorityUtils.NO_AUTHORITIES);
// authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
// emptyContext.setAuthentication(authentication);
// SecurityContextHolder.setContext(emptyContext);
request.setAttribute("userIdx", idx);
return joinPoint.proceed();
} catch (ExpiredJwtException e){
throw new UnauthorizedException("로그인이 만료되었습니다.");
} catch (Exception e){
throw new RuntimeException(e);
}
}
위 aop에서 setAttribute한 userIdx는 Controller에서 가져와지지만 주석처리한 코드처럼 SecurityContextHolder에 set한 authentication 객체는 @AuthenticationPrincipal annotation으로 불러와지지 않았다.. 무엇이 문제인지 아직 탐색중