토큰 주기 설정 

 

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

 

 

(settings.py)

    배포할 때는 access 토큰 평균 5~30분 정도

from datetime import timedelta

SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=100),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    "ROTATE_REFRESH_TOKENS": False,
    "BLACKLIST_AFTER_ROTATION": False,
    "UPDATE_LAST_LOGIN": False,

    "ALGORITHM": "HS256",
    "SIGNING_KEY": SECRET_KEY,
    "VERIFYING_KEY": "",
    "AUDIENCE": None,
    "ISSUER": None,
    "JSON_ENCODER": None,
    "JWK_URL": None,
    "LEEWAY": 0,

    "AUTH_HEADER_TYPES": ("Bearer",),
    "AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
    "USER_ID_FIELD": "id",
    "USER_ID_CLAIM": "user_id",
    "USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",

    "AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
    "TOKEN_TYPE_CLAIM": "token_type",
    "TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",

    "JTI_CLAIM": "jti",

    "SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
    "SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
    "SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),

    "TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",
    "TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",
    "TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",
    "TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",
    "SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",
    "SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}

 

 

 

 

permission

 

(app-views.py)

from rest_framework import permissions

class MockView(APIView):
    #로그인 확인
    permission_classes = [permissions.IsAuthenticated]
    def get(self, request):
        return Response('get 요청')

 

refresh 토큰으로 access 토큰 받기

    Body에 refresh 토큰을 입력하면 access 토큰을 받을 수 있다.

 

'Python > Django' 카테고리의 다른 글

[DRF] 10. 게시글 API  (0) 2023.04.26
[DRF] 09. 스태틱, 미디어 폴더 세팅  (0) 2023.04.26
[DRF] 08. Payload 커스텀  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25

Payload 커스텀

  • JWT Payload에 모델에서 작성한 필드를 추가하기

 

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/customizing_token_claims.html

 

(app-views.py)

from users.serializers import CustomTokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

class CustomTokenObtainPairView(TokenObtainPairView):
    serializer_class = CustomTokenObtainPairSerializer

 

 

(app-serializers.py)

class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        token['bio'] = user.bio
        token['name'] = user.name
        token['age'] = user.age
        token['gender'] = user.gender

        return token

 

 

(app-urls.py) 수정하기

urlpatterns = [
    path('api/token/', views.CustomTokenObtainPairView.as_view(), name='token_obtain_pair'),
]

 

'Python > Django' 카테고리의 다른 글

[DRF] 09. 스태틱, 미디어 폴더 세팅  (0) 2023.04.26
[DRF] 08.5 토큰 주기설정, permission  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25
[DRF] 06. User / UserManager  (0) 2023.04.24

회원가입

  • 시리얼라이즈 fields로 Users 모델의 필드를 전부 가져온다.
  • 시리얼라이즈 생성시 비밀번호가 노출되지 않도록 해싱한다.

 

(app-urls.py)

from users import views

urlpatterns = [
    path('signup/', views.UserView.as_view(), name='user_view'),
    ]

 

(app-views.py)

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from users.serializers import UserSerializer


class UserView(APIView):
    def post(self, request):
        serialize = UserSerializer(data=request.data)
        if serialize.is_valid():
            serialize.save()
            return Response({'message':'가입완료'}, status=status.HTTP_201_CREATED)
        else:
            return Response({'message':f'${serialize.errors}'}, status=status.HTTP_400_BAD_REQUEST)

 

(app-serializers.py)

from rest_framework import serializers
from user.models import Users


class UserSerialize (serializers.ModelSerializer):
    class Meta:
        model = Users
        fields = '__all__'

    def create(self, validated_data):
        user = super().create(validated_data)
        password = user.password
        user.set_password(password)
        user.save()
        return user

 

 

 

 

회원 수정, 삭제

  • 특정 회원 정보가 필요하므로 url을 통해 유저의 id를 전송한다.
  • 로그인한 유저와 전송된 유저의 id가 동일할 때 수정, 삭제한다.
  • 이메일 수정 요청을 해도 로그인한 유저의 이메일로 되돌려보낸다. (이메일 고정)
  • 업데이트 할 때도 비번을 해싱하여 저장한다.

(app - urls.py)

