OAuth(Open Authorization)란 표준 인증 프로토콜로 사용자들이 특정 플랫폼에 있는 자신의 정보에 대해 접근 권한을 부여하는 수단으로 사용이 된다.

 

사용자 인증(Authentication) 처리를 카카오, 네이버, 구글과 같이 OAuth 로그인 API를 제공하는 대형 서비스에게 맡기고 필요한 권한(Authorization)을 사용자 동의를 통해 받아서 필요한 Resource를 받아오는 것이다.

 

 

SecurityConfig

 

 

이전에는 스프링 시큐리티 설정을 WebSecurityConfigurerAdapter의 configure()로 했었지만 현재는 deprecated 되어서 SecurityFilterChain을 Bean으로 등록해야 한다.

 

oauth2Login() 밑에 부분을 보면 userService()에 CustomOAuth2UserService를 등록하는데 이는 함수형 인터페이스인 OAuth2UserService의 loadUser() 메서드를 구현한 것으로 로그인 성공 이후 Access Token을 이용해서 유저 정보(resource owner)를 받아서 OAuth2User(AuthenticatedPrincipal)를 반환한다.

 

 

CustomOAuth2UserService

 

 

사용자가 성공적으로 인증이 되면 OAuth2User에는 GrantedAutority Set이 포함되어 있는데 이 GrantedAuthority 컬렉션은 반환할 OAuth2AuthenticationToken에 매핑하는데 사용 될 수 있다.

 

매핑 옵션으로는 GrantedAuthoritiesMapper 또는 OAuth2UserService를 사용한 Delegation-based 전략이 있는데 후자의 경우 OAuth2UserRequest 및 OAuth2User에 대한 액세스를 제공하기 때문에 더 유연하고 향상된 방법이라고 한다. 나는 DefaultOAuth2UserService(표준 OAuth 2.0 공급자를 지원하는 OAuth2UserService의 구현)를 사용하였다.

 

DefaultOAuth2UserService 생성자를 통해 userRequest로 OAuth2User를 가져오고 Attributes 정보로 User Entity를 조회(기존 회원)하여 가져오거나 저장(새로운 회원)한다.

 

UserNameAttributeName()은 키 값으로 카카오의 경우 id가 된다

 

 

마지막으로 OAuth2User(AuthenticatedPrincipal)를 생성하여 반환한다.

 

 

아래는 전체적인 순서도와 내부적으로 어떻게 처리가 되는지 정리를 해봤다.

 

순서도

 

 

먼저 로그인을 누르면 프론트에서 "/oauth2/authorization/kakao"로 요청을 보내고 OAuth2AuthorizationRequestRedirectFilter는 기본 경로로 받아서 yml 파일에 정의해둔 authorization url로 요청을 보낸다. 

이때 앱의 Rest API 키 값인 client_id랑 Authorization Code를 받을 redirect_url, response_type을 같이 보내는데 이 정보는 yml 파일에 저장을 해놓는다.

 

참고로 스프링 시큐리티가 yml 파일을 읽어서 OAuth2ClientProperties를 생성하고 ClientRegistration 객체(kakao, google, naver ..)를 생성해서 InMemoryClientRegistrationRepository에 저장한다. 

 

 

위에서 말한 OAuth2AuthorizationRequestRedirectFilter는 OAuth2AUthorizationRequestResolver의 resolve()를 호출하는데 로그인 요청 URL에서 registrationId를 확인하고 InMemoryClientRegistrationRepository에서 ClientRegistration 객체를 꺼내 OAuth2AuthorizagtionRequest 객체를 만든다.

 

 

그리고 OAuth2AuthorizationRequest를 받아서 redirect를 보내면 카카오 로그인 창이 뜨게 되는 것이다.

 

 

 

사용자가 카카오 로그인 인증을 성공하면 카카오 서버에서는 위에서 요청시 보낸 redirect_url로 인가 코드(Authorization Code)를 보내기 때문에 OAuth2LoginAuthenticationFilter의 기본 경로에 맞춰서 redirect_url을 yml 파일에 정의해두었다.

 

 

 

OAuth2LoginAuthenticationFilter도 OAuth2AuthorizationRequestRedirectFilter처럼 registrationId를 통해 ClientRegistation을 가져오고 Authorization Code를 사용해서 Access Token을 가져온다.

 

OAuth2LoginAuthenticationProvider는 authenticate() 메서드를 실행하여 Access Token을 받고 loadUser 메서드를 통해 유저 정보를 가져오는 처리까지 하는데 이때 loadUser()를 실행하는 UserService가 처음에 SecuriryConfig에서 userService()에 주입해준  CustomUserService가 된다.

 

 

다음에는 JWT를 발급하는 부분을 처리해봐야겠다.

 

 

