[Spring Security] Keycloak AuthenticationProvider를 활용하여 사용자 정보를 커스터마이징하기 -Username 기반 Principal 설정하기

김민주·2024년 12월 17일

Keycloak 인증 후 사용자 정보를 원하는 형태로 변경하는 방법

SecurityContextHolder에 저장된 principal의 getName()은 KeycloakAuthenticationToken에서 저장된 토큰의 sub클레임을 이용한다.
그래서 principal의 네임을 keycloak의 UUID가 아닌 username을 사용하고 싶다면 KeycloakAuthenticationProvider의 커스터마이징이 필요하다.
getName()만 override한다고 바뀌지 않는 것이 KeycloakAuthenticationProcessingFilter가 인증 후에 SecurityContextHolder를 업데이트하면 Principal 값이 다시 설정되므로 KeycloakAuthenticationProvider를 상속받는 클래스를 생성해줘야 한다.
CustomKeycloakAuthenticationProvider를 생성하여 SecurityConfig에 등록해준다.
Principal을 implemetns받는 커스텀Principal 클래스도 필요하다.

import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider;
import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken;
import org.keycloak.adapters.springsecurity.account.OidcKeycloakAccount;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class CustomKeycloakAuthenticationProvider extends KeycloakAuthenticationProvider {

    @Override
    public Authentication authenticate(Authentication authentication) {
        KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        OidcKeycloakAccount account = token.getAccount();
        KeycloakSecurityContext keycloakSecurityContext = account.getKeycloakSecurityContext();

        // KeycloakSecurityContext에서 사용자 정보 가져오기
        String preferredUsername = keycloakSecurityContext.getToken().getPreferredUsername();
        String email = keycloakSecurityContext.getToken().getEmail();
        Set<String> roles = account.getRoles();

        // CustomPrincipal 생성
        CustomPrincipal customPrincipal = new CustomPrincipal(preferredUsername, email, String.join(", ", roles));

        // 새로운 OidcKeycloakAccount 생성
        OidcKeycloakAccount updatedAccount = new OidcKeycloakAccount() {
            @Override
            public Principal getPrincipal() {
                return customPrincipal; // 커스터마이징된 Principal
            }

            @Override
            public Set<String> getRoles() {
                return roles;
            }

            @Override
            public KeycloakSecurityContext getKeycloakSecurityContext() {
                return keycloakSecurityContext;
            }
        };

        // 새로운 Authentication 객체 생성
        KeycloakAuthenticationToken updatedAuth = new KeycloakAuthenticationToken(
            updatedAccount,
            token.isInteractive(),
            token.getAuthorities()
        );
        
        // SecurityContext 업데이트
        SecurityContextHolder.getContext().setAuthentication(updatedAuth);
        return updatedAuth;
    }
}

그럼 이제 SecurityConfig에서 AuthenticationManagerBuilder가 바라볼 프로바이저를 위의 커스텀프로바이저로 세팅해주면 된다.
본인은 KeycloakWebSecurityConfigurerAdapter 사용중임.

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exceptioin{

        // username 매핑을 위한 기본 인증프로바이저 대신 커스텀 프로바이저 사용
        customKeycloakAuthenticationProvider.setGrantedAuthoritiesMapper(keycloakAuthenticationProvider.getGrantedAuthoritiesMapper());
        auth.authenticationProvider(customKeycloakAuthenticationProvider);
    }

이렇게 설정해주면 키클락 UUID가 아닌 username으로 스프링시큐리티에 등록되어 사용가능하다.

profile
𝐃𝐨𝐧'𝐭 𝐛𝐞 𝐚 𝐩𝐫𝐨𝐜𝐫𝐚𝐬𝐭𝐢𝐧𝐚𝐭𝐨𝐫💫

0개의 댓글