Spring Secuirty 40 RestApi 기반 Google OAuth2 인증 만들기 1
포스트
취소

Spring Secuirty 40 RestApi 기반 Google OAuth2 인증 만들기 1

소스 전체

https://gitlab.com/kimdongy1000/public_project_amadeus/-/tree/main?ref_type=heads

해당 소스는 민감한 정보를 제외한 순수 코드입니다 사용하실려면 application.yml 에 자신이 필요한 정보를 기입하시면 사용 가능합니다 해당 글을 적는부분과 소스의 올라간 부분은 상당히 많이 다릅니다

우리는 지난시간까지 우리가 등록한 User 로 Authentication 기반으로 JWT 토큰을 RSA 기반으로 만들어서 클라이언트에 던지고 다시 클라이언트에서 이 JWT 를 공개키로 복호화 해서 UserDetails 를 만들어서 인증을 하는 것까지 배웠습니다 오늘은 Google 의 Oauth2 인증으로 사용자 정보를 가져와서 저의 어플리케이션에 인증을 하는 방법에 대해서 알아보도록 하겠습니다

구글 Api 콘솔 사이트

https://console.cloud.google.com

이 부분에서 진행을 하게 됩니다 따로 특별히 설정하는 것은 다른 사이트에서 충분히 볼 수 있기에 저는 이 부분을 생략을 하고 바로 코드로 진입을 하겠습니다 (구글에 검색하면 많이 나오기 때문에 생략했습니다 )

Oauth2-client maven 추가

1
2
3
4
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

사실 Oauth2 라이브러리를 쓰지 않아도 충분히 구글 로그인 api 를 활용해서 통신을 할 수 있지만 저는 ClientRegistration 을 사용하기 위해서 이 라이브러리를 안고 가겠습니다

application.properties

1
2
3
4
5
6
7
spring:
  security:
    google_client_id : 
    google_client_secret : 
    google_redirect_url : http://localhost:8080/oauth2_google_login
    google_login_url: https://accounts.google.com/o/oauth2/auth

만약 oauth2-client 라이브러리를 사용한다면 이 정도 정보만 가지고 있으면 된다 그게 아니라면 authorizationUri , tokenUri , userInfoUri 는 필수값인데 만약 사용하지 않는다는 예제는 다음 포스트 네이버 Oauth2 인증을 하면서 알아보도록 하겠습니다 Google 인증은 이 정도 정보만 있어도 사용이 가능합니다

Oauth2Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Configuration
public class Oauth2Config {

    @Value("${spring.security.google_client_id}")
    private String google_client_id;

    @Value("${spring.security.google_client_secret}")
    private String google_client_secret;

    @Value("${spring.security.google_redirect_url}")
    private String google_redirect_url;


    private ClientRegistration googleClientRegistration(){
        return CommonOAuth2Provider.GOOGLE.getBuilder("google")
                .clientId(google_client_id)
                .clientSecret(google_client_secret)
                .redirectUri(google_redirect_url)
                .build();
    }

    
    @Bean
    public ClientRegistrationRepository clientRegistrationRepository(){
        ClientRegistrationRepository clientRegistrationRepository = new InMemoryClientRegistrationRepository(googleClientRegistration());
        return clientRegistrationRepository;
    }
}


먼저 config 를 만들것인데 이 부분은 ClientRegistration 을 관리하기 위한 Bean 설정을 위한 config 입니다 이때 Google 같은 대표적인 인증 사이트는 CommonOAuth2Provider 가 제공이 되어 이때는 각 어플리케이션에 제공이 되어야 하는 client_id , client_secret , redirect_url 만 넣어주면 됩니다 그럼 잠깐 CommonOAuth2Provider 살펴보면

CommonOAuth2Provider

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public enum CommonOAuth2Provider {

    GOOGLE {
        public ClientRegistration.Builder getBuilder(String registrationId) {
            ClientRegistration.Builder builder = this.getBuilder(registrationId, ClientAuthenticationMethod.CLIENT_SECRET_BASIC, "{baseUrl}/{action}/oauth2/code/{registrationId}");
            builder.scope(new String[]{"openid", "profile", "email"});
            builder.authorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
            builder.tokenUri("https://www.googleapis.com/oauth2/v4/token");
            builder.jwkSetUri("https://www.googleapis.com/oauth2/v3/certs");
            builder.issuerUri("https://accounts.google.com");
            builder.userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo");
            builder.userNameAttributeName("sub");
            builder.clientName("Google");
            return builder;
        }
    }
}

