docker compose fullstack example -- keycloak web grant-type: password
fastapi-react-postgres-keycloak-sso
https://github.com/fanqingsong/fastapi-react-postgres-keycloak-sso
version: "3"
services:
nginx:
image: nginx:1.17
volumes:
- ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf
- ./logs/nginx:/var/log/nginx
ports:
- 80:80
depends_on:
- frontend
- backend
backend:
restart: unless-stopped
build:
context: backend
dockerfile: Dockerfile
env_file:
- .env
environment:
PYTHONPATH: .
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_USER}
volumes:
- ./logs/backend:/logs
ports:
- 8888:8888
depends_on:
- postgres
- keycloak
frontend:
build:
context: frontend
dockerfile: Dockerfile
ports:
- 8000:8000
environment:
NODE_ENV: development
CHOKIDAR_USEPOLLING: "true"
keycloak:
image: jboss/keycloak:12.0.4
environment:
DB_VENDOR: POSTGRES
DB_SCHEMA: public
DB_ADDR: keycloak_postgres
DB_DATABASE: ${KEYCLOAK_DB_DATABASE}
DB_USER: ${KEYCLOAK_DB_USER}
DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
KEYCLOAK_USER: ${KEYCLOAK_ADMIN_USERNAME}
KEYCLOAK_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
JDBC_PARAMS: "useSSL=false"
ports:
- 8080:8080
depends_on:
- keycloak_postgres
postgres:
image: postgres
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
ports:
- 5432:5432
volumes:
- postgres_data:/var/lib/postgresql/data
keycloak_postgres:
image: postgres
volumes:
- keycloak_postgres_data:/var/lib/postgresql/data
environment:
POSTGRES_DB: ${KEYCLOAK_DB_DATABASE}
POSTGRES_USER: ${KEYCLOAK_DB_USER}
POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD}
volumes:
postgres_data:
keycloak_postgres_data:
frontend docker wrapper
https://typeofnan.dev/how-to-serve-a-react-app-with-nginx-in-docker/
FROM node:lts as build WORKDIR /app COPY ./app/ /app RUN npm install --legacy-peer-deps --registry=https://registry.npm.taobao.org RUN npm run build FROM nginx COPY ./nginx.conf /etc/nginx/conf.d/angular.conf COPY --from=build /app/build /usr/share/nginx/html RUN chmod -R o+r /usr/share/nginx/html/
env set
https://docs.docker.com/compose/environment-variables/set-environment-variables/
.env文件向docker compose文件注入环境变量
docker compose文件中的
env-file
environment
属性,可以向容器内注入环境变量。
python-keycloak
https://python-keycloak.readthedocs.io/en/latest/
from keycloak import KeycloakOpenID
# Configure client
keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/",
client_id="example_client",
realm_name="example_realm",
client_secret_key="secret")
# Get WellKnown
config_well_known = keycloak_openid.well_known()
# Get Code With Oauth Authorization Request
auth_url = keycloak_openid.auth_url(
redirect_uri="your_call_back_url",
scope="email",
state="your_state_info")
# Get Access Token With Code
access_token = keycloak_openid.token(
grant_type='authorization_code',
code='the_code_you_get_from_auth_url_callback',
redirect_uri="your_call_back_url")
# Get Token
token = keycloak_openid.token("user", "password")
token = keycloak_openid.token("user", "password", totp="012345")
# Get token using Token Exchange
token = keycloak_openid.exchange_token(token['access_token'], "my_client", "other_client", "some_user")
# Get Userinfo
userinfo = keycloak_openid.userinfo(token['access_token'])
# Refresh token
token = keycloak_openid.refresh_token(token['refresh_token'])
# Logout
keycloak_openid.logout(token['refresh_token'])
usage
"""Module used for keycloak backend calls.""" import os import typing as tp from fastapi import Depends, HTTPException from fastapi.security import OAuth2PasswordBearer from jose.exceptions import JWTError from keycloak.exceptions import KeycloakAuthenticationError, KeycloakGetError from keycloak.keycloak_openid import KeycloakOpenID REALM = 'master' KEYCLOAK_BASEURL = f'http://localhost:8080/auth/realms' \ f'/{REALM}/protocol/openid-connect' oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{KEYCLOAK_BASEURL}/token") keycloak_openid = KeycloakOpenID( server_url=os.environ.get("KEYCLOAK_SERVER_URL"), realm_name=os.environ.get("KEYCLOAK_REALM_NAME"), client_id=os.environ.get("KEYCLOAK_CLIENT_ID"), client_secret_key=os.environ.get("KEYCLOAK_CLIENT_SECRET_KEY"), ) KEYCLOAK_PUBLIC_KEY = ( "-----BEGIN PUBLIC KEY-----\n" f"{keycloak_openid.public_key()}" "\n-----END PUBLIC KEY-----" ) async def authenticate_user(username: str, password: str) -> tp.Dict[str, str]: """Authenticate user with Keycloak backend. Args: username password Returns: Access token and refresh token with their expiration time """ try: return keycloak_openid.token(username, password) except KeycloakAuthenticationError as error: raise HTTPException(status_code=401, detail="Invalid credentials") from error async def verify_token(token: str = Depends(oauth2_scheme)) -> tp.Dict[str, str]: """Verify token with Keycloak public key. Args: token: access token to decode Returns: Token decoded """ try: return keycloak_openid.decode_token( token, key=KEYCLOAK_PUBLIC_KEY, options={"verify_signature": True, "verify_aud": False, "exp": True}, ) except (KeycloakGetError, JWTError) as error: raise HTTPException( status_code=401, detail=str(error), headers={"WWW-Authenticate": "Bearer"} ) from error async def refresh_token(token: str) -> tp.Dict[str, str]: try: return keycloak_openid.refresh_token(token) except (KeycloakGetError) as error: raise HTTPException(status_code=401, detail=str(error)) from error async def logout(token: str) -> tp.Dict[str, str]: try: return keycloak_openid.logout(token) except (KeycloakGetError) as error: raise HTTPException(status_code=401, detail=str(error)) from error
出处:http://www.cnblogs.com/lightsong/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

浙公网安备 33010602011771号