인증(Authentication)
- 로그인 : 사용자 식별(Identity)
- 회원가입
- 이메일 본인확인 (휴대폰X)
- 2차 인증 (2FA) : OTP
- 소셜 로그인
- 다국어 지원
- SSO (Single Sing On)
인가(Authorization)
- 자원 관리 : REAT API
- 범위 관리 : READ / WRITE (Action)
- 정책 관리
- ROLE 기반 정책
- GROUP 기반 정책
- TIME 기반 정책
- 사용자 기반 정책
- 권한 제어 : 자원에 대한 접근 통제(허용/불가) 관리

<!-- Spring Security dependency add -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- keycloak dependency add -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>

Keycloak을 적용하면 Application 접근시 Keycloak 공통 로그인 화면으로 Redirect 된다.
Keycloak의 <공통 로그인 화면>을 통해서 아래의 기능이 기본으로 제공된다.
- 로그인 : 사용자 식별(Identity)
- 회원가입하기
- 이메일 본인확인 (휴대폰은 지원 안함)
- 비밀번호 찾기
- 2차 인증(2FA) : OTP
- 다국어 지원
- SSO (Single Sign On)
아래는 기본으로 지원하는 화면을 캡쳐한 내용이다.

| 구분 | SecurityContextHolder.Authentication |
|---|---|
| Spring Security | Authentication.getPricipan()에 UserDetails 정보 저장 |
| Keycloak | Authentication.getPricipal()에 OidcUser 정보 저장 |


| 구분 | UserDetails 기반 | Keycloak(OIDC) 기반 |
|---|---|---|
| Principal Type | UserDetails | OidcUser(또는 OAuth2User) |
| Authentication Type | UsernamePasswordAuthenticationToken | OAuth2AuthenticationToken |
| 인증처리 방식 | Form 로그인 | Redirect-based OAuth2/OIDC |
| 사용자 정보 로딩 | UserDetailsService 구현체에서 직접 로딩 | ID Token 및 UserInfo Endpoint 에서 자동 맵핑 |
| Customizing Point | UserDetailsService | OAuth2UserService, OidcUserService |
[ 용어 정의 ]
- Realm은 '영역', '범위'라는 뜻으로 Client들의 집합이다.
- Client란, Application 또는 쉽게 Web Site라고 생각하면 된다.
즉, Keycloak이 IdP 서버가 되고, Application은 ID 인증을 요청하는 Client이다.
이렇게 Keycloak을 통해서 로그인 한 사용자는 A,B,C site 아무곳에서나 로그아웃(Logout)을 수행하면 전체 Site에 대해 로그아웃(Logout)이 수행된다.
그것은 사용자가 Logout을 호출할 때, Application은 자신의 SecurityContextHolder 정보를 삭제한다. 이후 Keycloak 세션을 삭제하고, 로컬PC(브라우저)의 Cookie를 삭제해야 전체 세션이 삭제되면서 Logout이 완성된다.
- Keycloak 세션을 삭제하기 위해서 Application은 Keycloak Logout Endpoint를 호출한다. Keycloak Endpoint가 호출되면 하나의 KEYCLOAK_SESSION에 A,B,C site가 SSO 로 묶여있기 때문에 이 KEYCLOAK_SESSION이 삭제 되면서 모든 site에 대한 로그아웃이 수행된다.
간단 코드 참조 (Logout Endpoint 호출)
@Component
public class KeycloakLogoutHandler implements LogoutHandler {
@Value("${spring.security.oauth2.client.provider.keycloak.issuer-uri}")
private String KEYCLOAK_URL = "";
@Value("${appl.url}")
private String APPL_URL = "";
@Override
public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
//STEP-1 :: Spring session delete...
if( authentication !=null && authentication.getDetails() != null ) {
request.getSession().invalidate();
SecurityContextHolder.clearContext();
//STEP-2 :: Keycloak Session delete...
try {
String keycloakLogoutUrl = this.KEYCLOAK_URL + "/protocol/openid-connect/logout?post_logout_redirect_uri=" + this.APPL_URL + "&id_token_hint=" + getIdToken(authentication);
response.sendRedirect(keycloakLogoutUrl);
} catch (Exception e) {
e.printStackTrace();
}
}
}
private String getIdToken(Authentication authentication) {
if( authentication instanceof OAuth2AuthenticationToken ) {
OAuth2AuthenticationToken authToken = (OAuth2AuthenticationToken) authentication;
OidcUser oidcUser = (OidcUser) authentication.getPrincipal();
return oidcUser.getIdToken().getTokenValue();
}
return null;
}
}