본문 바로가기
공부/Python

[Django] admin에 keycloak login 붙이기

by haejang 2024. 3. 30.
728x90
728x90

 

 

# 이미 존재하는 것

  • 장고 프로젝트 (with django-admin-interface)
  • 연동할 키클락

 

# 원하는 것

장고 어드민의 기본 로그인 화면은 아래와 같다. (admin_interface를 사용하는 경우)

 

LOG IN 버튼 밑에 Keycloak용 로그인 버튼을 만들고, 키클락 유저로 로그인 가능하도록 만들겠다.

 

# 시작! 🚀

1) social auth 세팅

social-auth-app-django 설치

pip install social-auth-app-django

 

settings.py에 social_django 추가

# settings.py
INSTALLED_APPS = [
    ...
    'social_django', # 추가
]

 

migration 수행

python manage.py migrate

 

여기까지 하면, python social auth 탭이 생긴 것을 확인할 수 있다.

 

2) keycloak 세팅

keycloak과 realm은 이미 있다는 가정 하에, client부터 만들어본다.

Create client
client id & name 설정
client authentication ON
Valid redirect URIs / Web origins에 모두 *로 허용해주자. 깎는건 알아서..
Credentails 탭에서 Client Secret을 복사해두자.

방금 복사한 시크릿은 SOCIAL_AUTH_KEYCLOAK_SECRET 로 쓰이게 된다.

 

Client > Client scopes > {client 이름}-dedicated 클릭
Configure a new mapper
Audience 클릭

  • Included Client Audience : 클라이언트 선택
  • Add to access token : ON

Audience mapper까지 만들었으니, 이제 Public key만 복사하면 keycloak에서 할 일은 끝이다.

Realm settings > Keys > RS256 Public Key 클릭

 

이 public key는 SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY 로 쓰이게 된다.

 

3) django - keycloak 연동

settings.py에 아래 내용들을 추가한다.

# Keycloak 설정
AUTHENTICATION_BACKENDS = (
    'social_core.backends.keycloak.KeycloakOAuth2',  # Keycloak 백엔드 추가
    'django.contrib.auth.backends.ModelBackend',
)

SOCIAL_AUTH_KEYCLOAK_KEY = '본인_키클락_클라이언트_이름'
SOCIAL_AUTH_KEYCLOAK_SECRET = '본인_키클락_클라이언트_시크릿'
SOCIAL_AUTH_KEYCLOAK_PUBLIC_KEY = '본인_키클락_퍼블릭_키'
SOCIAL_AUTH_KEYCLOAK_DOMAIN = '본인_키클락_도메인'
SOCIAL_AUTH_KEYCLOAK_REALM = '본인_키클락_REALM'
SOCIAL_AUTH_KEYCLOAK_AUTHORIZATION_URL = 'https://{domain}/realms/{realm}/protocol/openid-connect/auth'.format(domain=SOCIAL_AUTH_KEYCLOAK_DOMAIN, realm=SOCIAL_AUTH_KEYCLOAK_REALM)
SOCIAL_AUTH_KEYCLOAK_ACCESS_TOKEN_URL = 'https://{domain}/realms/{realm}/protocol/openid-connect/token'.format(domain=SOCIAL_AUTH_KEYCLOAK_DOMAIN, realm=SOCIAL_AUTH_KEYCLOAK_REALM)
SOCIAL_AUTH_KEYCLOAK_USERINFO_URL = 'https://{domain}/realms/{realm}/protocol/openid-connect/userinfo'.format(domain=SOCIAL_AUTH_KEYCLOAK_DOMAIN, realm=SOCIAL_AUTH_KEYCLOAK_REALM)
SOCIAL_AUTH_JWT_AUDIENCE = None

SOCIAL_AUTH_PIPELINE = (
    'social_core.pipeline.social_auth.social_details',
    'social_core.pipeline.social_auth.social_uid',
    'social_core.pipeline.social_auth.social_user',
    'social_core.pipeline.user.get_username',
    'social_core.pipeline.user.create_user',
    'social_core.pipeline.social_auth.associate_user',
    'social_core.pipeline.social_auth.load_extra_data',
    'social_core.pipeline.user.user_details',
)

 

urls.py에 아래 내용을 추가해준다.

urls.py

urlpatterns = [
    ...
    path('social-auth/', include('social_django.urls', namespace='social')),
]

 

 

admin login 페이지를 수정해야 하므로... templates/admin/login.html 파일을 추가해주자.

여기서 참고로, 내 프로젝트의 tree는 아래와 같다.

.
├── manage.py
├── honglab
│   ├── __init__.py
│   ├── asgi.py
│   ├── wsgi.py
│   ├── urls.py
│   └── settings.py
├── templates
│   └── admin
│       └── login.html
└── db.sqlite3

 

이 구조에서 templates/admin/login.html을 아래와 같이 작성해준다.

