keycloak-js 로 로그인 구현하기 (w. React)

🔥Log·2023년 1월 17일
1

스프링과 OAuth2

목록 보기
5/11

Keycloak서버의 구동 및 배포와 관련된 내용들은 이 시리즈의 이전 글들을 참고하자

☕ 시작


Keycloak으로 인증서버를 구성했다면, 이 인증서버와 연동될 클라이언트(서비스 또는 애플리케이션)도 있을 것이다.
이번 글에서는 React로 만든 웹서비스에서 keycloak-js를 활용하여 인증/인가와 관련된 기본적인 기능을 구현해보도록 하겠다.

참고로 @react-keycloak/web과 같은 써드파티 라이브러리는 사용하지 않고, 순수 keycloak-js를 다룬다.

  • Keycloak버전 : 20.0.2
  • keycloak-js버전 : 20.0.2

🙏 참고하면 좋은 컨텐츠들


공식문서이 유튜브 영상을 매우 추천한다.
유튜브 영상은 최신 버전과 버전차이가 좀 나긴하지만, 전체적인 맥락을 확실히 알 수 있다.


🤔 keycloak-js란?


Keycloak은 OAuth2표준을 구현한 인증/인가 프레임워크이다. 기본적으로 OAuth2의 인증/인가 흐름들은 단순하지는 않다. 그래서 직접 이 흐름들에 맞게 개발을 하려고하면 손이 엄청 많이 가고, 안정성도 떨어진다.

그래~서 Keycloak에서는 keycloak-js라는 어댑터를 제공한다. 쉽게 얘기하자면, sdk같은 것인데, 필요한 모든 기능을 제공한다 👍
바로 이것들을 살펴보도록 하자 ㅎㅎ


💻 구현할 기능들


  • Keycloak객체 초기화
  • Keycloak기능 관련 클래스 생성
  • 로그인하지 않은 사용자 처리
  • 접속시, 인증 처리 (정상, 에러)
  • 로그아웃
  • 그 외에 중요 기능들

1) Keycloak객체 초기화


import Keycloak from 'keycloak-js'

const config = {
  url: "https://keycloak서버.com",
  realm: "Realm이름",
  clientId: "ClientId"
}

const kc = new Keycloak(config);

먼저 Keycloak의 기능을 사용하려면, Keycloak객체를 초기화해야한다.
초기화하는 방법은 Keycloak객체에 설정값을 넘겨주면 된다.
설정값을 넘겨주는 방법은 json객체 또는 json파일로 구현할 수 있다.
공식문서


2) Keycloak 클래스 생성


export default class KeycloakService {
  static #instance;
  kc;
	
  constructor(config) {
    if (KeycloakService.#instance) return KeycloakService.#instance;
    this.kc = new Keycloak(config);
    KeycloakService.#instance = this;
  }

  init(renderCallback) {
    this.kc.init({onLoad: 'login-required'})
        .then((authenticated) => this.handleAuthenticated(renderCallback, authenticated))
        .catch(this.handleError)
  }

  handleAuthenticated(renderCallback, authenticated) {
    if (!authenticated) throw Error('인증되지 않은 접근입니다.');
    if (!this.kc.hasRealmRole(ROLE_ADMIN)) throw Error("접근 권한이 없습니다.")
    renderCallback()
  }

  handleError(error) {
    console.error(error)
  }

  login() {
    this.kc.login()
  }

  async logout() {
    await this.kc.logout()
  }
}

본격적으로 시작하기 전에 Keycloak과 관련된 기능들을 처리하는 KeycloakService라는 클래스를 만들었다. (이렇게 구현하는 것은 전혀 필수적인 것은 아니다.)

메서드들에 대한 소개만 간단히 하고 넘어가도록하겠다.

- init(): Keycloak객체를 초기화한 후, 애플리케이션이 시작하는 시점에 호출할 메서드
- handleAuthenticated(): init()이 성공했을 때, 처리할 로직
- handleError(): init()이 실패했을 때, 처리할 로직
- login(): 로그인 페이지로 이동
- logout(): 로그아웃 기능

3) 로그인하지 않은 사용자. 멈춰!


인증되지 않은(로그인하지 않은)사용자가 React application으로 접근시 로그인 페이지로 redirect시키는 것을 구현해보겠다.

먼저 React애플리케이션의 main.jsx를 위와 같이 구성했다.
보통은 바로 애플리케이션을 렌더링하지만, .init()메서드로 감싸줬다.
.init()메서드에서 뭔가를 처리해줄 것이다 ㅎㅎ

.init()메서드를 살펴보면, onLoadlogin-required로 되어 있다.
이 옵션은 로그인을 하지 않은 접근일 경우 강제로 인증서버의 로그인페이지로 redirect시키는 방식으로 동작하게 해준다.

즉, 로그인을 반드시 해야만 React애플리케이션에 접근할 수 있게 되는 것이다.
login-required옵션만으로 로그인하지 않은 사용자가 접근할 수 없도록 처리가 완료됐다.

그렇다면, 로그인을 하고 나서는 어떻게 될까?

login-required말고도 check-sso옵션도 있는데, 자세한 내용은 공식문서를 참고하자.


4) 초기 인증 처리


로그인을 한 후에는 이상이 없다면, init()메서드의 .then()으로 로직을 타게 되고 이상이 있는 경우엔 .catch()로 로직을 타게 된다.

나는 then()에 validation코드를 추가했다.
authenticated된 사용자이면서 특정 권한을 갖고 있어야 React애플리케이션을 렌더링을 하는 것이다. 그렇지 않은 경우엔 에러를 던지고, 던져진 에러는 당연히 .catch()에서 처리되게 된다.

이와 같은 방식으로 다양한 예외/에러 처리를 할 수 있다.

또, 이 부분에서 로그인한 유저의 AccessToken이나 RefreshToken을 조회해서 쿠키같은 곳에 저장할 수도 있다.


5) 로그아웃


로그아웃은 매우 간단하다.
초기화한 Keycloak객체에는 .logout()이라는 메서드가 있는데, 이 메서드를 호출하면 바로 로그아웃이 된다. 🤭

이로써, 완전 기본적인 기능들을 살펴봤는데, 추가로 꼭 필요한 기능들을 간단히 짚어보도록 하겠다.


⭐ 그 외에 중요 기능들


위에서 언급한 것들 말고도 OAuth2 인증/인가를 구현하기 위한 모든 기능들이 Keycloak객체에 들어 있다.
자세한 것은 공식문서를 참고하는 것을 권장한다 ㅎㅎ


토큰 조회

토큰들은 Keycloak객체의 variables로 존재하고, 아래와 같이 바로 접근해서 값을 가져올 수 있다.

const keycloak = new Keycloak({...}).init();
kecloak.token;
keycloak.refreshToken;

토큰 갱신

토큰 갱신은 .updateToken()이라는 메서드로 구현하면 된다.


이벤트 리스너

위와 같이 다양한 Keycloak의 기능들에 대해서 리스너를 구현할 수 있다.
이 리스너들을 통해서 뭔가 실패했을 때, 사용자에게 알림을 줄 수 있을 것 같다 ㅎㅎ


☕ 마무리

이번 글에서는 keycloak-js를 통해서 Keycloak인증 서버를 통한 클라이언트의 인증/인가 기능을 구현해보았다.
이런 sdk가 없으면 도대체 어떻게 개발을 할 수 있을까 싶다 ㅎㅎ
땡큐 키클락 🤭

0개의 댓글