Spring boot oauth2로 로그인하기

2022. 2. 13. 20:24Spring

728x90

oauth2의 인증 진행 과정은 다음과 같다

1. gradle dependency 설정

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-oauth2-client:2.4.2'
    implementation 'mysql:mysql-connector-java'
    implementation 'org.projectlombok:lombok:1.18.22'

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

spring-boot-starter-oauth2-client 라이브러리에 oauth2 로그인을 통한 인증과 권한 처리에 관한 api가 들어있다.

 

2. github oauth application 생성

https://github.com/settings/developers

 

GitHub: Where the world builds software

GitHub is where over 73 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories, review code like a pro, track bugs and feat...

github.com

Homepage URL은 나의 어플리케이션 홈페이지 url을,

Authorization callback URL은 로그인 후 호출되는 페이지 URL을 입력한다.

나는 둘 다 http://localhost:8000 을 입력했다.

3. applicaiton.yml 설정

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Seoul
    username: root
    password: 1234
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: 1q2w3e4r5t6y7u8i
            clientSecret: qawsedrftgyhujik

CilentID와 CliendSecret는 방금 생성한 github oauth application에 들어가면 확인할 수 있다.

4. RestController 생성

package com.example.jwtoauthtutorial.api;

import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Collections;
import java.util.Map;

@RestController
public class SocialController {

    @GetMapping("")
    public String hello() {
        return "hello";
    }

    @GetMapping("/user")
    public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
        return Collections.singletonMap("user", principal);
    }
    
    @GetMapping("/user/name")
    public Map<String, Object> userName(@AuthenticationPrincipal OAuth2User principal) {
        return Collections.singletonMap("user", principal.getAttribute("name"));
    }
}

5. WebSecurityConfigure 설정

package com.example.jwtoauthtutorial.config;

import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(a -> a.antMatchers("/", "/error")
                        .permitAll()
                        .anyRequest().authenticated()
                )
                .exceptionHandling(e -> e.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
                .oauth2Login()

                .and()
                .logout(l -> l.logoutSuccessUrl("/").permitAll())

                .csrf(c -> c.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()));

    }
}

WebSecurityConfigurerAdapter

WebSecurityConfigurer의 인스턴스를 편리하게 제공하는 클래스

WebSecurityConfigurer는 WebSecurity클래스를 커스터마이징이 가능하게 하는 인터페이스이다.

 

authorizeHttpRequests()

HttpServletRequest의 제한된 접근을 허가한다.

antMatchers를 통해 "/" 와 "/error" 에 대한 api 접근은 허가한다.

permitAll()

어떠한 보안 요구 없이 요청을 허용해준다.

anyRequest().authenticated()

(위에서 지정한 요청을 제외하고 "/", "/error")어떤 요청이든 인증된 자만 접근이 가능하다.

exceptionHandling()

예회 발생시 핸들링 처리

oauth2Login()

oauth2 혹은 openID를 통한 인증 지원을 구성한다.

 

logout()

로그아웃 실행 시 진행

logoutSuccessUrl()

로그아웃 성공 시 이동할 경로를 지정

 

csrf()

CSRF공격에 대한 보호를 가능하게 한다

 

CSRF란?

사이트 간 요청 위조(Cross-Site Request Forgery)

웹 어플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제 등의 작업을 하게 만드는 공격방법

 

 

6. 테스트

localhost:8080/login으로 접속해보자

이런 창이 나타날 것이다.

만약 클라이언트에서 github로그인을 호출하려면

"/oauth2/authorization/github"를 호출하면 된다.

해당 링크를 클릭하면 깃허브 로그인 창이 뜬다.

로그인 후에는 깃허브에서 지정한 callback URL로 이동한 것을 볼 수 있다.

이제 localhost:8080/user을 요청해보자

로그인 한 유저의 모든 정보를 가져올 수 있다.

localhost:8080/user/name을 요청하면

로그인중인 유저의 이름을 가져올 수 있다.

7. google login 설정

https://console.cloud.google.com/

 

Google Cloud Platform

하나의 계정으로 모든 Google 서비스를 Google Cloud Platform을 사용하려면 로그인하세요.

accounts.google.com

이 곳에서 새 프로젝트를 생성한다.

탐색메뉴 -> API 및 서비스 ->  사용자 인증 정보 -> +사용자 인증 정보 만들기 -> OAuth 클라이언트 ID 클릭

다음과 같이 입력