{% extends "admin/login.html" %}
{% block content %}
<div id="content-main">
    {{ block.super }}  <!-- 기존 로그인 폼을 불러옵니다. -->
    <!-- Keycloak 로그인 버튼 추가 -->
    <div class="submit-row">
        <input type="button" value="Keycloak 로그인" 
               onclick="location.href='{% url 'social:begin' 'keycloak' %}?next={{ request.GET.next }}'"
               style="background: #ff3d00; color: white; width: 100%;">
    </div>
</div>
{% endblock %}

 

settings.py에서 TEMPLATES 의 DIRS를 수정해준다.

TEMPLATES = [
    {
        ...
        'DIRS': [BASE_DIR / "templates"], # 본인 templates 폴더 위치에 맞게 적절히 조정
        ...
    },
]

 

migration 한번 더 해주자

python manage.py migrate

 

다시 서버 띄워서 admin 접근해보면...

오!! 원하는대로 keycloak 로그인 버튼이 이쁘게 뜬다.

(버튼색은 admin.html 파일에서 알아서 고치자)

 

내 keycloak client에는 test란 유저가 존재한다. > 해당 유저로 로그인 해봤는데...

test란 유저는 접근권한이 없다고 뜬다.

당연하다. django admin 페이지에 접속하기 위해서는 staff 권한이 존재해야 한다.

 

일단 다시 admin 유저(superuser)로 로그인해보자.

test란 유저가 생성은 되어 있다.

staff도 주고, superuser도 줘보자.

그리고 다시 test로 로그인하면..

test 유저로 admin 페이지 접근에 성공했다.

 

그러나 키클락 유저가 처음 로그인할때마다 매번 staff 권한을 넣어주려면 너무 번거롭겠지?

키클락유저의 그룹을 확인해서, 특정 그룹에 따라 staff / superuser 권한을 넣어줘보자.

 

4) keycloak 그룹 연동

먼저 키클락에서 test용 group을 만들어줬다.

django-staff는 staff 권한만, django-superuser는 superuser 권한까지 줄 것이다.

staff-user : django-staff 그룹 조인

super-user : django-superuser 그룹 조인

 

그리고 openid client scope를 만들어줘야 한다.

Create client scope

  • Name : openid
  • Type : Default

 

마지막으로 group membership에 대한 mapper를 만들어줘야 한다.

Client&nbsp;> Client scopes > {client 이름}-dedicated 클릭

Add mapper > By configuration > Group Membership을 클릭해준다.

Name, Token Claim Name 설정해주고, Add to access token을 활성화시켜준다.

 

이제 django project로 돌아와, pipeline을 추가해주자.

일단 pipeline은 core라는 app을 만들어서 그 안에 위치시킬 생각이다.

python manage.py startapp core

 

core/pipeline.py 파일을 생성해주자.

# core/pipeline.py
from django.contrib.auth.models import Group

def save_keycloak_groups(backend, user, response, *args, **kwargs):
    if backend.name == 'keycloak':
        keycloak_groups = response.get('groups', [])
        print(keycloak_groups)

        # Django의 Group 모델과 연동하여 사용자에게 그룹을 할당
        for group_name in keycloak_groups:
            # Django Group 모델에서 그룹을 찾거나 새로 생성
            group, created = Group.objects.get_or_create(name=group_name)

            # 사용자를 그룹에 추가
            user.groups.add(group)

        # 변경사항을 저장
        user.save()

def rbac_for_admin(backend, user, response, *args, **kwargs):
    if backend.name == 'keycloak':
        keycloak_groups = response.get('groups', [])

        # django-staff -> staff 권한 자동 획득
        if 'django-staff' in keycloak_groups:
            user.is_staff = True
            user.save()
        # django-superuser -> staff & superuser 권한 자동 획득
        if 'django-superuser' in keycloak_groups:
            user.is_staff = True
            user.is_superuser = True
            user.save()

 

메인 앱 (여기서는 홍랩) 의 settings.py를 손봐주자.

# honglab/settings.py

INSTALLED_APPS = [
    'core', # 추가
    ...
]

SOCIAL_AUTH_PIPELINE = (
    ...
    'core.pipeline.save_keycloak_groups', # 추가
    'core.pipeline.rbac_for_admin',       # 추가
)

 

마이그레이션이 필요하면 해주고, staff-user로 로그인해보자.

staff 권한은 있지만, 아무 모델에 대해서도 권한이 없기 때문에 이렇게만 보인다.

이번엔 super-user로 로그인해보겠다.

모든 메뉴가 잘 보인다.

Groups를 확인해보면,

키클락 그룹이 잘 연동되어 저장된 것을 확인할 수 있다.

 

위 내용들은 모두 github에 올려두었다.

https://github.com/suminhong/django/tree/main/admin-keycloak-login

 

django/admin-keycloak-login at main · suminhong/django

Contribute to suminhong/django development by creating an account on GitHub.

github.com

 

끝!

 

 

 

728x90
728x90

댓글