인증을 위한 개방형 표준 프로토콜이다.
리소스 소유자(사용자)가 특정 Third-Party 프로그램(서비스)에게 자신을 대신해 리소스 서버(구글, 카카오)에 있는 자원에 대한 접근 권한을 위임 할 수 있도록 설계되었다.
인증 서버와 리소스 서버는 보통 같은 서비스 제공자(구글, 카카오 등)에서 운영되지만, 역할이 다르다.
인증 서버는 사용자의 인증(로그인)을 처리하고, 클라이언트에게 AccessToken과 같은 권한 부여 토큰을 발급한다.
리소스 서버는 사용자의 데이터(이메일, 프로필 이미지 등)를 저장하고, 클라이언트가 제공한 AccessToken을 검증한 후 요청한 데이터를 반환한다.
OAuth2 프로토콜이 소셜 로그인 시스템에서 널리 사용되는 이유는 제 3자 애플리케이션을 사용자 이름과 비밀번호 없이 인증하는 매커니즘이 포함되어 있기 때문이다.
즉, OAuth2를 사용하면 사용자는 구글이나 카카오 같은 신뢰할 수 있는 서비스 제공자를 통해 제 3자 애플리케이션에 로그인할 수 있다.
신뢰할 수 있는 구글이나 카카오 같은 서비스 제공자는 사용자의 신원을 확인(로그인) 하고, 이 정보를 제 3자 애플리케이션에 제공한다.
OAuth2 는 로그인 과정을 직접 다루는 것이 아닌, 인증과 밀접하게 연관되어 있다.
1) 사용자가 소셜 로그인을 클릭
2) 프론트가 /oauth2/authorization/naver로 요청을 보낸다.
3) 백엔드는 인증 서버로 리다이렉트 처리한다.
4) 인증 서버에서 프론트에 로그인 페이지를 표시하고, 사용자는 ID와 비밀번호를 입력하여 로그인한다.
5) 로그인에 성공 시, 인증 서버는 등록된 리다이렉트 URI(백엔드 API 엔드포인트)로 리다이렉트 시킨다. 이 때, 쿼리 파라미터로 Authorization Code를 전달한다.
6) 백엔드는 이 Code를 이용해 인증 서버에 AccessToken을 요청한다.
7) 인증 서버는 이 Code를 확인 후, 백엔드는 인증 서버로부터 AccessToken을 받는다.
8) 받은 AccessToken으로 리소스 서버에 사용자 정보를 요청한다.
9) 리소스 서버는 AccessToken를 확인 후, 사용자의 정보를 백엔드에 발급 해준다.
10) 백엔드에서 사용자 정보를 확인 후, 회원가입이 되어 있지 않은 상태라면 DB에 저장 후, JWT를 생성하고, 이미 회원인 경우에는 DB에 저장하지 않고 JWT를 생성한다. (사용자의 닉네임이나 프로필 이미지와 같은 정보가 변경된 경우에는 DB에 반영)
11) 프론트는 로그인 요청을 하이퍼링크로 보냈기 때문에 JWT를 받을 로직이 존재하지 않는다.
그렇기 때문에 쿠키에 JWT를 발행하고, 로그인 완료된 화면으로 리다이렉트 한다.
위 flow를 보면 백엔드가 처리해줘야 될 부분이 굉장히 많아 보인다.
하지만 Spring Security가 이미 다 구현해두었기 때문에 직접 다 만들지 않고, 이를 잘 활용하는 방법으로 구현할 수 있다.
소셜 로그인을 하기 위한 OAuth2 클라이언트 부분(OAuth2Service, OAuth2User, LoginSuccessHandler)과 토큰을 발급하고 검증할 JWT부분(JWTFilter, JWTUtil)만 구현하면 된다.
OAuth2Service는 AccessToken으로 OAuth2 제공자 리소스 서버에서 사용자 정보를 얻어오고 정보를 가지고 OAuth2 인터페이스 구현체인 인증 객체를 생성하여 리턴해야된다.
이때 사용자 정보를 리소스 서버로부터 가져오는 과정은 이미 구현되어 있다. 상위 클래스인 DefaultOAuth2UserService객체에게 위임만 하면 된다.
#registration
#registration은 외부 서비스에서 우리 서비스를 특정하기 위해 등록하는 정보로, 등록이 필수이다.
spring.security.oauth2.client.registration.서비스명.client-name=서비스명
spring.security.oauth2.client.registration.서비스명.client-id=서비스에서 발급 받은 아이디
spring.security.oauth2.client.registration.서비스명.client-secret=서비스에서 발급 받은 비밀번호
spring.security.oauth2.client.registration.서비스명.redirect-uri=서비스에 등록한 우리쪽 로그인 성공 URI(스프링 IP:PORT/login/oauth2/서비스명)
spring.security.oauth2.client.registration.서비스명.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.서비스명.scope=리소스 서버에서 가져올 데이터 범위(name,email)
#provider
#구글, 페이스북, 깃허브 같은 경우는 provider를 등록하지 않아도 서비스별로 정해진 값이 존재한다.
spring.security.oauth2.client.provider.서비스명.authorization-uri=서비스 로그인 창 주소(네이버를 예로 https://nid.naver.com/oauth2.0/authorize)
spring.security.oauth2.client.provider.서비스명.token-uri=토큰 발급 서버 주소(https://nid.naver.com/oauth2.0/token)
spring.security.oauth2.client.provider.서비스명.user-info-uri=사용자 정보 획득 주소(https://openapi.naver.com/v1/nid/me)
spring.security.oauth2.client.provider.서비스명.user-name-attribute=응답 데이터 변수(response)