[참고]

 

OAuth2 :: Spring Security

Spring Security provides comprehensive OAuth 2 support. This section discusses how to integrate OAuth 2 into your servlet based application.

docs.spring.io

 

[OAuth + Spring Boot + JWT] 2. 스프링 시큐리티로 OAuth 구현해보기

이번에는 \[OAuth + Spring Boot + JWT] 1. OAuth란? 프론트엔드와 백엔드의 역할 마지막에 설명한 구조를 스프링 시큐리티 없이 구현하기 앞서 스프링 시큐리티를 사용해서 oauth를 구현해보려고 한다.👀

velog.io

 

[Spring Boot] OAuth2 + JWT + React 적용해보리기

오늘 팀원이랑 이야기를 해보다가 우려했던 일이 벌어졌다.. 우려했던 일이란?우려했던 일(현재 문제점)개선 방안OAuth2란?With Spring Boot구현현재까지 구현되었던 프로젝트의 로그인과정을 살펴보

velog.io

 

 이전에 Swagger로 API 문서를 만들어봤는데 UI도 예쁘게 만들어주고 API 테스트도 해볼 수 있어서 편리하게 사용했었다.

 

 

 

[SpringFox] Swagger3.0 사용하기 1 (Spring Security, JWT)

Swagger란 REST API를 문서화하여 보기 편하게 시각화하고, 테스트할 수 있는 라이브러리로 서버 가동시 @RestController를 읽어서 API 분석을 해서 HTML로 문서화를 하기 때문에 API 문서를 직접 만들어서

treecode.tistory.com

 

 

하지만 컨트롤러에 설정 코드가 많이 들어가고 동기화가 되지 않는 단점이 있어서 이번에는 Spring Rest Docs를 공부해서 적용을 해보았다.

 

Asciidoctor로 만든 문서와 Spring MVC Test로 생성된 AsciiDoc 스니펫을 결합하여 API 문서(HTML)를 만든다고 나와있는데 원하는 경우 Markdown을 사용하도록 Spring REST Docs를 구성할 수도 있다고 한다.

 

1. 설정


 

Asciidoctor Plugin

*.adoc으로 생성된 asciidoc 파일을 html로 변환해주는 플러그인, 처음에 "org.asciidoctor.convert" 를 사용했다가 오류가 떠서 확인해보니 Gradle 7 부터는 "org.asciidoctor.jvm.convert"를 사용한다고 한다.

그리고 asciidoctorExtensions 설정도 추가해준다.

 

 

snippetsDir에 테스트 빌드로 생성되는(outputs) 스니펫들이 저장될 위치를 지정해준다.

 

dependsOn은 해당 작업에 의존한다는 의미로 bootJar를 실행하면 asciidoctor가 먼저 실행이 된다. 그리고 finalizedBy는 후행 작업을 명시하는 것으로 마지막에 build/docs/asciidoc/ 에 생성된 html 파일을 static 경로에 복사한다.

 

블로그 보면서 해보다가 설정 안 맞아서 고생했는데 블로그 글을 쓰면서 공식 문서를 살펴보니 다시 한번 공식 문서의 중요성을 느끼게 된다.

 

 

 

 

2. 테스트 코드


 

@AutoConfigureRestDocs 애노테이션으로 Rest Docs 여러 설정을 간편하게 할 수 있다.

 

우선 순위에 따라 @AutoConfigureRestDocs(), OperationRequestPreprocessor로 url 설정을 할 수 있다.

 

MockMvc, Rest Assured 등으로 테스트를 작성하면 되는데 API 명세를 ResourceSnippetParameters builder()로 만든다,

 

 

3. 결과


 

퀄리티는 만들기 나름이라고 하는데.. Swagger를 썼을 때의 UI에 비하면 아주 심심한 화면이다. 그래서 더 괜찮은 방법이 없나 찾아보다가 Rest Docs랑 Swagger UI를 결합하는 방식을 소개하는 글을 발견해서 결국 해당 방식으로 변경을 했다!

이거에 대한 정리는 다음에 이어서 해야겠다.

 

 

 

[참고]

 

 

나의 첫 SpringRestDocs 적용기 part 1

※ 모든 코드는 저의 Github 에서 확인하실 수 있습니다. 0. 코드로 말합니다. 개발업무에 있어 형상관리업무만큼은 지극히 최소한으로 유지하는 게 좋다고 생각합니다. 과거엔 코드를 유지보수할

ahndy84.tistory.com

 

API 문서 자동화 - Spring REST Docs 팔아보겠습니다