application.yml에 google 추가

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Seoul
    username: root
    password: 1234
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: 1q1q2q2q2q2q2q2q
            clientSecret: q3q33q33q3q3q3q3q3q3q3q3q3 #???? ??
          google:
            client-id: 1qsx3efcjiorj3.com
            client-secret: 243udsasdfjkl;jaflk;ajkldsrjkldsafjklasd

테스트

"localhost:8080/login" 요청 시

google 누르면 로그인 된다.

github와 마찬가지로 "/oauth2/authorization/google" 을 요청하면 구글 로그인 창으로 넘어가진다.

"localhost:8080/user" 요청 시

"localhost:8080/user/name" 요청 시

8. kakao login 설정

https://developers.kakao.com/console/app

 

카카오계정 로그인

여기를 눌러 링크를 확인하세요.

accounts.kakao.com

애플리케이션 추가하기

플렛폼 -> web 플렛폼 등록 -> 사이트 도메인 입력

카카오 로그인 -> 활성화 설정 ON -> Redirect URI에 "http://localhost:8080/login/oauth2/code/kakao" 입력

동의항목 설정

원하는 항목에 상태 설정

application.yml 설정

카카오는 스프링에서 지원이 안되기 때문에 Provider를 직접 입력해줘야 한다.

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Seoul
    username: root
    password: 1234
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: 1qw2w4e5e65r65rtr65r65t354eewr
            clientSecret: 1qw2w4e5e65r65rtr65r65t354eewr #???? ??
          google:
            client-id: 88761955634-1qw2w4e5e65r65rtr65r65t354eewr.apps.googleusercontent.com
            client-secret: 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wr-1TZy_fock1qw2w4e5e65r65rtr65r65t354eewrNlVy7
          kakao:
            client-id: 1qw2w4e5e65r65rtr65r65t354eewr
            client-name: Kakao
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            client-authentication-method: POST
            authorization-grant-type: authorization_code
            scope: profile_nickname, profile_image, account_email
        provider:
          kakao:
            authorization_uri: https://kauth.kakao.com/oauth/authorize
            token_uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user_name_attribute: id

테스트

lcoalhost:8080/login

localhost:8080/user

9. naver login 설정

https://developers.naver.com/apps/#/register?api=nvlogin 

 

애플리케이션 - NAVER Developers

 

developers.naver.com

application 등록

application.yml 설정

 

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?serverTimezone=Asia/Seoul
    username: root
    password: 1234
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: 1q2w3e4r5t6y7u
            clientSecret: 1q2w3e4r5t6y7u #???? ??
          google:
            client-id: 88761955634-1q2w3e4r5t6y7u.apps.googleusercontent.com
            client-secret: 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u
          kakao:
            client-id: 1q2w3e4r5t6y7u
            client-name: Kakao
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            client-authentication-method: POST
            authorization-grant-type: authorization_code
            scope: profile_nickname, profile_image, account_email
          naver:
            client-id: 1q2w3e4r5t6y7u
            client-secret: 1q2w3e4r5t6y7u
            client-name: Naver
            redirect-uri: "{baseUrl}/{action}/oauth2/code/{registrationId}"
            authorization-grant-type: authorization_code
            scope: name, email, nickname, gender, age, birthday, profile_image, birthyear, mobile

        provider:
          kakao:
            authorization_uri: https://kauth.kakao.com/oauth/authorize
            token_uri: https://kauth.kakao.com/oauth/token
            user-info-uri: https://kapi.kakao.com/v2/user/me
            user_name_attribute: id
          naver:
            authorization_uri: https://nid.naver.com/oauth2.0/authorize
            token_uri: https://nid.naver.com/oauth2.0/token
            user-info-uri: https://openapi.naver.com/v1/nid/me
            user_name_attribute: response

테스트

localhost:8080/login

localhost:8080/user

참고

https://spring.io/guides/tutorials/spring-boot-oauth2/

 

Spring Boot and OAuth2

this tutorial is designed to be completed in 2-3 hours, it provides deeper, in-context explorations of enterprise application development topics, leaving you ready to implement real-world solutions.

spring.io

https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/config/annotation/web/builders/HttpSecurity.html

 

HttpSecurity (spring-security-docs 5.6.1 API)

Allows specifying which HttpServletRequest instances this HttpSecurity will be invoked on. This method allows for easily invoking the HttpSecurity for multiple different RequestMatcher instances. If only a single RequestMatcher is necessary consider using

docs.spring.io

https://brownbears.tistory.com/251

 

CSRF란?

CSRF란? 사이트 간 요청 위조(Cross-site Request Forgery) 웹 어플리케이션 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나

brownbears.tistory.com

 

728x90