Notice
Recent Posts
Recent Comments
Link
«   2025/05   »
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 31
Tags more
Archives
Today
Total
관리 메뉴

두리공장

스프링부트에서 keycloak admin restAPI를 사용하려면,,, 본문

cloud

스프링부트에서 keycloak admin restAPI를 사용하려면,,,

두리공장 2023. 10. 29. 09:11

스프링부트에서 keycloak admin restapi 를 사용해야 할 경우가 있다. (사용자 계정에 대한 정보 변경 등등...)
나의 경우에는 사용자가 등록한 OTP 정보를 admin cli 를 사용하여 삭제해 주어야 하는 미션이 있었다.
몇몇 방법이 있지만 구글링 결과 키클락에서 제공하는 라이브러리를 사용하기로 했다.
(순수 restapi를 구현하여 사용하는 방법도 있디만,,,ㅎㅎ)

1. pom.xml 에 디펜던시 추가

        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-admin-client</artifactId>
            <version>20.0.5</version>
        </dependency>

2. application.yml 에 접속정보 추가

keycloak:
  server-url: http://localhost:9080/
  realm: master
  username: admin
  password: XXX

3. keycloakUtil.java 만들기(bean으로 사용할 것이므로 Component 어노테이션을 추가해 준다.

package com.durifac.jpa.global.utils;


import lombok.RequiredArgsConstructor;
import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.KeycloakBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
@RequiredArgsConstructor
public class KeycloakUtil {
    @Value("${keycloak.server-url}")
    private String serverUrl;

    @Value("${keycloak.realm}")
    private String realm;

    @Value("${keycloak.username}")
    private String username;

    @Value("${keycloak.password}")
    private String password;

    public Keycloak conn() {

        return KeycloakBuilder.builder()
                .serverUrl(serverUrl)
                .realm(realm)
                .grantType(OAuth2Constants.PASSWORD)
                .username(username)
                .password(password)
                .clientId("admin-cli")
                .clientSecret("")
                .resteasyClient(new ResteasyClientBuilderImpl()
                        .connectionPoolSize(10)
                        .build())
                .build();
    }


}

4. controller 부분

package com.durifac.jpa.domain.keycloak.controller;

import com.durifac.jpa.domain.keycloak.service.KeycloakService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.RequiredArgsConstructor;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequiredArgsConstructor
@RequestMapping("/keycloak")
public class KeycloakController {

    private final KeycloakService keycloakService;


    @Operation(summary = "키클락 유저", description = "키클락 유저정보를 가져옵니다")
    @GetMapping("/user")
    public UserRepresentation getUser(@RequestParam(name = "id") @Schema(example = "7682bedd-abe0-468f-aedb-4385b0f4b0e3") String id){

        UserResource userResource = keycloakService.getUser(id);
        return userResource.toRepresentation();
    }

    @Operation(summary = "키클락 유저의 인증정보", description = "키클락 유저의 인증정보를 가져옵니다")
    @GetMapping("/user/credentials")
    public List<CredentialRepresentation> getUserCredentials(@RequestParam(name = "id") @Schema(example = "7682bedd-abe0-468f-aedb-4385b0f4b0e3")String id){

        List<CredentialRepresentation> credentialRepresentations = keycloakService.getUserCredentials(id);
        return credentialRepresentations;
    }
    @Operation(summary = "키클락 유저의 인증정보 Otp id를 가져온다", description = "키클락 유저의 인증정보otp 아이디를 가져옵니다")
    @GetMapping("/user/credentials/ids")
    public List<String> getFindbyCredentialList(@RequestParam(name = "id") @Schema(example = "7682bedd-abe0-468f-aedb-4385b0f4b0e3")String id){

        List<String> ids = keycloakService.getFindbyCredentialList(id);
        return ids;
    }

    @Operation(summary = "키클락 유저의 인증정보 Otp 를 삭제한다", description = "키클락 유저의 인증정보를 삭제한다")
    @PostMapping("/user/credentials/ids")
    public void removeOtp(
            @RequestParam(name = "id") @Schema(example = "7682bedd-abe0-468f-aedb-4385b0f4b0e3")String id,
            @RequestParam(name = "credentialId") @Schema(example = "096cc197-9fc4-413e-b688-357031caaa34")String credentialId
    ){

        keycloakService.removeOtp(id, credentialId);

    }



}

4. service 부분

package com.durifac.jpa.domain.keycloak.service;

import com.durifac.jpa.global.utils.KeycloakUtil;
import lombok.AllArgsConstructor;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class KeycloakService {


    private final KeycloakUtil keycloak;

    //계정정보를 가져온다.
    public UserResource getUser(String id) {
        UserResource userResource = keycloak.conn().realm("durifac").users().get(id);
        return userResource;
    }

    //credential 정보를 가져온다.
    public List<CredentialRepresentation> getUserCredentials(String id) {
        UserResource userResource = keycloak.conn().realm("durifac").users().get(id);
        return userResource.credentials();
    }

    //credential 목록에서 otp id를 찾아온다.
    public List<String> getFindbyCredentialList(String id) {
        UserResource userResource = getUser(id);
        List<CredentialRepresentation> list =  userResource.credentials().stream().filter(e -> e.getType().equals("otp"))
                .collect(Collectors.toList());

        List<String> ids = list.stream().map(e -> e.getId()).toList();
        return ids;
    }

    //otp를 삭제한다.
    public void removeOtp(String id, String otpId) {
        UserResource userResource = keycloak.conn().realm("durifac").users().get(id);
        userResource.removeCredential(otpId);
    }


}

키클락 admin rest api 에서는 다음의 링크 문서를 참조한다.
https://www.keycloak.org/docs-api/21.0.1/rest-api/index.html