Я интегрирую аутентификацию keycloak в свое приложение django.
После того, как я вошел в систему на сервере keycloak, я столкнулся с ошибкой в обратном вызове входа в систему. HTTPError в /oidc/callback/ 401 Ошибка клиента: не авторизован для URL-адреса: http://keycloak:8080/realms/SquadStack/protocol/openid-connect/userinfo
вот мой docker-compose.yml
services:
db:
image: postgres:13
environment:
- POSTGRES_DB=squadrun
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=123456
volumes:
- ~/.siq/pg_data:/var/lib/postgresql/data
ports:
- "5432:5432"
networks:
- local-keycloak
redis:
image: redis
expose:
- 6379
networks:
- local-keycloak
celery:
build:
context: .
dockerfile: Dockerfile
command: celery --app=squadrun worker -Q voice_make_ivr_india_queue,voice_send_email_india_queue,voice_send_email_india_upstox_queue,voice_send_sms_india_queue,voice_workflow_india_queue,celery_voice,ivr_queue,voice_analytics_and_metrics_queue,voice_fsm_india_queue,dnd_queue,voice_bulk_sync,voice_dnd_and_compliance_actions_queue,voice_notifications_queue,voice_make_ivr_india_queue,voice_send_email_india_queue,voice_send_email_india_upstox_queue,voice_send_sms_india_queue,voice_sync_ivr_details_india_queue,voice_workflow_india_queue,voice_sync_sms_details_india_queue,voice_send_sms_india_upstox_queue,voice_dnd_and_compliance_actions_upstox_queue,voice_imports_queue --concurrency=3 --without-heartbeat --without-gossip -n celery.%%h --loglevel=INFO
container_name: celery
working_dir: /home/docker/code
volumes:
- .:/home/docker/code
depends_on:
- db
- redis
networks:
- local-keycloak
web:
build:
context: .
dockerfile: Dockerfile
command: python -Wignore manage.py runserver 0.0.0.0:8001
container_name: django_web3
volumes:
- .:/home/docker/code
ports:
- "8001:8001"
depends_on:
- db
- redis
networks:
- local-keycloak
keycloak:
image: quay.io/keycloak/keycloak:20.0.2
command: start-dev
container_name: keycloak
ports:
- "8080:8080"
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
networks:
- local-keycloak
networks:
local-keycloak:
driver: bridge
вот моя настройка.py
AUTHENTICATION_BACKENDS = [
'apps.voice.voice_auth.auth.KeycloakOIDCAuthenticationBackend',
'django.contrib.auth.backends.ModelBackend',
]
OIDC_RP_CLIENT_ID = "voice-dashboard"
OIDC_RP_CLIENT_SECRET = "rnX0eo0R43xnZficrZTkQQseyBip4V7t"
OIDC_RP_SIGN_ALGO = "RS256"
OIDC_OP_JWKS_ENDPOINT = "http://keycloak:8080/realms/SquadStack/protocol/openid-connect/certs"
OIDC_OP_AUTHORIZATION_ENDPOINT = "http://172.20.0.3:8080/realms/SquadStack/protocol/openid-connect/auth"
OIDC_OP_TOKEN_ENDPOINT = "http://keycloak:8080/realms/SquadStack/protocol/openid-connect/token"
OIDC_OP_USER_ENDPOINT = "http://keycloak:8080/realms/SquadStack/protocol/openid-connect/userinfo"
LOGIN_REDIRECT_URL = "/voice/dashboard/index/"
LOGOUT_REDIRECT_URL = "/voice/dashboard/index/"
вот auth.py
class KeycloakOIDCAuthenticationBackend(OIDCAuthenticationBackend):
def create_user(self, claims):
""" Overrides Authentication Backend so that Django users are
created with the keycloak preferred_username.
If nothing found matching the email, then try the username.
"""
user = super(KeycloakOIDCAuthenticationBackend, self).create_user(claims)
user.first_name = claims.get('given_name', '')
user.last_name = claims.get('family_name', '')
user.email = claims.get('email')
user.username = claims.get('preferred_username')
user.save()
return user
def filter_users_by_claims(self, claims):
""" Return all users matching the specified email.
If nothing found matching the email, then try the username
"""
email = claims.get('email')
preferred_username = claims.get('preferred_username')
if not email:
return self.UserModel.objects.none()
users = self.UserModel.objects.filter(email__iexact=email)
if len(users) < 1:
if not preferred_username:
return self.UserModel.objects.none()
users = self.UserModel.objects.filter(username__iexact=preferred_username)
return users
def update_user(self, user, claims):
user.first_name = claims.get('given_name', '')
user.last_name = claims.get('family_name', '')
user.email = claims.get('email')
user.username = claims.get('preferred_username')
user.save()
return user
журналы джанго
django_web3 | django 02/Jan/2023:14:02:14,278955 +0000 [ERROR] django.request: thread=281473135460832 extra:status_code=500&request=<WSGIRequest:GET'/oidc/callback/?state=R1OaaRk4jfr5nNNI4gr5CSdfX6sXoEqg&session_state=ea277a99-7da4-4904-abb6-63fa9bb7fb75&code=4b3c49b6-11c9-4cef-b847-fe356dfe86c3.ea277a99-7da4-4904-abb6-63fa9bb7fb75.bad660f7-7969-42d3-8475-536e4955c554'> Internal Server Error: /oidc/callback/
django_web3 | Traceback (most recent call last):
django_web3 | File "/usr/local/lib/python3.5/site-packages/django/core/handlers/base.py", line 149, in get_response
django_web3 | response = self.process_exception_by_middleware(e, request)
django_web3 | File "/usr/local/lib/python3.5/site-packages/django/core/handlers/base.py", line 147, in get_response
django_web3 | response = wrapped_callback(request, *callback_args, **callback_kwargs)
django_web3 | File "/usr/local/lib/python3.5/site-packages/django/views/generic/base.py", line 68, in view
django_web3 | return self.dispatch(request, *args, **kwargs)
django_web3 | File "/usr/local/lib/python3.5/site-packages/django/views/generic/base.py", line 88, in dispatch
django_web3 | return handler(request, *args, **kwargs)
django_web3 | File "/usr/local/lib/python3.5/site-packages/mozilla_django_oidc/views.py", line 88, in get
django_web3 | self.user = auth.authenticate(**kwargs)
django_web3 | File "/usr/local/lib/python3.5/site-packages/django/contrib/auth/__init__.py", line 74, in authenticate
django_web3 | user = backend.authenticate(**credentials)
django_web3 | File "/usr/local/lib/python3.5/site-packages/mozilla_django_oidc/auth.py", line 242, in authenticate
django_web3 | return self.get_or_create_user(access_token, id_token, verified_id)
django_web3 | File "/usr/local/lib/python3.5/site-packages/mozilla_django_oidc/auth.py", line 259, in get_or_create_user
django_web3 | user_info = self.get_userinfo(access_token, id_token, verified_id)
django_web3 | File "/usr/local/lib/python3.5/site-packages/mozilla_django_oidc/auth.py", line 202, in get_userinfo
django_web3 | user_response.raise_for_status()
django_web3 | File "/usr/local/lib/python3.5/site-packages/requests/models.py", line 943, in raise_for_status
django_web3 | raise HTTPError(http_error_msg, response=self)
django_web3 | requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: http://keycloak:8080/realms/SquadStack/protocol/openid-connect/userinfo
django_web3 | django 02/Jan/2023:14:02:14,398185 +0000 [INFO] qinspect.middleware: thread=281473135460832 extra: [SQL] 0 queries (0 duplicates), 0 ms SQL time, 201 ms total request time
django_web3 | [02/Jan/2023 19:32:14] "GET /oidc/callback/?state=R1OaaRk4jfr5nNNI4gr5CSdfX6sXoEqg&session_state=ea277a99-7da4-4904-abb6-63fa9bb7fb75&code=4b3c49b6-11c9-4cef-b847-fe356dfe86c3.ea277a99-7da4-4904-abb6-63fa9bb7fb75.bad660f7-7969-42d3-8475-536e4955c554 HTTP/1.1" 500 269936
Эта проблема такая же, как эта https://github.com/mozilla/mozilla-django-oidc/issues/481 В соответствии с этим решением я думаю, что мне нужно изменить OIDC_OP_AUTHORIZATION_ENDPOINT на "http://keycloak:8080/realms/SquadStack/protocol/openid-connect/auth" но я не могу зайти на этот сайт http://keycloak:8080 Я не могу связаться с сервером keycloak, используя имя контейнера докеров вместо localhost в имени хоста я не могу понять, связана ли проблема с докером, mozilla-django-oidc или Keycloak, и я застрял здесь Я новичок в докере, и keycloak, возможно, сделал какую-то наивную ошибку Любая помощь будет оценена!
Я использовал kubernetes.docker.internal в качестве доменного имени вместо localhost и keycloak, что решает мою проблему. Мои измененные настройки:
KEYCLOACK_BASE_URI = "http://kubernetes.docker.internal:8080"
KEYCLOACK_REALM_NAME = "SquadStack"
OIDC_AUTH_URI = KEYCLOACK_BASE_URI + "/realms/" + KEYCLOACK_REALM_NAME
OIDC_OP_JWKS_ENDPOINT = OIDC_AUTH_URI + "/protocol/openid-connect/certs"
OIDC_OP_AUTHORIZATION_ENDPOINT = OIDC_AUTH_URI + "/protocol/openid-connect/auth"
OIDC_OP_TOKEN_ENDPOINT = OIDC_AUTH_URI + "/protocol/openid-connect/token"
OIDC_OP_USER_ENDPOINT = OIDC_AUTH_URI + "/protocol/openid-connect/userinfo"
OIDC_OP_LOGOUT_ENDPOINT = OIDC_AUTH_URI + "/protocol/openid-connect/logout"