urlpatterns = [
    path('<int:user_id>/', views.UserDetailView.as_view(), name='user_detail_view'),
]

 

(app - views.py)

from user.models import Users


class UserDetailView(APIView):
    def delete(self, request, user_id):
        compare_user = get_object_or_404(Users, id=user_id)
        if request.user == compare_user:
            compare_user.delete()
            return Response('회원 탈퇴.', status=status.HTTP_204_NO_CONTENT)
        else:
            return Response('삭제 못함', status=status.HTTP_403_FORBIDDEN)
        
    def put(self, request, user_id):
        compare_user = get_object_or_404(Users, id=user_id)
        if request.user == compare_user:
            serialize = UserSerialize(compare_user, data=request.data)
            if serialize.is_valid():
                serialize.email=request.user.email,
                serialize.save()
            return Response('회원 수정', status=status.HTTP_200_OK)
        else:
            return Response('수정 못함', status=status.HTTP_403_FORBIDDEN)

 

(app - serializers.py)

# 추가하기
class UserSerialize (serializers.ModelSerializer):
    # 이메일을 아이디 값으로 취급
    # 비번은 해싱
    def update(self, instance, validated_data):
        password = validated_data.get('password', instance.password)
        instance.set_password(password)
        instance.bio = validated_data.get('bio', instance.bio)
        instance.name = validated_data.get('name', instance.name)
        instance.age = validated_data.get('age', instance.age)
        instance.gender = validated_data.get('gender', instance.gender)
        instance.save()
        return instance

 

'Python > Django' 카테고리의 다른 글

[DRF] 08.5 토큰 주기설정, permission  (0) 2023.04.26
[DRF] 08. Payload 커스텀  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25
[DRF] 06. User / UserManager  (0) 2023.04.24
[DRF] 05. 기본 JWT 토큰  (0) 2023.04.24

admin 커스텀

    사용자 추가, 변경에 사용할 폼을 별도로 만들어 설정해 줄 수도 있다.

 

 

(app-admin.py)

 

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from user.models import Users

# admin 페이지
class UserAdmin(BaseUserAdmin):
    # 아래처럼 사용자 추가, 변경에 사용할 폼을 지정 가능
    # form = UserChangeForm
    # add_form = UserCreationForm

    # admin 리스트에 표시될 필드
    list_display = ["id","email", "is_admin"]
    list_filter = ["is_admin"]
    # admin의 user수정 페이지에서 보여지는 부분
    fieldsets = [
        (None, {"fields": ["password", "gender", "age", "bio"]}),
        ("Permissions", {"fields": ["is_admin"]}),
    ]

    # admin의 user생성 페이지에서 보여지는 부분
    add_fieldsets = [
        (
            None,
            {
                "classes": ["wide"],
                "fields": ["email", "password1", "password2", "name", "gender", "age", "bio"],
            },
        ),
    ]
    # 검색 필드
    search_fields = ["email"]
    ordering = []
    filter_horizontal = []

admin.site.register(Users, UserAdmin)
# Group 모델을 등록 해제(사용x)
admin.site.unregister(Group)

 

 

 

 

JWT 커스텀 공식문서

https://docs.djangoproject.com/en/4.2/topics/auth/customizing/

'Python > Django' 카테고리의 다른 글

