본문 바로가기
공부/Spring

[Spring] 스프링 Oauth2 구글 로그인과 jpa 사용하여 유저 정보 데이터베이스에 저장 (OAuth2 스프링 1편)

by 웅대 2023. 3. 23.
728x90

OAuth2 구글 로그인을 해 볼 예정인데 mysql 데이터베이스와 jpa를 사용하여 데이터베이스에 유저 정보를 저장해보려 한다.

 

먼저 OAuth2에 대해 간단하게 알아보자면 로그인, 회원가입 구현 과정의 번거로움을 덜어줄 수 있는 프로토콜이다.

 

우리가 직접 로그인, 회원가입을 구현한다면 단순 정보를 저장하는 것 뿐만 아니라 보안 및 여러 요소들을 신경써야한다.

 

OAuth2는 이러한 과정을 구글, 페이스북과 같은 곳에 위임하는 것이다.

 

OAuth2를 사용하면 당연하게도 인증 과정 구현에 대한 개발자의 고민을 덜어줄 수 있다.

 

먼저 구글 OAuth2를 사용하기 위해 구글에서 key값을 받아와야 한다.

 

구글 클라우드 플랫폼에 접속한다.

https://console.developers.google.com/?hl=ko 

 

Google 클라우드 플랫폼

로그인 Google 클라우드 플랫폼으로 이동

accounts.google.com

좌측 상단의 프로젝트를 누르고

새 프로젝트를 누른다.

프로젝트 이름을 정하고 만들기를 누른다.

프로젝트가 생성되면 생성된 프로젝트를 선택한다.

좌측의 OAuth 동의 화면으로 들어와서 외부를 선택하고 만든다.

그러면 다음과 같은 화면을 볼 수 있는

필수로 작성해야하는 부분들을 작성하고 저장 후 계속을 클릭한다.

 

그 다음 사용자 인증 정보 -> 사용자 인증 정보 만들기 -> OAuth 클라이언트 ID를 클릭한다.

유형은 웹 애플리케이션을 선택한다.

필수 입력하는 곳들을 채워주는데 승인된 리디렉션 URI의 경로는 /login/oauth2/code/google로 적어줘야한다.

 

 

 

생성하고 나면 클라이언트 ID와 비밀번호가 나오는데 이를 기억해둔다.

 

스프링 초기 세팅은 아래와 같다.

 

스프링 프로젝트의 application.properties에 이전에 기억해둔 클라이언트 아이디와 시크릿을 적어준다.

 

<application.properties>

spring.security.oauth2.client.registration.google.client-id=[클라이언트 아이디]
spring.security.oauth2.client.registration.google.client-secret=[클라이언트 시크릿]
spring.security.oauth2.client.registration.google.scope=profile, email

mysql과 jpa를 사용할 예정이므로 데이터베이스를 만들고 application.properties에 데이터베이스 설정 정보를 적어준다.

 

<다음 포스팅 참고>

https://growth-coder.tistory.com/111

 

[Spring] 스프링 mysql 데이터베이스와 jpa 연동

본 포스팅은 mysql이 깔려있다는 가정하게 진행합니다. mysql 데이터베이스와 연동 후 jpa를 사용할 예정이므로 다음과 같은 dependencies를 추가한다. 만약 기존 프로젝트에 mysql과 jpa를 사용하고 싶다

growth-coder.tistory.com

 

이제 유저 정보를 저장할 Member 엔티티와 레포지토리 생성한다.

 

<Member.java>

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id; //기본키
    private String name; //유저 이름
    private String password; //유저 비밀번호
    private String email; //유저 구글 이메일
    private String role; //유저 권한 (일반 유저, 관리지ㅏ)
    private String provider; //공급자 (google, facebook ...)
    private String providerId; //공급 아이디

}

<MemberRepository.java>

public interface MemberRepository extends JpaRepository<Member, Long> {
    public Optional<Member> findByName(String name);
}

 

구글로부터 유저 정보를 받아오면 그 정보들을 바탕으로 엔티티를 생성해서 데이터베이스에 저장할 예정이고 MemberRepository의 findByName 메소드는 최초 로그인 여부를 체크하기 위해 사용할 예정이다.

 

이제 페이지를 만들 차례이다. main/resources/template 경로에 loginForm.html 파일을 생성한다.

 

<loginForm.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<a href="/oauth2/authorization/google">google login</a>

</body>
</html>

구글 로그인 버튼의 경로는 "/oauth2/authorization/google"이다.

 

또한 같은 경로에 로그인 한 사람만 접근 가능한 privatePage.html과 관리자 계정만 접근 가능한 adminPage.html과 인덱스 파일인 index.html 파일을 생성한다.

 

<privatePage.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

private
</body>
</html>

<adminPage.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
admin
</body>
</html>

