react 로 이뤄진 페이지에서 js-adapter 를 사용하여 keycloak 로그인을 진행하는 과정에 대해 정리하고자 한다.
구현하려는 그림
구현하고자 하는 로그인 flow 는 아래와 같다.
각 단계가 구체적으로 어떻게 진행되는지는 js-adapter 에 관해 먼저 알아보고 설명할 것이다.
사용할 라이브러리들
keycloak-js adapter
javascript 용 keycloak adapter 이다.
keycloak 을 이용한 로그인, token 갱신 등 작업들을 해준다.
frontend 단에 적용하는 adapter 이기 때문에, token 교환이 frontend 에서 발생한다.
react-keycloak/web
js-adapter 를 react 에서 쓰기 쉽게 wrapping 해 놓은 것이다.
자세한 사용법은 아래 guide 에 자세히 나와있다.
www.npmjs.com/package/@react-keycloak/web
로그인 구현
위에서 말한 flow 를 구현하기 위해 keycloak 설정부분부터 살펴보자.
1. keycloak 서버 페이지 설정
client access type 은 public 으로 해준다.
인증과 토큰 교환을 브라우저단에서 진행하기 때문이다.
backend 서버에서 token 교환을 진행할 거라면 confidentail/barier 타입을 선택해야 한다.
redirect uri/cors 는 * 로 설정해준다. (어떤 주소의 url 에서든 로그인 진행하는것을 허용하게 된다.)
특정 주소만 허용해주고 싶으면 * 대신 주소를 적어줘야 한다.
2. react-keycloak 설정
react-keycloak 사용법은 간단하다. ReactKeycloakProvider
로 최상위에서 감싸주고, keycloak-js optoin 들을 넣어주면 된다.
import React from 'react';
import ReactDOM from 'react-dom';
import { ReactKeycloakProvider } from '@react-keycloak/web';
// 따로 정의한 파일이다. keycloak instance, option 들을 가져온다.
import keycloak, { initOptions, onKeycloakEvent } from './keycloak/keycloak';
import App from './view/app';
ReactDOM.render(
<React.StrictMode>
<ReactKeycloakProvider
authClient={keycloak}
initOptions={initOptions}
onEvent={onKeycloakEvent}
>
<App/>
</ReactKeycloakProvider>
</React.StrictMode>,
document.getElementById('root'),
);
authClient 에는 keycloak-js Instance 를, initOptions 에는 keycloak 옵션들을 넣어주면 된다.
위의 예시에서는 keycloak 옵션들을 정의해놓은 keycloak.ts 파일을 따로 만들어 두었다.
react-keycloak 문서에는 react-redux 같은 다른 provider 들도 ReactKeycloakProvider 내부에 정의하는 것을 권장하고 있다.
N.B. If your using other providers (such as react-redux) it is recommended to place them inside ReactKeycloakProvider.
아래가 따로 정의한 keycloak.ts 파일의 내용이다. typescript 를 사용했다.
import Keycloak from 'keycloak-js';
const KEYCLOAK_REALM_NAME = 'Test' // keycloak realm
const KEYCLOAK_CLIENT_ID = 'my-client'; // 사용할 client
const KEYCLOAK_URL = 'http://ip/auth/'; // keycloak url
// 위에 설정한 realm, client_id, url 로 keycloak instance 를 생성한다.
const keycloak: Keycloak.KeycloakInstance = Keycloak({
realm: KEYCLOAK_REALM_NAME,
clientId: KEYCLOAK_CLIENT_ID,
url: KEYCLOAK_URL
});
// initOption 지정
export const initOptions = {
onLoad: 'login-required',
checkLoginIframe: false,
};
// keycloak Event 를 보기 위한 함수 정의
// keycloak provider 의 onEvent 에 넣어준다.
export const onKeycloakEvent = (event: any, error: any) => {
console.log('keycloak event ', event, error);
switch (event) {
case 'onAuthLogout':
keycloak.logout();
break;
case 'onAuthRefreshError':
keycloak.logout();
break;
case 'onAuthRefreshSuccess':
console.log('auth token: ' + keycloak.token);
console.log('refresh token: ' + keycloak.refreshToken);
break;
default:
break;
}
};
export default keycloak;
initOptions
keycloak.init() 함수의 인자로 들어가게 된다.
keycloak 로그인 방식에 대한 설정을 지정할 수 있다.
onLoad
- login-reuqired : 프론트 처음 접속시 로그인이 되어 있지 않으면 바로 keycloak 로그인 페이지를 띄워준다.
- check-sso : 사용자가 로그인 되어져 있지 않으면 프론트 페이지로 redirect 시켜준다. 프론트는 그냥 로그인되지 않은 채로 남아있게 된다.
checkLoginIframe
login 되어져 있는지 자동으로 계속 모니터링 해준다. default 가 true 다.
true 로 해주면 keycloak url 의 iframe 이 생성된다.
checkLoginIframeInterval
login status 모니터링 하는 주기를 설정해준다. default 로 5초마다 검사한다.
이외에도 다른 옵션들이 존재한다. 다른 옵션들은 keycloak-js 문서를 참고하자.
useKeycloak
react-keycloak 이 제공한 hook 이다.
아래처럼 keycloak instance 를 가져오거나 초기화 여부를 알 수 있게 해준다.
import React, { useEffect } from 'react';
import { useKeycloak } from '@react-keycloak/web';
export default function App() {
const { keycloak, initialized } = useKeycloak();
// 아직 초기화 되지 않았으면 렌더링 하지 않는다.
// react-keycloak 의 LoadingComponent 를 이용해도 될 듯 싶다.
if (!initialized) {
return <></>;
}
return (
<div>
<div>{`User is ${
!keycloak.authenticated ? 'NOT ' : ''
}authenticated`}</div>
// usekeycloak 에서 authenticated 는 idToken 과 token 여부로 결정된다.
{!!keycloak.authenticated && (
<button type="button" onClick={() => keycloak.logout()}>
Logout
</button>
)}
</div>
}
userKeycloak 의 실제 구현은 다음과 같다.
구현체를 보면 알수 있듯이 react context 를 사용하고 있다. context 에서 초기화 상태와 keycloak instance 를 가져온다.
import { useContext } from 'react';
import { reactKeycloakWebContext } from './context';
export function useKeycloak() {
var ctx = useContext(reactKeycloakWebContext);
if (!ctx) {
throw new Error('useKeycloak hook must be used inside ReactKeycloakProvider context');
}
if (!ctx.authClient) {
throw new Error('authClient has not been assigned to ReactKeycloakProvider');
}
var authClient = ctx.authClient, initialized = ctx.initialized;
return {
initialized: initialized,
keycloak: authClient,
};
}
react keylcoak 에서는 keycloak instance 의 event 에 updateState 함수를 달아놓는다.
updateState 함수는 keyclok instance 가 초기화 되어있는지, 사용자가 인증되었는지를 판단해서 initliazed, authenticated 등의 값을 결정한다.
/* react-keycloak KeycloakProvider core 일부분*/
// mount 됐을 때, init 함수를 호출한다.
KeycloakProvider.prototype.componentDidMount = function () {
this.init();
};
KeycloakProvider.prototype.init = function () {
var _a = this.props, initOptions = _a.initOptions, authClient = _a.authClient;
// Attach Keycloak listeners
authClient.onReady = this.updateState('onReady');
authClient.onAuthSuccess = this.updateState('onAuthSuccess');
authClient.onAuthError = this.onError('onAuthError');
authClient.onAuthRefreshSuccess = this.updateState('onAuthRefreshSuccess');
authClient.onAuthRefreshError = this.onError('onAuthRefreshError');
authClient.onAuthLogout = this.updateState('onAuthLogout');
authClient.onTokenExpired = this.refreshToken('onTokenExpired');
// keycloak-js 의 init 함수를 호출한다. 이때 initOptions 를 인자로 넘긴다.
// 여기서 실제 keycloak-js 의 초기화 과정이 발생한다.
authClient
.init(__assign(__assign({}, defaultInitOptions), initOptions))
.catch(this.onError('onInitError'));
};
실제 Flow
1. Login 페이지 이동
onLoad 옵션을 'login-required' 로 설정해놓은 상태라면, 로그인 되어 있지 않으면 자동으로 keycloak 로그인 페이지로 이동한다.
check-sso 설정시에는 kecylok.login() 을 호출해줘야 한다.
로그인 페이지로 이동하면 url 의 pramaeter로 realm, client-id, 로그인 성공후 되돌아갈 주소인 redirect-uri 이 있는 것을 볼 수 있다.
redirect-uri 는 keycloak 설정시 옵션에 넣어줄 수 도 있고, 넣어주지 않았다면 default 로 로그인을 요청할 당시의 url 주소로 설정된다.
2. Lgoin 시도
Login 페이지에서 id/pw 입력후 로그인 버튼을 누르면 이는 keycloak 서버로 전송된다.
3. Frontend 로 redirect
keycloak 에서 valid 하다고 판단하면 redirect-uri 에 적어준 주소로 다시 이동한다.
(브라우저가 다시 frontend 페이지로 redirect 된다.)
이 때, code 방식의 token 교환방식을 설정했다면 url 뒤에 code 가 붙여서 온다.
이를 keycloak-js 가 init() 함수를 통해 초기화 할 때 url 을 파싱해 code 를 가져온다.
4. token 요청
post call 로 token 을 요청한다.
5. token 저장.
'기타 > Keycloak' 카테고리의 다른 글
keycloak js adapter 사용법 정리 (0) | 2020.11.14 |
---|