[DRF] 08. Payload 커스텀  (0) 2023.04.26
[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06. User / UserManager  (0) 2023.04.24
[DRF] 05. 기본 JWT 토큰  (0) 2023.04.24
[DRF] 04.5 Fetch API, CORS 에러  (0) 2023.04.24

User / UserManager

 

  • manager 클래스를 통해 DB와 데이터를 주고 받는다.
  • User와 함께 BaseUserManger를 만들어 주어야 한다.
  • 장고가 만들어준 필수사항이 존재한다.

 

(settings.py)

#users 앱의 User 모델
AUTH_USER_MODEL = "user.Users"

 

 

(app - models.py)

from django.db import models
from django.contrib.auth.models import BaseUserManager, AbstractBaseUser


# User를 생성할 때 사용하는 헬퍼 클래스
class UserManager(BaseUserManager):
    # 사용자를 생성
    def create_user(self, email, name, gender,  age, bio, password=None):
        if not email:
            raise ValueError("이메일을 입력하세요")
        user = self.model(
            email=self.normalize_email(email),
            name=name,
            gender=gender,
            age=age,
            bio=bio,
        )
        # 장고에서 제공하는 password 설정 함수
        user.set_password(password)
        user.save(using=self._db)
        return user

    # 관리자 생성
    def create_superuser(self, email, name, gender, age, bio, password=None):
        user = self.create_user(
            email,
            name=name,
            gender=gender,
            age=age,
            bio=bio,
            password=password,
        )
        user.is_admin = True
        user.save(using=self._db)
        return user


class Users(AbstractBaseUser):
    GENDER_CHOICE = {
        ('male', 'Male'),
        ('female', 'Female'),
    }

    email = models.EmailField(max_length=255, unique=True)
    name = models.CharField(max_length=30)
    gender = models.CharField(max_length=10, choices=GENDER_CHOICE, blank=True)
    age = models.PositiveIntegerField(default=0, blank=True)
    bio = models.TextField(blank=True)

    # User 모델의 필수 field
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    # 헬퍼 클래스 사용
    objects = UserManager()

    # 쉽게 말해 login ID
    USERNAME_FIELD = "email"

    # 이거 없으면 cratesuperuser 만들때 에러남
    REQUIRED_FIELDS = ["name", "gender", "age", "bio"]

    def __str__(self):
        return self.email
    
    def has_perm(self, perm, obj=None):
        "Does the user have a specific permission?"
        return True

    def has_module_perms(self, app_label):
        "Does the user have permissions to view the app `app_label`?"
        return True

    @property
    def is_staff(self):
        "Is the user a member of staff?"
        return self.is_admin

 

 

'Python > Django' 카테고리의 다른 글

[DRF] 07. 유저 API  (0) 2023.04.26
[DRF] 06.5 admin 커스텀  (0) 2023.04.25
[DRF] 05. 기본 JWT 토큰  (0) 2023.04.24
[DRF] 04.5 Fetch API, CORS 에러  (0) 2023.04.24
[DRF] 04. 클래스 뷰(CBV)  (0) 2023.04.24

JWT 토큰 기본 설정

JWT 공식문서

https://django-rest-framework-simplejwt.readthedocs.io/en/latest/

 

 

+) 토큰 정리

https://winterakoon.tistory.com/145

 

pip install djangorestframework-simplejwt

#users 앱 만들고 settings, urls 세팅
python manage.py startapp users

 

(settings.py)

#추가하기
INSTALLED_APPS = [
    'rest_framework_simplejwt',
]


REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

 

 

(app - urls.py)

from rest_framework_simplejwt.views import (
    TokenObtainPairView,
    TokenRefreshView,
)


