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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。