장고 OAuth2.0 제공

Pywiki
둘러보기로 가기 검색하러 가기

1 개요[편집 | 원본 편집]

django-oauth-toolkit을 통해 OAuth2.0 로그인을 제공한다. 공식 문서(https://django-oauth-toolkit.readthedocs.io/en/latest/)

애시당초 공급을 목표로 하는 라이브러리.

이미 로그인 뷰 등 기본적인 서비스는 구현된 상태라 가정한다.

과정 설명 비고
설치 pip install django-oauth-toolkit
settings.py 설정
INSTALLED_APPS += [
    "oauth2_provider",
]
AUTHENTICATION_BACKENDS = [  # 보통 소셜로그인 등을 구현했다면 이미 있음.
    "django.contrib.auth.backends.ModelBackend",
]
OAUTH2_PROVIDER = {
    # 토큰 만료 시간(초)
    "ACCESS_TOKEN_EXPIRE_SECONDS": 36000,
}
url 등록
path("o/", include("oauth2_provider.urls", namespace="oauth2_provider")),
path("auth/", include("myapp.auth_urls")),  # 사용자 인증용
path("clients/", include("myapp.client_urls")),  # 클라이언트 등록용
기본적으로 제공되는 기능은 o/로 연결하고, 이외 필요한 기능은 기존 구성한 앱으로 넘기든가...
보통 custom_account를 구성하기에, auth 따위는 이쪽으로 넘기는 것도 좋을듯.
form 제작
from oauth2_provider.models import get_application_model
Application = get_application_model()
class ClientRegisterForm(forms.ModelForm):
    class Meta:
        model = Application
        fields = ['name', 'redirect_uris']
        widgets = {
            'redirect_uris': forms.Textarea(attrs={'rows': 3}),
        }

2 클라이언트 페이지 만들기.[편집 | 원본 편집]

과정 설명 비고
url 설정.
# OAuth2.0 관련.
path('OAuth2.0/client_list', views.OAuth_client_list, name='OAuth_client_list'),
path('OAuth2.0/detail/<int:pk>', views.OAuth_client_edit, name='OAuth_client_edit'),
path('OAuth2.0/register', views.OAuth_register_client, name='OAuth_register_client'),
path('OAuth2.0/delete/<int:pk>', views.OAuth_delete_client, name='OAuth_delete_client'),
예시. 각 사정에 맞게 설정.
view
## OAuth2.0 제공 관련.
from oauth2_provider.models import get_application_model
from .forms import ClientRegisterForm
Application = get_application_model()
@login_required
def OAuth_client_list(request):
    '''사용자가 가진 어플리케이션의 설정 보기.(어플리케이션을 여러 개 만들 수 있게 해야 할듯)'''
    apps = Application.objects.filter(user=request.user)
    return render(request, 'custom_account/OAuth2/client_list.html', {'apps': apps})
@login_required
def OAuth_client_edit(request, pk):
    '''어플리케이션 수정 페이지.'''
    app = get_object_or_404(Application, pk=pk, user=request.user)

    if request.method == 'POST':
        form = ClientRegisterForm(request.POST, instance=app)
        if form.is_valid():
            form.save()
            return redirect('custom_account:OAuth_client_list')  # 수정 후 목록 페이지로 리다이렉트
    else:
        form = ClientRegisterForm(instance=app)

    return render(request, 'custom_account/OAuth2/register.html', {'form': form, 'is_edit':True})
@login_required
def OAuth_register_client(request):
    '''어플리케이션 등록.'''
    if request.method == 'POST':
        form = ClientRegisterForm(request.POST)
        if form.is_valid():
            app = form.save(commit=False)
            app.user = request.user
            app.client_type = Application.CLIENT_CONFIDENTIAL
            app.authorization_grant_type = Application.GRANT_AUTHORIZATION_CODE
            app.save()
            return redirect('custom_account:OAuth_client_list')
    else:
        form = ClientRegisterForm()
    return render(request, 'custom_account/OAuth2/register.html', {'form': form})
@login_required
def OAuth_delete_client(request, pk):
    '''어플리케이션 등록.'''
    app = get_object_or_404(Application, pk=pk, user=request.user)
    if app.user == request.user:
        app.delete()
        return redirect('custom_account:OAuth_client_list')
    return render(request, 'custom_account/OAuth2/register.html', {'form': form})
list 탬플릿
{% extends 'custom_account/section.html' %}

{% block content %}


<div class="row row-cols-1 row-cols-md-2 g-4">
  {% for app in apps %}
    <div class="col">
      <div class="card h-100 shadow-sm">
        <div class="card-body">
          <h5 class="card-title d-flex justify-content-between align-items-center">
            {{ app.name }}
            <span>
            <a class="btn btn-outline-primary btn-sm" href="{% url 'custom_account:OAuth_client_edit' app.pk %}">정보 수정</a>
            <a class="btn btn-outline-danger btn-sm" href="{% url 'custom_account:OAuth_delete_client' app.pk %}"
            onclick="return confirm('정말로 삭제하시겠습니까? 되돌릴 수 없습니다.');">삭제</a>
            </span>
          </h5>
          <p><strong>Client ID:</strong> {{ app.client_id }}</p>
          <p><strong>Client Secret:</strong> {{ app.client_secret }}</p>
          <p><strong>Redirect URIs:</strong></p>
          <ul class="list-group list-group-flush">
            {% for uri in app.redirect_uris.splitlines %}
              <li class="list-group-item">{{ uri }}</li>
            {% empty %}
              <li class="list-group-item text-muted">(등록된 URI가 없습니다)</li>
            {% endfor %}
          </ul>
        </div>
      </div>
    </div>
  {% empty %}
    <p class="text-muted">등록된 클라이언트 애플리케이션이 없습니다.</p>
  {% endfor %}
</div>

<a href="{% url 'custom_account:OAuth_register_client' %}" class="btn btn-outline-primary">
   어플리케이션 등록.</a>



{% endblock %}
등록, 수정 탬플릿.
{% extends 'custom_account/section.html' %}

{% block content %}

<h2>{{ is_edit|yesno:"클라이언트 수정,클라이언트 등록" }}</h2>
<form method="post">
  {% csrf_token %}
  {{ form.as_p }}
  <button type="submit" class="btn btn-primary">
    {{ is_edit|yesno:"수정,등록" }}
  </button>
</form>

{% endblock %}

비밀키 갱신 기능 구현 필요.