<index.html>

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
index
<a href="/logout">로그아웃</a>
</body>
</html>

 

index 페이지는 로그인이 성공하면 이동할 페이지로 로그아웃 버튼을 만들어준다.

 

경로를 "/logout"으로 설정하면 자동으로 로그아웃 기능이 생긴다.

 

그리고 이 경로들 매핑해줄 컨트롤러를 생성한다. (타임리프를 템플릿 엔진으로 사용 중이다.)

 

참고로 index.html의 경우 자동으로 "/"경로로 매핑이 되기 때문에 신경쓰지 않아도 된다.

 

<OAuthController.java>

@Controller
public class OAuthController {
    @GetMapping("/loginForm")
    public String home() {
        return "loginForm";
    }

    @GetMapping("/private")
    public String privatePage() {
        return "privatePage";
    }
    @GetMapping("/admin")
    public String adminPage() {
        return "adminPage";
    }
}

 

이제 DefaultOAuth2UserService를 확장한 서비스를 만들 차례이다.

 

DefaultOAuth2UserService를 확장한 서비스에서 loadUser 메소드를 오버라이딩 해야 한다.

 

이 loadUser 메소드는 구글로부터 회원 정보를 가져온 다음 그 정보들을 처리하는 메소드이다.

 

<OAuth2MemberService.java>

@Service
public class OAuth2MemberService extends DefaultOAuth2UserService {
    @Override
    public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
        OAuth2User oAuth2User = super.loadUser(userRequest);
        System.out.println("oAuth2User = " + oAuth2User.getAttributes());
        return super.loadUser(userRequest);
    }
}

일단 간단하게 회원 정보를 출력하도록 만들었다.

 

이후 이 메소드에 레포지토리에 회원을 저장하는 로직을 만들 예정이다.

 

이제 시큐리티 관련된 설정 파일을 만들 차례이다. 

 

OAuth 로그인과 관련하여 설정을 해줘야 하는데 설정을 해야 하는 부분은 다음과 같다.

 

  1. /private 하위 경로는 로그인 한 사람만 접근 가능
  2. 1번 경로를 제외한 경로는 모든 사람이 접근 가능
  3. 로그인이 필요한 경로에 접근 시 "/loginForm" 경로로 리다이렉션
  4. 로그인 성공 시 인덱스 페이지로 리다이렉션
  5. 구글 로그인 완료 후 구글 회원 정보 가져오기
  6. 정보를 받은 후 실행해야하는 메소드 설정 (OAuth2MemberService의 loadUser 메소드)

<SecurityConfig.java>

@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfig {
    private final OAuth2MemberService oAuth2MemberService;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception{
        return httpSecurity
                .httpBasic().disable()
                .csrf().disable()
                .cors().and()
                .authorizeRequests()
                .requestMatchers("/private/**").authenticated() //private로 시작하는 uri는 로그인 필수
                .anyRequest().permitAll() //나머지 uri는 모든 접근 허용
                .and().oauth2Login()
                .loginPage("/loginForm") //로그인이 필요한데 로그인을 하지 않았다면 이동할 uri 설정
                .defaultSuccessUrl("/") //OAuth 구글 로그인이 성공하면 이동할 uri 설정
                .userInfoEndpoint()//로그인 완료 후 회원 정보 받기
                .userService(oAuth2MemberService).and().and().build(); //로그인 후 받아온 유저 정보 처리
    }
}

 

주석을 읽어보면 이해가 어렵지 않을 것이다.

 

이제 테스트를 해 볼 차례이다.

 

http://localhost:8080/loginForm 로 접속을 해보면 google login 버튼이 하나 보인다.

누르게 되면 이제 인증 과정을 google에서 대신 해주는 것이다.

자신의 계정을 선택하면 구글에서 자동으로 인증 과정을 거친다.

 

로그인 성공하면 우리가 설정한 index 페이지로 이동하는 모습을 확인할 수 있다.

 

한번 http://localhost:8080/private 으로도 접근을 해본다.

 

로그인을 한 상태이므로 접근할 수 있는 것을 볼 수 있다.

 

이제 로그아웃을 한 다음에는 private에 접근하면 로그인 페이지로 강제로 보내야한다.

 

로그아웃을 누르고 private 경로에 접속해본다.

 

접근 권한이 없기 때문에 자동으로 loginForm 페이지로 가게 된다.

 

다음 포스팅에서 jpa를 활용하여 데이터베이스에 유저 정보를 저장하는 과정을 진행해보려 한다.

 

참고

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-%EC%8B%9C%ED%81%90%EB%A6%AC%ED%8B%B0/dashboard

 

[무료] 스프링부트 시큐리티 & JWT 강의 - 인프런 | 강의

스프링부트 시큐리티에 대한 개념이 잡힙니다., - 강의 소개 | 인프런

www.inflearn.com

 

728x90
반응형

댓글