너무나 다양하고 많은 웹 / 앱 서비스들이 출시되고 있는 추세에
매번 새로운 Application 에, 새로운 정보로 가입하는 건 요즘은 꽤나 기피됩니다.
OAuth2 를 활용하면
대중적인 사이트들의 로그인 API 를 활용해서 나의 새로운 Application에 손쉽게 클릭 한 두번으로 가입할 수 있게 됩니다.
최근 출시하는 Application 들은 이러한 편의성을 강점으로 살리고자 로그인 방법만 10가지가 넘게 제공하기도 하죠..
대표적인 사이트 구글, 네이버 로그인을 OAuth 를 활용해 적용하는 법을 정리해 보았습니다.
1. 라이브러리 설치
[ Build Gradle ]
# Spring Scurity
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
# OAuth2 - Client
implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
# Spring Boot - DevTools
developmentOnly 'org.springframework.boot:spring-boot-devtools'
2. application-oauth.properties 생성 ( new - resource bundle )
(1) 구글
spring.security.oauth2.client.registration.google.client-id=
spring.security.oauth2.client.registration.google.client-secret=
spring.security.oauth2.client.registration.google.scope=email
(2) 네이버
#registration
spring.security.oauth2.client.registration.naver.client-id=
spring.security.oauth2.client.registration.naver.client-secret=
spring.security.oauth2.client.registration.naver.redirect-uri={baseUrl}/{action}/oauth2/code/{registrationId}
spring.security.oauth2.client.registration.naver.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.naver.scope=email
spring.security.oauth2.client.registration.naver.client-name=Naver
# provider
spring.security.oauth2.client.provider.naver.authorization-uri=https://nid.naver.com/oauth2.0/authorize
spring.security.oauth2.client.provider.naver.token-uri=https://nid.naver.com/oauth2.0/token
spring.security.oauth2.client.provider.naver.user-info-uri=https://openapi.naver.com/v1/nid/me
spring.security.oauth2.client.provider.naver.user-name-attribute=response
=> application.properties 에 가져오기
[ application.properties ]
# 추가
spring.profiles.include=oauth
- 구글/네이버 클라이언트 id, pw 가 들어가므로, gitIgnore, 암호화 등 조치 필요
- scope : 구글/네이버 로그인 시 사이트에서 받아올 정보 종류.
3. SecurityConfig 설정 추가
(1) 기존 security configure 설정에 oauth2 설정을 추가
@Override
protected void configure(HttpSecurity http) throws Exception{
(기존 설정) ...
.and()
.oauth2Login().loginPage("/login")
.defaultSuccessUrl("/test")
.userInfoEndpoint()
.userService(customOAuth2UserService);
}
=> OAuth2 로그인 페이지 설정, success fail URL 등 설정
=> customOAuth2UserService 에서 처리하겠다.
( OAuth가 아닌, 자체 로그인에 대한 처리는 UserDetailService 인터페이스를 상속해 처리했었다. )
(2) Security Config 에서 configure 메소드를 오버로딩해서
매개변수로 AuthenticationManagerBuilder 가 주어졌을 때는 해당 객체의 userDetailsService 를 사용하도록
추가해줍니다.
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailService);
}
4. OAuth2 User 서비스 생성
@Service
public class CustomOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
MemberRepository memberRepository;
HttpSession httpSession;
@Autowired
public CustomOAuth2UserService(MemberRepository memberRepository, HttpSession httpSession) {
this.memberRepository = memberRepository;
this.httpSession = httpSession;
}
@Override
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
OAuth2UserService delegate = new DefaultOAuth2UserService();
OAuth2User oAuth2User = delegate.loadUser(userRequest);
// 서비스 구분을 위한 작업 ( 구글 / 네이버 )
String registrationId = userRequest.getClientRegistration().getRegistrationId();
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
String email;
Map<String, Object> response = oAuth2User.getAttributes();
// 네이버
if (registrationId.equals("naver")) {
Map<String, Object> hash = (Map<String, Object>) response.get("response");
email = (String) hash.get("email");
//구글
} else if (registrationId.equals("google")) {
email = (String) response.get("email");
} else {
throw new OAuth2AuthenticationException("허용되지 않는 인증입니다.");
}
MemberDTO memberDTO;
Optional<MemberDTO> optionalMmeberDTO = memberRepository.findByEmail(email);
//이미 가입한 사람 => findbyEmail 로 찾은 DTO 가져옴
if (optionalMmeberDTO.isPresent()) {
memberDTO = optionalMmeberDTO.get();
//새로 가입 => 새로 DTO 만들어서 저장
} else {
memberDTO = new MemberDTO();
memberDTO.setEmail(email);
memberDTO.setRole("USER"); // Enum을 사용하면 Role.ROLE_USER 형식으로 사용, 여기선 String - default 값
memberRepository.registerMember(memberDTO);
}
// 로그인 된 뒤 처리 => 세션 등록
httpSession.setAttribute("sessiondto", memberDTO);
return new DefaultOAuth2User(
Collections.singleton(new SimpleGrantedAuthority(memberDTO.getRole()))
, oAuth2User.getAttributes()
, userNameAttributeName
);
}
}
5. Controller 맵핑
// oauth 파라미터 => 리다이렉트로 맵핑
@GetMapping("/login/{oauth2}")
public String loginGoogle(@PathVariable String oauth2) {
return "redirect:/oauth2/authorization/" + oauth2;
}
6. View href
<a href="/login/google">Google Login</a>
<a href="/login/naver">Naver Login</a>
이렇게 설정해두고, Google, Naver 에서 로그인 API 를 사용할 수 있도록 각 사이트에서
Application 을 생성, 내 URL 을 등록, 리디렉션 설정을 해주면 OAuth2 를 사용한 로그인이 가능해집니다.
[ Google Cloud - OAuth API 등록 ]
1. 프로젝트 생성
2. 해당 프로젝트에서 OAuth 동의화면
- 어플설정하고 저장
- scope 범위 : 요청할 data, 서비스 범위
- 사용자 : 외부 => 사용자 유저 추가
3. 사용자 인증정보 - 만들기 - OAuth 클라이언트 ID 만들기
- 어플리케이션 유형 : 웹 어플리케이션
- 승인된 리디렉션 URI :
http://localhost:8080/login/oauth2/code/google
(/login/oauth2/code/사이트) 고정
naver 에서는
http://localhost:8080/login/oauth2/code/naver
주소로 callback 주소를 적어주면 됩니다.
- 생성 후 받게되는 클라이언트 ID / PW 를 application-oauth.properties 에 등록해주면 됩니다.
노출되지 않도록 gitignore, 암호화 등을 활용해 꼭! 주의해서 관리해주어야 합니다.
( 네이버의 경우도 과정이 크게 다르지 않으니 가이드를 읽으며 따라가시면 될 것 같습니다. )
'Back to the Spring' 카테고리의 다른 글
[ Spring ] 프레임워크, DI, Entity / DTO (0) | 2023.01.15 |
---|---|
[Spring Security] Authentication Failure Handler 적용 (0) | 2022.12.24 |
[Spring Security] SecurityConfig, UserDetailsService, BCrypt, CSRF (0) | 2022.12.23 |
이미지 파일 다중 업로드, 미리보기 구현 ( AJAX ) (0) | 2022.09.24 |
IntlliJ 단축키 => Eclipse(STS) 단축키 (0) | 2022.09.24 |