티스토리 뷰

 

지난 게시글에서 키클록에 대해 다루면서 스프링 시큐리티 OAuth 구현을 위한 키클록 기본 세팅을 진행했다. 

 

[Spring] Keycloak으로 SpringSecurity OAuth 구현하기 #1 | 키클록이란?

0. Keycloak 이란?Keycloak은 Open Source 기반의 IAM(Identity and Access Management) 소프트웨어로 사용자에 대한 인증(Authentication)과 인가(Authorization) 관리기능을 국제 인증/인가 표준 프로토콜(OIDC, SAML, OAuth 2.0

yuejeong.tistory.com

 

오늘은 스프링부트 앱에서 시큐리티 세팅을 구현해 보자. 

스프링 시큐리티와 키클록을 연동하는 과정에서 정말 무수히 많은 에러를 경험했다.. 레퍼런스를 찾아보려고 해도 버전이 안 맞아서 deprecated 된 패키지를 사용해 쓸 수 없는 것이 대부분이었고, 이유를 알 수 없는 오류가 많아 직접 다양한 코드를 시도해 보면서 해결해야 했다. 피눈물이 담긴 나의 코드가 deprecated 되기 전에 많은 사람들에게 도움이 되길 바란다..! 

 

자바 버전: 17.0.9

Springboot 버전: 3.2.7

 


 

지난 시간에 키클록을 세팅했으니, 오늘은 스프링 시큐리티와 연동을 하기 위한 코드를 작성해 보자.

키클록 연동을 위해 작성해야 하는 파일은 크게 세 가지이다.

 

1. application.yml

spring:
  datasource:
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}
    url: ${DB_URL}
    driver-class-name: com.mysql.cj.jdbc.Driver
  jpa:
    properties:
      hibernate:
        show_sql: true
        format_sql: true
        use_sql_comments: true
        hbm2ddl:
          auto: update
  
   # 키클록 설정 부분 
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: http://localhost:8090/realms/aws-springboot
        registration:
          keycloak:
            client-id: spring-security
            client-secret: ${CLIENT_SECRET}
            redirect-uri: http://localhost:8080/login/oauth2/code/spring-security

 

application.yml 파일에서 키클록 연동을 위한 네 가지 필드를 설정해 주자.

필드명 설명
 issuer-uri '{내 로컬 키클록 url}:{포트번호}/realms/{사용할 realm 명}' 이렇게 작성한다.
이때, 로컬 키클록이 아닌 배포한 키클록을 사용한다면 해당 url을 그대로 적어주면 된다.
client-id 키클록에 추가한 클라이언트 아이디
client-secret 저번 포스팅에서 Client details - Credentials 탭에서 복사한 시크릿 값
redirect-uri 로그인 후 리다이렉트할 url을 설정해준다. 이 리다이렉트 url을 잘못 설정하면 무한 로딩이나 아예 로그인 페이지에 접속하지 못하는 오류가 발생한다. 반드시 다음과 같이 설정해준다
➡️ {스프링 애플리케이션 실행하는 url:포트번호}/login/oauth2/code/{client-id}

 

 

2. SecurityConfig.java

import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
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.configurers.AbstractHttpConfigurer;
import org.springframework.security.web.SecurityFilterChain;


@Configuration
@EnableWebSecurity
@KeycloakConfiguration
public class SecurityConfig {
    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests((authorizeRequests) ->
                        authorizeRequests.requestMatchers("/public/**").permitAll()
                                .anyRequest().authenticated()
                )
                .oauth2Login(Customizer.withDefaults())
        ;

        return http.build();
    }

}

 

시큐리티 Config 부분에서는 filterchain으로 시큐리티 설정을 하고, oauth2Login을 추가해서 "/public/**"을 제외한 api에 대해서 oauth2Login으로 사용자 인증을 구현하도록 설정한다.

 

 

3. KeycloakConfig.java

import org.keycloak.adapters.springsecurity.KeycloakConfiguration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
import org.springframework.security.oauth2.core.AuthorizationGrantType;

@EnableWebSecurity
@KeycloakConfiguration
public class KeycloakConfig {


    @Value("${spring.security.oauth2.client.registration.keycloak.client-id}")
    private String clientId;

    @Value("${spring.security.oauth2.client.registration.keycloak.client-secret}")
    private String clientSecret;

    @Value("${spring.security.oauth2.client.provider.keycloak.issuer-uri}")
    private String baseUrl;

    @Value("${spring.security.oauth2.client.registration.keycloak.redirect-uri}")
    private String redirectUrl;


    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        ClientRegistration keycloakRegistration = ClientRegistration.withRegistrationId("keycloak")
                .clientId(clientId)
                .clientSecret(clientSecret)
                .authorizationUri(baseUrl +"/auth")
                .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
                .redirectUri(redirectUrl)
                .tokenUri( baseUrl + "/token")
                .userInfoUri( baseUrl + "/userinfo")
                .jwkSetUri(baseUrl + "/certs")
                .userNameAttributeName("preferred_username")
                .build();

        return new InMemoryClientRegistrationRepository(keycloakRegistration);
    }

}

 

KeycloakConfig에서는 키클록 oauth2Login 설정에서 필요한 ClientRegistrationRepository를 만들어줬다. RegistrationId는 "keycloak"이고 application.yml에 적어준 키클록 설정 정보를 가져와서 clientId, clientSecret 등에 담아준다. 이렇게 하면 키클록 로그인 설정 준비가 모두 끝난다.

 

 

자 이제 빌드를 하고 실행해 보자.

'localhost:8080/public', 'localhost:8080/swagger-ui.html' 두 개의 url에 대해서 스프링 시큐리티에서 전자는 permitAll, 후자는 Authenticated로 설정했기 때문에 public api는 키클록 로그인 없이 연결되고, 스웨거는 키클록 로그인 화면이 연결돼야 한다.

 

먼저 로컬호스트 public으로 접속해 보면,

다음과 같이 로그인 없이 실행됨을 확인할 수 있다.

 

이번에는 스웨거에 접속해 보자.

접속하면 다음과 같이 자동으로 키클록 로그인 화면으로 리다이렉트 된다. 

 

여기서 로그인에 성공하면 다음과 같이 스웨거 화면에 접속할 수 있다.

 

 

이렇게 간단하게 키클록으로 스프링 시큐리티 Oauth를 구현해 봤다.

여기까지 정리해 봤을 때 정말 간단해 보이지만 로그인 화면을 가져오는 데까지 피눈물 나도록 고생했다...... 

다음에는 리액트 프론트엔드와 스프링부트 백엔드를 사용하는 서비스에 키클록을 적용하는 과정과 에러슈팅을 정리해 볼 것이다.

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/09   »
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
글 보관함