#추가하기
urlpatterns = [
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

 

 

 

 

 

 

 

 

 

 

Token으로 로그인

python manage.py createsuperuser

 

 

 

 

 

 

 

토큰 만료 기간 설정

  • access 토큰은 사용하면 만료됨
  • JWT의 경우 보안상의 이유로 refresh 토큰을 이용
  • 만료 기간을 조정할 수 있다.
SIMPLE_JWT = {
    "ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
    "REFRESH_TOKEN_LIFETIME": timedelta(days=1),
    }

 

'Python > Django' 카테고리의 다른 글

[DRF] 06.5 admin 커스텀  (0) 2023.04.25
[DRF] 06. User / UserManager  (0) 2023.04.24
[DRF] 04.5 Fetch API, CORS 에러  (0) 2023.04.24
[DRF] 04. 클래스 뷰(CBV)  (0) 2023.04.24
[DRF] 03. postman-1, swagger  (0) 2023.04.24

Fetch API 사용

  • javascript에서 접근하고 조작할 수 있는 인터페이스를 제공
  • 네트워크의 리소스를 쉽게 비동기적으로 가져올 수도 있다.

 

(index.html)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>프론트엔드</title>
</head>
<script src="index..js">
</script>

<body>
    <h1>프론트엔드인가</h1>
    이렇게 제출하면 욕먹지 않나? 아니면 말고
    <div id="articles"></div>
</body>

</html>

 

 

 

동기 / 비동기 처리

    동기

        순차적으로 처리. 요청과 응답의 순서를 보장받음

    비동기

        병렬적으로 처리. 자원을 효율적으로 사용(처리 시간이 빠름)

 

 

async / await

  • 내부적으로 promise 방식으로 비동기 처리
  • 함수 앞에 async 를 붙이고 비동기로 처리할 부분 앞에 await를 붙임
  • 문법 형태만 간결해짐

 

(index.js)

//로딩이 될 때
window.onload = async function loadArticles() {
    //fetch안의 주소를 get방식으로 보냄
    //fetch 함수는 promise 객체를 반환
    //await를 사용하여 Promise 객체가 반환 될 때까지 기다림
    const response = await fetch('http://127.0.0.1:8000/articles/', { method: 'GET' })
	//response.json()을 호출하여 JSON 형태의 데이터를 파싱하여 반환
    response_json = await response.json()

    console.log(response_json)

    const articles = document.getElementById('articles')

    response_json.forEach(element => {
        console.log(element.title)
        const newArticle = document.createElement('div')
        newArticle.innerText = element.title
        articles.appendChild(newArticle)
    })
}

 

 

 

 

 

CORS 에러 

    (보안) 주소와 포트가 다를 때 발생, 별도의 허용이 필요함

 

pip install django-cors-headers

 

(settings.py)

INSTALLED_APPS =[
'corsheaders', 
]


MIDDLEWARE = [
	'corsheaders.middleware.CorsMiddleware',
    #'django.middleware.common.CommonMiddleware', # 얘 위에 추가
]


#보안에 안 좋음
CORS_ALLOW_ALL_ORIGINS = True

 

'Python > Django' 카테고리의 다른 글

[DRF] 06. User / UserManager  (0) 2023.04.24
[DRF] 05. 기본 JWT 토큰  (0) 2023.04.24
[DRF] 04. 클래스 뷰(CBV)  (0) 2023.04.24
[DRF] 03. postman-1, swagger  (0) 2023.04.24
[DRF] 02. @api_view  (0) 2023.04.24

클래스 뷰 

  • 코드를 재사용하고 뷰를 체계적으로 구성할 수 있다.
  • def 메소드( ) : 형태를 가진다.
  • url 설정시 함수명 뒤에 as_view()를 사용한다.

 

https://www.django-rest-framework.org/tutorial/3-class-based-views/

from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema

# 함수 articleAPI 변형
class ArticleList(APIView):
    def get(self, request, format=None):
        articles = Articles.objects.all()
        serialize = ArticleSerialize(articles, many=True)
        return Response(serialize.data)

    # 스웨거에서도 편집이 가능
    @swagger_auto_schema(request_body=ArticleSerialize)
    def post(self, request, format=None):
        serialize = ArticleSerialize(data = request.data)
        if serialize.is_valid():
            serialize.save()
            return Response(serialize.data, status=status.HTTP_201_CREATED)
        else:
            print(serialize.errors)
            return Response(serialize.errors, status=status.HTTP_400_BAD_REQUEST)
        

class ArticleDetail(APIView):
    def get(self, request, article_id, format=None):
        article = get_object_or_404(Articles, id=article_id)
        serialize = ArticleSerialize(article)
        return Response(serialize.data)

    def put(self, request, article_id, format=None):
        article = get_object_or_404(Articles, id=article_id)
        serialize = ArticleSerialize(article, data = request.data)
        if serialize.is_valid():
            serialize.save()
            return Response(serialize.data)
        return Response(serialize.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, article_id, format=None):
        article = get_object_or_404(Articles, id=article_id)
        article.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 

 

app - urls.py

# 수정
urlpatterns = [
	# 클래스형을 사용할 때 as_view()를 사용
	path('', views.ArticleList.as_view(), name='index'),
	path('<int:article_id>/', views.ArticleDetail.as_view(), name='article_view'),
]

'Python > Django' 카테고리의 다른 글

[DRF] 05. 기본 JWT 토큰  (0) 2023.04.24
[DRF] 04.5 Fetch API, CORS 에러  (0) 2023.04.24
[DRF] 03. postman-1, swagger  (0) 2023.04.24
[DRF] 02. @api_view  (0) 2023.04.24
[DRF] 01. 시리얼라이즈  (0) 2023.04.24

postman 활용하기

  • postman 사용시 500번 에러가 발생할 때 슬래시 ( / ) 가 빠지지 않았는지 확인하자.

 

새로고침 : send 클릭

 

 

 

 

 

 

 

 

 

Environments 등록하기

나중에 도메인으로 변경할 때 편리하다.

 

 

 

 

 

 

swagger

api를 알아서 만들어 줌

 

drf-yasg

https://drf-yasg.readthedocs.io/en/latest/readme.html#usage

 

drf-yasg - Yet another Swagger generator — drf-yasg 1.20.1.dev31+gd9700db documentation

Since the schema does not usually change during the lifetime of the django process, there is out of the box support for caching the schema view in-memory, with some sane defaults: caching is enabled by the cache_page decorator, using the default Django cac

drf-yasg.readthedocs.io

pip install drf-yasg
pip freeze > requirements.txt

 

settings.py

# 추가하기

INSTALLED_APPS = [
   'drf_yasg',
]

 

urls.py

from django.urls import re_path
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi


schema_view = get_schema_view(
   openapi.Info(
      title="Snippets API",
      default_version='v1',
      description="Test description",
      terms_of_service="https://www.google.com/policies/terms/",
      contact=openapi.Contact(email="contact@snippets.local"),
      license=openapi.License(name="BSD License"),
   ),
   public=True,
   permission_classes=[permissions.AllowAny],
)


urlpatterns = [
   re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
   re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
   re_path(r'^redoc/$', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
]

http://127.0.0.1:8000/swagger/ 로 접속하기

'Python > Django' 카테고리의 다른 글

[DRF] 04.5 Fetch API, CORS 에러  (0) 2023.04.24
[DRF] 04. 클래스 뷰(CBV)  (0) 2023.04.24
[DRF] 02. @api_view  (0) 2023.04.24
[DRF] 01. 시리얼라이즈  (0) 2023.04.24
11. Django gitignore, 시크릿 키  (0) 2023.04.24

새로운 데이터 만들기

※반드시 문자열을 큰따옴표( " )로 감쌀것

 

 

게시글 보기, 생성

from rest_framework.response import Response
from rest_framework import status
from rest_framework.decorators import api_view
from articles.models import Articles
from articles.serializers import ArticleSerialize

@api_view(['GET', 'POST'])
def articleAPI(request):
    if request.method =='GET':
        articles = Articles.objects.all()
        serialize = ArticleSerialize(articles, many=True)
        return Response(serialize.data)
    elif request.method =='POST':
        print(request.data['title'])
        serialize = ArticleSerialize(data = request.data)
        if serialize.is_valid():
            serialize.save()
            return Response(serialize.data, status=status.HTTP_201_CREATED)
        else:
            print(serialize.errors)
            return Response(serialize.errors, status=status.HTTP_400_BAD_REQUEST)

 

 

 

게시글 상세보기, 수정, 삭제

 

app - urls.py 

# 추가
urlpatterns = [
    path('<int:article_id>', views.articleDetailAPI, name='article_view'),
]

 

app - views.py

@api_view(['GET', 'PUT', 'DELETE'])
def articleDetailAPI(request, article_id):
    if request.method == 'GET':
        article = get_object_or_404(Articles, id=article_id)
        serialize = ArticleSerialize(article)
        return Response(serialize.data)
    elif request.method == 'PUT':
        article = get_object_or_404(Articles, id=article_id)
        serialize = ArticleSerialize(article, data = request.data)
        if serialize.is_valid():
            serialize.save()
            return Response(serialize.data)
    elif request.method == 'DELETE':
        article = get_object_or_404(Articles, id=article_id)
        article.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

 

 

 

 

+) origin main으로 push 할 때

에러 :  error: src refspec main does not match any

해결 : git push origin master 

'Python > Django' 카테고리의 다른 글

[DRF] 04. 클래스 뷰(CBV)  (0) 2023.04.24
[DRF] 03. postman-1, swagger  (0) 2023.04.24
[DRF] 01. 시리얼라이즈  (0) 2023.04.24
11. Django gitignore, 시크릿 키  (0) 2023.04.24
10. Django 폼  (0) 2023.04.24

+ Recent posts