React & Keycloakでユーザー認証する


React & Keycloakでユーザー認証する

目標

  • Reactでユーザー認証
  • 認証にはKeycloakを使う
  • docker-composeで一発立ち上げ

リポジトリ

Keycloak

今回はDBにMySQLを使う。

Keycloakの設定

以下のdocker-composeを使って一度Keycloakを起動する。
http://localhost:8080を開いて管理画面からRealmとClient、Userを追加する。

docker-compose.yml
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/
  • User:

Installationファイルの取得

Clients>demo-client>InstallationからKeycloak OIDC JSONをダウンロードする。

keycloak.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を作成する。

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がやってくれる!

Secured.tsx
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化する。

Dockerfile
FROM node:latest

WORKDIR /app

COPY package.json /app
RUN npm install

COPY . /app
RUN npm run build

CMD ["npm", "start"]

DockerCompose化

最後の仕上げ。

docker-compose.yml
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/をブラウザで開く。

[email protected]/password

おおー!

感想

こんなにも簡単にフロントエンドのSSO認証を実装できるなんて!

参考文献

USER AUTHENTICATION WITH KEYCLOAK – PART 1: REACT FRONT-END
https://scalac.io/user-authentication-keycloak-1/