이렇게 google 같은 경우는 기본적으로 이렇게 미리 설정이 되어 있습니다 우리는 이 정보를 그대로 가져가서 진행을 하겠습니다 그럼 설정은 끝났습니다

React 에서 구글 로그인 버튼 클릭

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 const oauth2_google_login = (event) => {

    const api = "/oauth2/google/oauth2_login_address"
    const method= "get"
    const param = {}

    networkApiCall(api , method , param).then(result => {

        
        const options = 'width=700, height=600, top=50, left=50, scrollbars=yes popup=true';
        const google_oauth2_popup = window.open(result.Oauth2_login_url ,'popup' ,  options);
        

        let token_interval =  setInterval(() => {

            const google_jwt_token = getCookie("Oauth2_JWT_Token");
            if(google_jwt_token){
                const project_name = f1().project_name;
                localStorage.setItem(`${project_name}_ACCESS_TOKEN` , google_jwt_token);
                google_oauth2_popup.close();
                clearInterval(token_interval)        
                setLogInVaild(true)
            }
        } , 1000)
    }).catch(error => {
        
        console.log(error)
    })

}


이 구글 로그인 버튼을 클릭하게 되면 back-end 에서 인증을 할 수 있는 url 주소를 만들어서 client 로 return 을 하게 됩니다 예를 들면 이렇게 말이죠

1

지금 화면에서 구글 로그인 버튼을 클릭하면 옆에 팝업으로 뜨는게 현재의 상태입니다 그럼 이때 url 을 가져오는 부분을 back-end 로 보게 되면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
@RestController
public class LoginController {

    @Autowired
    private LoginService loginService;

    @Autowired
    private Gson gson;

    @Autowired
    private ClientRegistrationRepository clientRegistrationRepository;




    @GetMapping("/oauth2/{oauth2_service}/oauth2_login_address")
    public ResponseEntity<?> google_oauth2_address(
            @PathVariable("oauth2_service") String oauth2_service
        )
    {

        try{

            ClientRegistration clientRegistration = null;
            StringBuffer return_url = new StringBuffer();

            switch (oauth2_service) {
                case "google" :

                    clientRegistration = clientRegistrationRepository.findByRegistrationId("google");
                    Set<String> scopes = clientRegistration.getScopes();
                    String string_scope = String.join(" ", clientRegistration.getScopes());
                    return_url.append(clientRegistration.getProviderDetails().getAuthorizationUri());
                    return_url.append("?");
                    return_url.append("client_id=");
                    return_url.append(clientRegistration.getClientId());
                    return_url.append("&");
                    return_url.append("redirect_uri=");
                    return_url.append(clientRegistration.getRedirectUri());
                    return_url.append("&");
                    return_url.append("response_type=code&");
                    return_url.append("scope=");
                    return_url.append(string_scope);

                    break;
            }


            Map<String , Object> result = new HashMap<>();
            result.put("Oauth2_login_url" , return_url);


            return new ResponseEntity<>(gson.toJson(result) , HttpStatus.OK);
        }catch(Exception e){
            throw new RuntimeException(e);
        }
    }
}


이 부분이 현재 Google 의 저 팝업을 띄우기 위한 url 주소를 만드는 부분입니다 그러면 구글 api 를 읽어서 파라미터를 만든뒤 다시 client 로 return 하게 되면

1
2
3
4
5
6
7
8
9
networkApiCall(api , method , param).then(result => {
        
    const options = 'width=700, height=600, top=50, left=50, scrollbars=yes popup=true';
    const google_oauth2_popup = window.open(result.Oauth2_login_url ,'popup' ,  options);
})



중간에 생햑하고 result 에 key 값이 Oauth2_login_url 로 넘어오게 됩니다 그러면 사용자는 저의 어플리케이션 사이트에 접속을 해서 인증을 하는게 아니라 이때 만큼은 google 에 요청을 해서 인증을 받게 됩니다 그러면 그 인증이 완료 되고 난 다음에는 다음장에서 정리하도록 하겠습니다