SSO(Single Sign-On)란 무엇인가요?

김상욱·2024년 12월 31일
0

SSO(Single Sign-On)란 무엇인가요?

Single Sign-On(SSO)는 사용자가 한 번의 로그인으로 여러 관련 시스템나 애플리케이션에 접근할 수 있게 해주는 인증 메커니즘입니다. 예를 들어, 회사의 이메일, 인트라넷 프로젝트 관리 도구 등을 각각 따로 로그인하지 않고도 하나의 로그인으로 모두 접근할 수 있는 것이 SSO의 예입니다.

  • 여러번 로그인할 필요가 없어 사용자 경험이 개선됩니다
  • 비밀번호 관리가 간소화되고, 중앙에서 인증을 관리하기 때문에 보안 정책을 일관되게 적용할 수 있습니다.
  • 사용자 계정을 중앙에서 관리할 수 있어 관리가 용이.

작동 원리

  1. 사용자 로그인 요청 : 사용자가 애플리케이션 A에 접근하려고 합니다.
  2. 인증 요청 : 애플리케이션 A는 사용자가 인증되지 않았음을 감지하고, SSO 인증 서버로 인증을 요청합니다.
  3. 사용자 인증 : SSO 인증 서버는 사용자에게 로그인 페이지를 제공하고 사용자가 자격 증명을 입력합니다.
  4. 토큰 발급 : 인증이 성공하면 SSO 서버는 사용자에게 인증 토큰을 발급합니다.
  5. 토큰 전달 및 접근 허용 : 사용자는 이 토큰을 애플리케이션 A에 전달하고 애플리케이션 A는 토큰을 검증하여 접근을 허용합니다.
  6. 다른 애플리케이션 접근 : 이후 사용자가 애플리케이션 B에 접근할 때, 이미 발급된 토큰을 사용하여 추가 로그인 없이 접근할 수 있습니다.

Java/Spring 환경에서 SSO 구현하기

a. Spring Security와 OAuth2
Spring Security는 인증 및 권한 부여를 처리하는 강력한 프레임워크입니다. OAuth2는 SSO를 구현할 때 자주 사용되는 인증 프로토콜 중 하나입니다.
1. 의존성 추가

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-client</artifactId>
    </dependency>
</dependencies>
  1. 설정 파일 구성
