React & Keycloakでユーザー認証する
目標
- Reactでユーザー認証
- 認証にはKeycloakを使う
- docker-composeで一発立ち上げ
リポジトリ
Keycloak
今回はDBにMySQLを使う。
Keycloakの設定
以下のdocker-composeを使って一度Keycloakを起動する。
http://localhost:8080
を開いて管理画面からRealmとClient、Userを追加する。
version: '3'
services:
keycloak:
image: jboss/keycloak:6.0.1
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: password
DB_VENDOR: MYSQL
DB_ADDR: keycloak-db
DB_DATABASE: keycloak
DB_USER: keycloak
DB_PASSWORD: password
ports:
- 8080:8080
depends_on:
- keycloak-db
keycloak-db:
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: password
今回は以下のように登録した。
- Realm:
demo
- Client:
- Client ID:
demo-client
- RootURL:
http://localhost:3000/
- Client ID:
- User:
- FirstName:
John
- LastName:
Smith
- EMail:
john.smith@mail.com
- Password:
passward
- FirstName:
Installationファイルの取得
Clients>demo-client>Installation
からKeycloak OIDC JSON
をダウンロードする。
{
"realm": "demo",
"auth-server-url": "http://localhost:8080/auth",
"ssl-required": "external",
"resource": "demo-client",
"public-client": true,
"confidential-port": 0
}
データのExport
Keycloakのプロセスに入って以下のコマンドを打ち込む。
投入したデータが指定したファイルにExportされたあとKeycloakが再起動する。
# keycloak/bin/standalone.sh \
-Djboss.socket.binding.port-offset=100 \
-Dkeycloak.migration.action=export \
-Dkeycloak.migration.provider=singleFile \
-Dkeycloak.migration.realmName=demo \
-Dkeycloak.migration.usersExportStrategy=REALM_FILE \
-Dkeycloak.migration.file=/tmp/import-demo.json
Exportされたjsonを回収する。
$ docker cp <CONTAINER ID>:/tmp/import-demo.json import-demo.json
Dockerfileの作成
初回起動時にExportしたjsonをImport出来るようにDockerfile
を作成する。
FROM jboss/keycloak:6.0.1
ADD import-demo.json /opt/jboss/keycloak/
CMD ["-b", "0.0.0.0", "-Dkeycloak.import=/opt/jboss/keycloak/import-demo.json"]
これでKeycloakの初回起動時にRealmとClient、UserがImportされるようになった。
React
今回はTypeScriptで実装
プロジェクトの作成
create-react-app
等でざっくりプロジェクトを作る。
$ npx create-react-app react-spa-keycloak --scripts-version=react-scripts-ts
keycloak-js
をインストール。
見た目も多少魅せたいからBootstrap追加。
$ npm install keycloak-js
$ npm install bootstrap
$ npm install react-bootstrap
public
ディレクトリに前項で取得したkeycloak.json
を配置する。
キモになる部分はこの部分。
keycloakによるログインが必須であること、認証が成功したときのみUserInfo.tsx
を
表示することを書くだけ。
煩わしい認証処理は全てkeycloak-js
がやってくれる!
const Secured: React.FC = () => {
const keycloak = Keycloak('/keycloak.json');
const [keycloakState, setKeycloakState] = useState<KeycloakState>({keycloak: null, authenticated: false});
useEffect(() => {
keycloak.init({onLoad: 'login-required'})
.success((authenticated) => {
setKeycloakState({keycloak: keycloak, authenticated: authenticated});
});
}, []);
if (keycloakState.keycloak !== null) {
if (keycloakState.authenticated) {
return (
<div>
<Alert variant="success">
<Alert.Heading>Authenticated</Alert.Heading>
</Alert>
<UserInfo keycloakState={keycloakState}/>
<Logout keycloakState={keycloakState}/>
</div>
);
} else {
return (
<div>
<Alert variant="danger">
<Alert.Heading>Unable to authenticate</Alert.Heading>
</Alert>
</div>
)
}
}
return (
<div>
<p>Initializing Keycloak...</p>
</div>
);
};
export default Secured;
Dockerfileの作成
ReactアプリケーションもDocker化する。
FROM node:latest
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
RUN npm run build
CMD ["npm", "start"]
DockerCompose化
最後の仕上げ。
version: '3'
services:
keycloak:
build: ./keycloak
environment:
KEYCLOAK_USER: admin
KEYCLOAK_PASSWORD: password
DB_VENDOR: MYSQL
DB_ADDR: keycloak-db
DB_DATABASE: keycloak
DB_USER: keycloak
DB_PASSWORD: password
ports:
- 8080:8080
depends_on:
- keycloak-db
keycloak-db:
image: mysql:5.7
volumes:
- ./keycloak/db:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: password
react-spa-keycloak:
build: .
ports:
- 3000:3000
実行
docker-compose up
http://localhost:3000/
をブラウザで開く。
john.smith@email.com/password
おおー!
感想
こんなにも簡単にフロントエンドのSSO認証を実装できるなんて!
参考文献
USER AUTHENTICATION WITH KEYCLOAK – PART 1: REACT FRONT-END
https://scalac.io/user-authentication-keycloak-1/