프로덕션 코드와 분리하여 문서 자동화를 하고 싶다고요? 신뢰도 높은 API 문서를 만들고 싶다고요? 테스트가 성공해야 문서를 만들 수 있다!! Spring REST Docs가 있습니다. API 문서를 자동화 도구로

tecoble.techcourse.co.kr

 

betterfuture4 (헌치) - velog

🌱 함께 자라는 중입니다 🚀 rerub0831@gmail.com

velog.io

 

Spring Rest Docs 적용 | 우아한형제들 기술블로그

{{item.name}} 안녕하세요? 우아한형제들에서 정산시스템을 개발하고 있는 이호진입니다. 지금부터 정산시스템 API 문서를 wiki 에서 Spring Rest Docs 로 전환한 이야기를 해보려고 합니다. 1. 전환하는

techblog.woowahan.com

 

Spring REST Docs 적용 (Gradle 7)

Spring REST Docs를 통해 API를 문서화한다.

xlffm3.github.io

 

디자인 패턴은 소프트웨어 설계 시 특정 상황에서 자주 만나는 문제를 해결하기 위해 사용할 수 있는 재사용 가능한 솔루션으로 디자인 패턴에서 중요한 것은 각 패턴의 핵심이 담긴 목적 또는 의도이다.

 

1. 패턴을 적용할 상황

2. 해결해야 될 문제

3. 핵심 의도가 무엇인지

 

 

메서드를 추상 메서드(abstaract method)로 선언해서 자식 클래스가 이를 상속 받아 메서드를 구현하도록 하면 클래스 계층구조를 통해 관심을 분리할 수 있다. (DB의 커넥션 연결 등과 SQL, DB 접근 등의 로직을 분리)

 

상속을 통해 기능을 확장하는 방법으로 사용되는 2가지 패턴이 있는데 먼저 템플릿 메서드 패턴(template method pattern)은 부모 클래스에서 자주 변경되거나 확장할 기능을 추상 메서드나 오버라이드 가능한 메서드를 정의해둔 템플릿 메서드를 만들어서 자식 클래스에서 해당 메서드를 구현하도록 하는 패턴이다. (훅(Hook) 메서드 : 부모 클래스에서 디폴트 기능을 정의해두거나 비워뒀다가 자식 클래스에서 오버라이드할 수 있도록 만들어둔 메서드)

팩토리 메서드 패턴(factory method pattern)자식 클래스에서 객체 생성 방법과 클래스를 결정할 수 있도록 미리 정의해둔 메서드(팩토리 메소드)를 통해 객체의 생성을 부모 클래스의 기본 코드에서 독립시키는 패턴이다.

 

관심을 분리한다는 것은 내부 동작에 상관없이 관심을 두지 않고 필요한 기능만 가져다 사용한다는 것이다. 

 

템플릿 메서드 패턴, 팩토리 메서드 패턴을 사용하면 관심 사항이 다른 코드를 분리해내고, 서로 독립적으로 변경, 확장을 할 수 있다. 하지만 상속을 사용하기 때문에 클래스의 다중 상속이 허용되지 않는 자바에서는 비용이 큰 편이고, 결합력이 높기 때문에 관심 사항은 분리했더라도 변경 시 변화의 파급력이 큰 편이다. 그래서 토비의 스프링 책에서는 인터페이스를 사용하여 분리를 하는 방식을 권장하는데 인터페이스를 사용하면 다형성으로 인해 의존관계를 외부에서 주입하고 클래스에서는 인터페이스 타입의 참조 변수를 통해 구현체의 메서드를 사용하면 되기 때문에 완벽하게 분리를 할 수 있다. 구현체가 변경이 되더라도 외부에서 변경된 구현체로 주입을 해주면 된다.

 

이렇게 보면 인터페이스를 사용하면 될 것 같은데 템플릿 메서드 패턴을 왜 쓰는지, 어떤 상황에 쓰이는지 잘 모르겠다. 다른 블로그를 찾아보다보니 템플릿 메서드 패턴과 비슷하면서 상속의 단점을 제거할 수 있는 전략 패턴이 있다고 하는데 인프런 김영한님의 스프링 고급편에도 템플릿 메서드 패턴에 대한 목차가 있어서 강의를 통해 더 깊게 공부해보고 코드로 사용해보면서 정리를 해봐야겠다.

 

 

 

 

[참고]

토비의 스프링

 

Overriding in Java - GeeksforGeeks

A Computer Science portal for geeks. It contains well written, well thought and well explained computer science and programming articles, quizzes and practice/competitive programming/company interview Questions.

www.geeksforgeeks.org

 

 

팩토리 메서드, 템플릿 메서드 패턴

1. 팩토리 메서드 패턴 팩토리 메서드 패턴(Factory Method Pattern)이란 객체 생성을 하는 클래스를 따로 두는 것입니다. 그래서 공장(Factory)이라는 표현을 쓰나봅니다. 🙂 실질적인 클래스의 구현은

