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으로 스프링시큐리티에 등록되어 사용가능하다.