docker-compose.yaml и добавим в него данные:YAML
version: '3.8'
services:
keycloak_db:
image: postgres:14
environment:
POSTGRES_DB: keycloak_db
POSTGRES_USER: keycloak_user
POSTGRES_PASSWORD: keycloak_password
volumes:
- ./postgres-keycloak-data:/var/lib/postgresql/data
ports:
- "5433:5432" keycloak_db и пользователя для доступа в базу keycloak_user с паролем keycloak_password. ./postgres-keycloak-data. YAML
keycloak:
image: quay.io/keycloak/keycloak:21.1
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak_db:5432/keycloak_db
KC_DB_USERNAME: keycloak_user
KC_DB_PASSWORD: keycloak_password
command:
- start-dev
- --import-realm
volumes:
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json
ports:
- "8080:8080"
depends_on:
- keycloak_db Docker-compose.yaml полностью
YAML
version: '3.8'
services:
keycloak_db:
image: postgres:14
environment:
POSTGRES_DB: keycloak_db
POSTGRES_USER: keycloak_user
POSTGRES_PASSWORD: keycloak_password
volumes:
- ./postgres-keycloak-data:/var/lib/postgresql/data
ports:
- "5433:5432"
keycloak:
image: quay.io/keycloak/keycloak:21.1
environment:
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://keycloak_db:5432/keycloak_db
KC_DB_USERNAME: keycloak_user
KC_DB_PASSWORD: keycloak_password
command:
- start-dev
- --import-realm
volumes:
- ./keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json
ports:
- "8080:8080"
depends_on:
- keycloak_db
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
REACT_APP_API_URL: http://localhost:8000
REACT_APP_KEYCLOAK_URL: http://localhost:8080
REACT_APP_KEYCLOAK_REALM: reports-realm
REACT_APP_KEYCLOAK_CLIENT_ID: reports-frontend --import-realm. Это означает, что данные о пользователях, ролях и клиентах загружаются при старте. С той же целью мы прикладываем ./keycloak/realm-export.json.realm — это изолированная область, где управляются пользователи, роли, политики и клиенты. Каждый realm позволяет администратору настраивать параметры аутентификации, авторизации и контроля доступа для приложений.master-realm. Это основная область, используемая для административных задач, таких как создание и управление другими realm в системе. Только администраторы имеют доступ к master-realm.realm — reports-realm. Это пространство будет содержать все настройки, необходимые для аутентификации и авторизации пользователей, которые работают с нашими приложениями. Внутри reports-realm можно:reports-realm, не затрагивая другие realm или глобальные настройки Keycloak.realm полезно, если есть несколько проектов или команд, требующих разные политики безопасности. Reports-realm изолирует конфигурацию для вашего приложения и не конфликтует с другими realm, что делает систему более гибкой и безопасной.JSX
"realm": "reports-realm" JSX
"roles": {
"realm": [
{
"name": "user",
"description": "Regular user role"
},
{
"name": "administrator",
"description": "Administrator role"
},
{
"name": "prothetic_user",
"description": "Prothetic user role with report access"
}
] prothetic_user.JSX
{
"username": "prothetic1",
"enabled": true,
"email": "prothetic1@example.com",
"firstName": "Prothetic",
"lastName": "One",
"credentials": [
{
"type": "password",
"value": "prothetic123",
"temporary": false
}
],
"realmRoles": ["prothetic_user"]
}, JSX
"clients": [
{
"clientId": "reports-frontend",
"enabled": true,
"publicClient": true,
"redirectUris": ["http://localhost:3000/*"],
"webOrigins": ["http://localhost:3000"],
"directAccessGrantsEnabled": true
},
{
"clientId": "reports-api",
"enabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq",
"bearerOnly": true
} redirectUris указывает, куда Keycloak будет переводить пользователя. Параметр "directAccessGrantsEnabled": true разрешает клиенту использовать прямые гранты доступа, что позволяет входить в систему через API без перенаправления пользователя."bearerOnly": true указывает, что этот клиент только проверяет токены (bearer tokens) и не инициирует собственный поток аутентификации.keycloak/realm-export.json целиком
JSON
{
"realm": "reports-realm",
"enabled": true,
"roles": {
"realm": [
{
"name": "user",
"description": "Regular user role"
},
{
"name": "administrator",
"description": "Administrator role"
},
{
"name": "prothetic_user",
"description": "Prothetic user role with report access"
}
]
},
"users": [
{
"username": "user1",
"enabled": true,
"email": "user1@example.com",
"firstName": "User",
"lastName": "One",
"credentials": [
{
"type": "password",
"value": "password123",
"temporary": false
}
],
"realmRoles": ["user"]
},
{
"username": "user2",
"enabled": true,
"email": "user2@example.com",
"firstName": "User",
"lastName": "Two",
"credentials": [
{
"type": "password",
"value": "password123",
"temporary": false
}
],
"realmRoles": ["user"]
},
{
"username": "admin1",
"enabled": true,
"email": "admin1@example.com",
"firstName": "Admin",
"lastName": "One",
"credentials": [
{
"type": "password",
"value": "admin123",
"temporary": false
}
],
"realmRoles": ["administrator"]
},
{
"username": "prothetic1",
"enabled": true,
"email": "prothetic1@example.com",
"firstName": "Prothetic",
"lastName": "One",
"credentials": [
{
"type": "password",
"value": "prothetic123",
"temporary": false
}
],
"realmRoles": ["prothetic_user"]
},
{
"username": "prothetic2",
"enabled": true,
"email": "prothetic2@example.com",
"firstName": "Prothetic",
"lastName": "Two",
"credentials": [
{
"type": "password",
"value": "prothetic123",
"temporary": false
}
],
"realmRoles": ["prothetic_user"]
},
{
"username": "prothetic3",
"enabled": true,
"email": "prothetic3@example.com",
"firstName": "Prothetic",
"lastName": "Three",
"credentials": [
{
"type": "password",
"value": "prothetic123",
"temporary": false
}
],
"realmRoles": ["prothetic_user"]
}
],
"clients": [
{
"clientId": "reports-frontend",
"enabled": true,
"publicClient": true,
"redirectUris": ["http://localhost:3000/*"],
"webOrigins": ["http://localhost:3000"],
"directAccessGrantsEnabled": true
},
{
"clientId": "reports-api",
"enabled": true,
"clientAuthenticatorType": "client-secret",
"secret": "oNwoLQdvJAvRcL89SydqCWCe5ry1jMgq",
"bearerOnly": true
}
]
} docker-compose. Но есть и другой способ — настроить новый realm вручную, вставив JSON в импорт или загрузив его же через интерфейс.docker-compose up -d build и ждать, когда всё соберётся и запустится.Инструкция по настройке Realm через интерфейс
Resourse file наш файл JSON.reports-frontend и reports-api.redirectUris был указан: после успешного логина пользователя переведут по этому адресу..well-known/openid-configuration.YAML
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
REACT_APP_API_URL: http://localhost:8000
REACT_APP_KEYCLOAK_URL: http://localhost:8080
REACT_APP_KEYCLOAK_REALM: reports-realm
REACT_APP_KEYCLOAK_CLIENT_ID: reports-frontend TSX
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
); TSX
import React from 'react';
import { ReactKeycloakProvider } from '@react-keycloak/web';
import Keycloak, { KeycloakConfig } from 'keycloak-js';
import ReportPage from './components/ReportPage';
const keycloakConfig: KeycloakConfig = {
url: process.env.REACT_APP_KEYCLOAK_URL,
realm: process.env.REACT_APP_KEYCLOAK_REALM||"",
clientId: process.env.REACT_APP_KEYCLOAK_CLIENT_ID||""
};
const keycloak = new Keycloak(keycloakConfig);
const App: React.FC = () => {
return (
<ReactKeycloakProvider authClient={keycloak}>
<div className="App">
<ReportPage />
</div>
</ReactKeycloakProvider>
);
};
export default App;
TSX
import React, { useState } from 'react';
import { useKeycloak } from '@react-keycloak/web';
const ReportPage: React.FC = () => {
const { keycloak, initialized } = useKeycloak();
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const downloadReport = async () => {
if (!keycloak?.token) {
setError('Not authenticated');
return;
}
try {
setLoading(true);
setError(null);
const response = await fetch(`${process.env.REACT_APP_API_URL}/reports`, {
headers: {
'Authorization': `Bearer ${keycloak.token}`
}
});
} catch (err) {
setError(err instanceof Error ? err.message : 'An error occurred');
} finally {
setLoading(false);
}
};
if (!initialized) {
return <div>Loading...</div>;
}
if (!keycloak.authenticated) {
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
<button
onClick={() => keycloak.login()}
className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
>
Login
</button>
</div>
);
}
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-100">
<div className="p-8 bg-white rounded-lg shadow-md">
<h1 className="text-2xl font-bold mb-6">Usage Reports</h1>
<button
onClick={downloadReport}
disabled={loading}
className={`px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 ${
loading ? 'opacity-50 cursor-not-allowed' : ''
}`}
>
{loading ? 'Generating Report...' : 'Download Report'}
</button>
{error && (
<div className="mt-4 p-4 bg-red-100 text-red-700 rounded">
{error}
</div>
)}
</div>
</div>
);
};
export default ReportPage;
docker-compose.yml. В нём задаются конфигурации сервиса, тип базы данных, учётные данные для подключения, порты и основные параметры для работы. Это позволяет быстро и централизованно управлять конфигурацией и запуском сервиса.