western-sky.tistory.com

 

 

Template Method (템플릿 메서드) 패턴

1. Overview 코드를 작성하다보면 로깅, 예외 처리 등등 반복되어 작성하는 코드가 발생합니다. 이런 경우 코드의 중복을 없애기 위한 패턴 중 하나가 템플릿 메서드 패턴입니다. AbstractClass (추상

bcp0109.tistory.com

 

 

SwaggerREST API를 문서화하여 보기 편하게 시각화하고, 테스트할 수 있는 라이브러리로 서버 가동시 @RestController를 읽어서 API 분석을 해서 HTML로 문서화를 하기 때문에 API 문서를 직접 만들어서 수정시마다 일일이 수정하는 번거로움이 없어진다.

 

1. build.gradle

 

springfox-boot-starter로 추가하면 필요한 하위 라이브러리들이 전부 추가된다.

 

 

2. application.properties

 

spring boot 2.6.0 버전 이상인 경우에는 application.properties에서 spring.mvc.pathmatch.matching-strategy=ant_path_matcher을 추가하거나 2.6.0 밑으로 버전을 낮춰야 한다.

 

 

3. SecurityConfig

 

 

 

스프링 시큐리티를 사용하는 경우 해당 경로가 필터에 걸리지 않도록 permit해준다.

 

 

4. SwaggerConfig

 

Swagger 3.0을 사용하는 경우 Swagger2.x에서 사용하던 @EnableSwagger2 애노테이션을 사용하면 안 되고 Docket 생성시 DocumentationType.OAS_30으로 설정을 해야한다.

 

Swagger UI 화면을 보면 Contact와 ApiInfo에 입력한 정보들이 어디에 입력이 되는지 비교가 될 것이다.

 

 

그리고 JWT를 사용하기 때문에 관련 설정들을 해줘야 하는데 securitySchems는 API를 보호하는데 사용되는 보안 체계를 설정하는 것으로 ApiKey(또는 BasicAuth, OAuth)를 등록해서 JWT가 Authorization Header에 포함되도록 한다.

securityContext는 ApiKey로 정의한 JWT의 authorizationScope를 설정해서 SecurityReference를 포함해서 생성을 한다.

 

이제 실행을 하고 http://localhost:8080/swagger-ui/index.html 로 접속을 하면 아래와 같은 메인 화면이 뜬다. 

 

 

Authorize를 누르면 ApiKey로 등록한 정보가 나온다.

 

 

 

 

Spring Boot를 이용한 RESTful Web Services 개발 - 인프런 | 강의

이 강의는 Spring Boot를 이용해서 RESTful Web Services 애플리케이션을 개발하는 과정에 대해 학습하는 강의으로써, REST API 설계에 필요한 기본 지식에 대해 학습할 수 있습니다., - 강의 소개 | 인프런..

www.inflearn.com

 

Springfox Reference Documentation

The Springfox suite of java libraries are all about automating the generation of machine and human readable specifications for JSON APIs written using the spring family of projects. Springfox works by examining an application, once, at runtime to infer API

springfox.github.io

 

[swagger3] 설정 및 authroize button 활성화하기(Bearer 사용)

버전 2보다 좋은 점은 url에 다음과 같이 되어있을때 http://localhost:9001/swagger-ui/index.html#/1.Login/loginUsingPOST 브라우저로 접속하면 해당 api가 바로 펼쳐지면서 이동한다. (아마 그게 전부... 대신..

lemontia.tistory.com

 

Spring Boot Swagger 3.x 적용

1. Swagger 란? Swagger 는 OAS(Open Api Specification)를 위한 프레임워크입니다. 개발자들의 필수 과제인 API 문서화를 쉽게 할 수 있도록 도와주며, 파라미터를 넣어서 실제로 어떤 응답이 오는지 테스트도

bcp0109.tistory.com

 

Spring Boot2.6에서 Springfox3 실행 실패 에러

Intro Kotlin 프로젝트 였지만, Spring Boot 설정과 관련된 내용이기 때문에 java 로 프로젝트를 진행 하시는 경우에도 문제 해결을 하실 수 있습니다. Kotlin 과 스프링 부트를 이용해 API 서버를 만드는

shanepark.tistory.com

 

SpringBoot 2.6 이상 springfox-swagger3.0 적용 시 에러 해결

원인 spring boot 2.6.0부터 요청 경로를 ControllerHandler에 매칭시키기 위한 전략의 기본값이 ant_path_matcher 전략 -> path_pattern_parser 전략으로 변경되었기 때문이다. 해결 방안 2가지 application

velog.io

+ Recent posts