spring:
  security:
    oauth2:
      client:
        registration:
          google:
            client-id: your-client-id
            client-secret: your-client-secret
            scope: openid, profile, email
        provider:
          google:
            authorization-uri: https://accounts.google.com/o/oauth2/auth
            token-uri: https://oauth2.googleapis.com/token
            user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo
            user-name-attribute: sub
  1. 보안 설정 클래스 작성
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/", "/public/**").permitAll()
                .anyRequest().authenticated()
                .and()
            .oauth2Login();
    }
}
  1. 로그인 및 콜백 처리

b. SSO 제공자 사용하기
직접 SSO를 구현하는 대신 KeyCloak, Okta, Auth0와 같은 외부 SSO 제공자를 사용할 수도 있습니다. 이들 서비스는 SSO 기능을 쉽게 통합할 수 있는 다양한 기능과 설정을 제공합니다.


취업 준비 중인 신입 Java/Spring 백엔드 개발자라면 이론을 실습을 통해 체득하는 것이 매우 중요합니다. SSO(Single Sign-On)를 이해하고 실제로 구현해보는 것은 큰 도움이 될 것입니다. 다음은 실습을 통해 SSO를 학습할 수 있는 몇 가지 프로젝트 아이디어와 단계별 가이드를 제공합니다.

프로젝트 1: Spring Boot 애플리케이션에 Google OAuth2 SSO 통합하기

이 프로젝트는 Spring Boot 애플리케이션에 Google OAuth2를 사용한 SSO를 통합하는 간단한 실습입니다.

1. 사전 준비

  • Java 및 Spring Boot 환경 설정: JDK 11 이상과 Spring Boot 초기 프로젝트를 설정합니다.
  • Google API 콘솔 설정:
    1. Google API Console에 접속하여 새 프로젝트를 생성합니다.
    2. OAuth 동의 화면을 설정하고 필요한 정보를 입력합니다.
    3. 자격 증명에서 OAuth 클라이언트 ID를 생성합니다. 애플리케이션 유형은 웹 애플리케이션으로 선택하고, 승인된 리디렉션 URI에 http://localhost:8080/login/oauth2/code/google을 추가합니다.
    4. 클라이언트 ID와 클라이언트 시크릿을 기록해둡니다.

2. Spring Boot 프로젝트 설정

  • 의존성 추가: pom.xml에 Spring Security와 OAuth2 클라이언트 의존성을 추가합니다.

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>
  • application.yml 설정: src/main/resources/application.yml 파일에 Google OAuth2 설정을 추가합니다.

    spring:
      security:
        oauth2:
          client:
            registration:
              google:
                client-id: YOUR_GOOGLE_CLIENT_ID
                client-secret: YOUR_GOOGLE_CLIENT_SECRET
                scope: openid, profile, email
            provider:
              google:
                authorization-uri: https://accounts.google.com/o/oauth2/auth
                token-uri: https://oauth2.googleapis.com/token
                user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo
                user-name-attribute: sub

    YOUR_GOOGLE_CLIENT_IDYOUR_GOOGLE_CLIENT_SECRET을 실제 값으로 대체합니다.

3. 보안 설정 클래스 작성

  • src/main/java/com/example/demo/SecurityConfig.java 파일을 생성하고 다음과 같이 작성합니다.

    package com.example.demo;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/", "/public/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .oauth2Login()
                    .defaultSuccessURL("/home", true);
        }
    }

4. 컨트롤러 및 뷰 작성

  • HomeController.java: src/main/java/com/example/demo/HomeController.java 파일을 생성합니다.

    package com.example.demo;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.security.core.annotation.AuthenticationPrincipal;
    import org.springframework.security.oauth2.core.user.OAuth2User;
    
    @Controller
    public class HomeController {
    
        @GetMapping("/")
        public String index() {
            return "index";
        }
    
        @GetMapping("/home")
        public String home(@AuthenticationPrincipal OAuth2User principal, Model model) {
            model.addAttribute("name", principal.getAttribute("name"));
            return "home";
        }
    }
  • Thymeleaf 템플릿 작성:

    • src/main/resources/templates/index.html:

      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>Welcome</title>
      </head>
      <body>
          <h1>Welcome to the SSO Demo</h1>
          <a href="/oauth2/authorization/google">Login with Google</a>
      </body>
      </html>
    • src/main/resources/templates/home.html:

      <!DOCTYPE html>
      <html xmlns:th="http://www.thymeleaf.org">
      <head>
          <title>Home</title>
      </head>
      <body>
          <h1>Home Page</h1>
          <p>Welcome, <span th:text="${name}"></span>!</p>
          <a href="/logout">Logout</a>
      </body>
      </html>

5. 애플리케이션 실행 및 테스트

  • 애플리케이션을 실행합니다.
  • 브라우저에서 http://localhost:8080에 접속하여 "Login with Google" 버튼을 클릭합니다.
  • Google 계정으로 로그인하면 /home 페이지로 리디렉션되며, 사용자 이름이 표시됩니다.

프로젝트 2: Keycloak을 사용한 SSO 구현

Keycloak은 오픈 소스 인증 및 권한 부여 서버로, SSO를 쉽게 구현할 수 있습니다. 이 프로젝트에서는 Keycloak을 사용하여 SSO를 설정하고 Spring Boot 애플리케이션과 통합해보겠습니다.

1. Keycloak 설치 및 설정

  • Keycloak 다운로드 및 실행:
    1. Keycloak 다운로드 페이지에서 최신 버전을 다운로드합니다.
    2. 압축을 해제하고 bin 디렉토리로 이동하여 Keycloak 서버를 실행합니다.
      ./kc.sh start-dev
  • Keycloak 관리 콘솔 접속: 브라우저에서 http://localhost:8080에 접속합니다. 초기 관리자 계정을 설정합니다.
  • Realm 및 Client 설정:
    1. Realm 생성: 예를 들어, demo-realm을 생성합니다.
    2. Client 생성:
      • Client ID: spring-app
      • Client Protocol: openid-connect
      • Access Type: confidential
      • Valid Redirect URIs: http://localhost:8081/*
      • Save 후, Credentials 탭에서 Secret을 확인합니다.

2. Spring Boot 애플리케이션 설정

  • 새 Spring Boot 프로젝트 생성: 포트 변경을 위해 application.yml을 사용하여 기본 포트를 8081로 변경합니다.

    server:
      port: 8081
    
    spring:
      security:
        oauth2:
          client:
            registration:
              keycloak:
                client-id: spring-app
                client-secret: YOUR_KEYCLOAK_CLIENT_SECRET
                authorization-grant-type: authorization_code
                redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"
                scope: openid, profile, email
            provider:
              keycloak:
                issuer-uri: http://localhost:8080/realms/demo-realm

    YOUR_KEYCLOAK_CLIENT_SECRET을 Keycloak에서 확인한 값으로 대체합니다.

  • 보안 설정 클래스 작성:

    package com.example.demo;
    
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    
    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers("/", "/public/**").permitAll()
                    .anyRequest().authenticated()
                    .and()
                .oauth2Login()
                    .defaultSuccessURL("/home", true);
        }
    }
  • 컨트롤러 및 뷰 작성: 이전 프로젝트와 유사하게 HomeController와 Thymeleaf 템플릿을 작성합니다.

3. 애플리케이션 실행 및 테스트

  • Spring Boot 애플리케이션을 실행합니다.
  • 브라우저에서 http://localhost:8081에 접속하여 로그인합니다.
  • Keycloak 로그인 페이지가 나타나면, Keycloak에 설정한 사용자 계정으로 로그인합니다.
  • 성공적으로 로그인하면 /home 페이지로 리디렉션되며, 사용자 정보가 표시됩니다.

프로젝트 3: 다중 Spring Boot 애플리케이션 간 SSO 구현

이 프로젝트에서는 두 개 이상의 Spring Boot 애플리케이션을 설정하여 하나의 인증 서버(Keycloak 또는 Google)를 통해 SSO를 구현해봅니다.

1. 인증 서버 설정

  • Keycloak 사용 시: 앞서 설정한 Keycloak 서버를 사용합니다.
  • OAuth2 제공자 사용 시: Google 또는 다른 OAuth2 제공자를 사용할 수 있습니다.

2. 두 개 이상의 Spring Boot 애플리케이션 설정

  • 각 애플리케이션은 동일한 OAuth2 제공자(예: Keycloak)로 인증을 설정합니다.
  • 각 애플리케이션의 application.yml에 동일한 OAuth2 클라이언트 설정을 추가합니다.
  • 예를 들어, 두 번째 애플리케이션의 포트를 8082로 설정하고 동일한 client-idclient-secret을 사용합니다.

3. SSO 테스트

  • 첫 번째 애플리케이션(http://localhost:8081)에 로그인합니다.
  • 로그인 후 두 번째 애플리케이션(http://localhost:8082)에 접근하면, 추가 로그인 없이 접근이 허용됩니다.

추가 실습 및 확장 아이디어

  • 로그아웃 기능 구현: SSO 환경에서 로그아웃 시 모든 애플리케이션에서 로그아웃되도록 설정해보세요.
  • 사용자 역할 및 권한 관리: Keycloak이나 Spring Security에서 사용자 역할을 정의하고, 각 애플리케이션에서 권한에 따라 접근을 제어해보세요.
  • JWT 토큰 사용: JWT(Json Web Token)를 사용하여 토큰 기반 인증을 구현해보고, 토큰의 유효성을 검증하는 방법을 학습하세요.
  • 외부 SSO 제공자 사용: Auth0, Okta 등 다른 SSO 제공자를 사용하여 통합해보세요.

학습 자료 및 참고 링크

결론

실습을 통해 SSO의 개념과 구현 방법을 직접 경험해보는 것은 매우 유익합니다. 위의 프로젝트들을 따라하면서 SSO의 작동 원리와 Spring Boot와의 통합 방법을 깊이 있게 이해할 수 있을 것입니다. 또한, 실제 프로젝트에서 SSO를 적용할 때 고려해야 할 보안 사항과 최적화 방법에 대해서도 자연스럽게 익힐 수 있습니다. 꾸준한 실습과 학습을 통해 SSO에 대한 자신감을 키우세요. 화이팅입니다!

0개의 댓글