배경
백엔드 서버는 keycloak을 보조하기 위한 역할로 존재. 기본적으로 keycloak은 인증만 목적으로하는 모듈임
- CIBA(Client Initiated Backchannel Authentication) 등 중간 서버가 있어야하는 인증 방식이 필요한 경우
- 다중 약관 동의, 서비스별 추가 데이터 등이 필요한 경우
다중 약관 동의 항목 설계
필요성
keycloak에서는 기본적으로 단일 약관 내용만 제공하고, 동의 여부도 timestamp를 기록하기 위한 update 방식을 채택하므로 요구사항을 충족하기에는 어려움이 있음. 개별로 SPI, entity 등을 개발하여 keycloak에 적용하는 경우 keycloak version up 대응 시 위험 요소로 작용할 수 있음
따라서 백엔드 서버에서 약관 동의 항목용 API를 만들고 개별적으로 적용해야함
인프라 비용 절감을 위해 기존 keycloak이 사용하는 DB에 schema만 다르게하여 백엔드 서버용 DB를 구성함
핵심 요구사항
전자상거래법
제6조(거래기록의 보존 등) ① 사업자는 전자상거래 및 통신판매에서의 표시ㆍ광고, 계약내용 및 그 이행 등 거래에 관한 기록을 상당한 기간 보존하여야 한다. 이 경우 소비자가 쉽게 거래기록을 열람ㆍ보존할 수 있는 방법을 제공하여야 한다.
② 제1항에 따라 사업자가 보존하여야 할 거래기록 및 그와 관련된 개인정보(성명ㆍ주소ㆍ전자우편주소 등 거래의 주체를 식별할 수 있는 정보로 한정한다)는 소비자가 개인정보의 이용에 관한 동의를 철회하는 경우에도 「정보통신망 이용촉진 및 정보보호 등에 관한 법률」 등 대통령령으로 정하는 개인정보보호와 관련된 법률의 규정에도 불구하고 이를 보존할 수 있다. <개정 2016. 3. 29.>
③ 제1항에 따라 사업자가 보존하는 거래기록의 대상ㆍ범위ㆍ기간 및 소비자에게 제공하는 열람ㆍ보존의 방법 등에 관하여 필요한 사항은 대통령령으로 정한다.
도메인 설계
기타 항목들은 제외하고 속성값만 표기함
Terms
- 약관은 수정이 불가하다. 수정이 필요하다면 같은 type으로 새로 생성하여 버전을 올리면 된다.
- 약관의 버전은 yyyyMMddHHmmss 포맷으로 지정하여 초 단위로 구분할 수 있고, 인간이 쉽게 해석할 수 있는 형식으로 표기한다.
- type별로 약관을 구분한다. 즉 같은 type의 약관에 대해 버전을 올릴 수 있다.
- type에 서비스명을 포함한다. 필요하다면 service 테이블로 확장하여 관계를 맺어도 된다.
- deleted로 삭제여부 또는 활성화 여부를 표현한다. 나중에 필요하다면 isActive 같은 컬럼을 두어 활성화 여부와 삭제 여부는 구분하여 표기한다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
@Schema(description = "버전 (yyyyMMddHHmmss 포맷)")
private String version;
private String title;
private String description;
@Column(nullable = false, columnDefinition = "TEXT")
private String content;
@Column(nullable = false)
@Schema(description = "type별로 버전이 구분됨")
private String type;
@Column(nullable = false)
private Boolean required;
private String link;
private Boolean deleted;
termsAgreement
- 사용자가 특정 type, version의 약관에 대해 동의하면 termsAgreement(TA)항목이 생성된다.
- 사용자가 약관에 대해 동의를 할 때마다 TA 레코드가 생성되고, 동의를 철회하면 기존 TA 레코드는 is_deleted 항목이 true가 된다.
- 위 두 항목에 따라 사용자가 약관에 동의할 때마다 TA 항목이 생성되고, 철회할 때마다 최신 항목이 deleted 처리된다.
- 사용자별, 약관별 동의여부 조회 시, TA 항목 중 각 약관별 created_at 값이 최신인 것을 기준으로 is_deleted가 false인 항목 1개가 조회된다. version 값을 기준으로 해도 된다. 다만 이 때는 정렬 로직을 따로 넣어줘야한다.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "terms_id", nullable = false)
private Terms terms;
@Column(nullable = false)
private String userId; // Keycloak User UUID
private Boolean deleted;
private LocalDateTime agreedAt;
활용 방안
회원 정보 페이지 등이 있다면, 회원의 기본 인증 등의 정보는 keycloak에서 호출하고, 약관 정보는 백엔드 서버에서 호출하면 된다. 클라이언트에서 단일화하여 요청하고 싶다면 백엔드 서버에서 userinfo endpoint를 keycloak으로 요청하고, 그 정보를 클라이언트에 전달해주면 된다. 네트워크 홉이 더 생기겠지만, 복잡도는 줄어든다.
'Programming-[Backend] > Keycloak' 카테고리의 다른 글
keycloak v26.1.2 image build issue( w/ Docker engine 28.x.x) (1) | 2025.04.28 |
---|---|
Keycloak Infinispan 통신 방식 정리: udp, jdbc-ping, kubernetes (0) | 2025.04.27 |
keycloak upstream header is too big. 502 Gateway Error w/ nextAuth (0) | 2025.04.24 |
Keycloak 성능 테스트 - 특정 url 호출 확인(userinfo) (0) | 2025.04.23 |
Keycloak CODE_TO_TOKEN_ERROR: cookie와 roles (0) | 2025.04.21 |