Skip to content

Latest commit

ย 

History

History
246 lines (171 loc) ยท 7.3 KB

File metadata and controls

246 lines (171 loc) ยท 7.3 KB

4์ฃผ์ฐจ - 3. Authentication

Authentication & Permission

API ์„œ๋ฒ„์˜ ๋™์ž‘ ์›๋ฆฌ

  • Create
  • Read
  • Update
  • Delete

API ์„œ๋ฒ„์˜ ์šด์˜ ์›๋ฆฌ

  • Authentication
    • ์„œ๋น„์Šค๋ฅผ ์ด์šฉํ•  ๋•Œ ์‚ฌ์šฉ์ž๊ฐ€ ์–ด๋Š ์ •๋„์˜ ๊ถŒํ•œ์ด ์žˆ์Œ์„ ์š”์ฒญํ•˜๋Š” ๊ณผ์ •
  • Permission
    • ์„œ๋น„์Šค๋ฅผ ์–ด๋Š ์ •๋„๋กœ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ๊ถŒํ•œ

๋Œ€๋ถ€๋ถ„์˜ ์›น ์„œ๋น„์Šค์—์„œ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ๋™์ผํ•œ ๊ถŒํ•œ์„ ์ฃผ์ง€ ์•Š๋Š”๋‹ค.

Authentication

์ธ์ฆ ์š”์ฒญ์ด ์™”์„ ๋•Œ ์ธ์ฆ์ด ์„ฑ๊ณต์„ ํ•  ๊ฒฝ์šฐ์™€ ์‹คํŒจํ•  ๊ฒฝ์šฐ ๋ชจ๋‘
request.user์™€ request.auth ๋‘ ๊ฐœ์˜ ๋ณ€์ˆ˜๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.

์ธ์ฆ์— ์„ฑ๊ณตํ–ˆ์„ ๋•Œ

์ธ์ฆ์ด ์„ฑ๊ณตํ•  ๊ฒฝ์šฐ ์œ ์ €์˜ ๋Œ€ํ‘œ๊ฐ’์ธ ์•„์ด๋””๊ฐ€ request.user์— ์ €์žฅ๋˜๊ณ 
์ธ์ฆ์„ ์„ฑ๊ณตํ•œ ์œ ์ €์˜ ๊ถŒํ•œ์ด request.auth์— ์ €์žฅ๋œ๋‹ค.

์ธ์ฆ์— ์‹คํŒจํ–ˆ์„ ๋•Œ

์ธ์ฆ์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ AnonymousUser๊ฐ€ request.user์— ์ €์žฅ๋˜๊ณ 
request.auth๋Š” None๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ฒŒ ๋œ๋‹ค.
์ธ์ฆ์— ์‹คํŒจํ–ˆ์„ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ์„ค์ •๊ณผ ๋‹ค๋ฅด๊ฒŒ ๋‹ค๋ฅธ ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด
settings.py์—์„œ UNAUTHENTICATED_USER์™€ UNAUTHENTICATED_TOKEN๊ฐ’์„ ์ˆ˜์ •ํ•˜๋ฉด ๋œ๋‹ค.

์ „์—ญ์œผ๋กœ ์ธ์ฆ ์„ค์ •ํ•˜๊ธฐ

settings.py์— REST_FRAMEWORK ๋”•์…”๋„ˆ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ์•„๋ž˜์™€ ๊ฐ™์ด
๊ธฐ๋ณธ ๊ฐ’์œผ๋กœ ์‚ฌ์šฉํ•˜๊ธธ ์›ํ•˜๋Š” ์ธ์ฆ ๋ฐฉ์‹์„ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ]
}

View๋ณ„๋กœ ์ธ์ฆ ์„ค์ •ํ•˜๊ธฐ

rest_framework์˜ authentication์—์„œ ์‚ฌ์šฉํ•  ์ธ์ฆ ๋ฐฉ์‹์„ importํ•ด์ฃผ๊ณ 
authentication_classes๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•œ ์ธ์ฆ ๋ฐฉ์‹์„ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

class ExampleView(APIView):
    authentication_classes = [SessionAuthentication, BasicAuthentication]
    permission_classes = [IsAuthenticated]

    def get(self, request, format=None):
        content = {
            'user': unicode(request.user),
            'auth': unicode(request.auth),
        }
        return Response(content)

Function Based View์—์„œ ์ธ์ฆ ์„ค์ •ํ•˜๊ธฐ

๋ฐ์ฝ”๋ ˆ์ดํ„ฐ(@)๋ฅผ ์‚ฌ์šฉํ•ด ๊ตฌํ˜„ํ•˜๋ฉฐ ์•„๋ž˜์™€ ๊ฐ™์ด @authentication_classes์— ์œ„์˜ CBV์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ ๊ฒƒ๊ณผ ๋งˆ์ฐฌ ๊ฐ€์ง€๋กœ ์‚ฌ์šฉํ•  ์ธ์ฆ ๋ฐฉ์‹์„ ์ž‘์„ฑํ•˜๋ฉด ๋œ๋‹ค.

@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
    content = {
        'user': unicode(request.user),
        'auth': unicode(request.auth),
    }
    return Response(content)

Django rest framework์—์„œ์˜ ์ธ์ฆ

์ธ์ฆ๋˜์ง€ ์•Š์€ ์š”์ฒญ์ด๋‚˜ ํ—ˆ๊ฐ€๋˜์ง€ ์•Š์€ ์š”์ฒญ

  • HTTP 401 Unauthorized
  • HTTP 403 Permission Denied

Authentication ์ข…๋ฅ˜

  • BasicAuthentication
  • TokenAuthentication
  • SessionAuthentication
  • RemoteUserAuthentication
  • Custom authentication

BasicAuthentication

HTTP Protocol์ž์ฒด ๊ธฐ๋ณธ ์ธ์ฆ์— ๊ธฐ๋ฐ˜ํ•œ ์ธ์ฆ ๋ฐฉ์‹
HTTP ์ œ์–ด ํ—ค๋”๋กœ ๋„˜๊ธด ID, PW๋ฅผ base64๋กœ ์ธ์ฝ”๋”ฉํ•œ๋‹ค.

TokenAuthentication

BasicAuthentication์„ ๋ณด์™„ํ•œ ๋ฐฉ์‹
์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์„ ์š”์ฒญํ•˜๋ฉด ํ•ด๋‹น ์‚ฌ์šฉ์ž์—๊ฒŒ ์œ ์ผํ•œ Key ๊ฐ’์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.
Token ํ—ค๋”์—์„œ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

SessionAuthentication

๋กœ๊ทธ์ธ์ด ๋  ๋•Œ๋งˆ๋‹ค ์ €์žฅ๋˜๋Š” Session์ •๋ณด๋ฅผ ์ฐธ์กฐํ•˜์—ฌ ์ธ์ฆํ•œ๋‹ค.

RemoteUserAuthentication

์‚ฌ์šฉ์ž ์ •๋ณด๊ฐ€ ๋‹ค๋ฅธ ์„œ๋น„์Šค์—์„œ ๊ด€๋ฆฌ๋  ๋•Œ ์“ฐ์ด๋Š” ์ธ์ฆ ๋ฐฉ์‹์ด๋‹ค.
REMOTE_USER ํ—ค๋”์—์„œ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

Authentication ๊ตฌํ˜„ํ•˜๊ธฐ

1. ๊ธฐ๋ณธ ์•ฑ ๊ตฌ์„ฑํ•˜๊ธฐ

์ด์ „ ๊ฐ•์˜์—์„œ ์ง„ํ–‰ํ–ˆ๋˜ UserPost๋ชจ๋ธ์„ ์‚ฌ์šฉํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  1. ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ๋ฐ ์•ฑ ์ƒ์„ฑ
  2. settings.py ์ž‘์„ฑ
  3. models.py ์ž‘์„ฑ ๋ฐ admin.py ์—ฐ๊ฒฐ
  4. migrate ๋ช…๋ น์–ด ์‹คํ–‰
  5. serializer.py ์ž‘์„ฑ
  6. views.py ์ž‘์„ฑ
  7. ์•ฑ์˜ urls.py์ž‘์„ฑ ๋ฐ ํ”„๋กœ์ ํŠธ์˜ urls.py์™€ ์—ฐ๊ฒฐ

2. author ํ•„๋“œ ReadOnly๋กœ ๋ฐ”๊พธ๊ธฐ

serializer.py๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค.

class UserPostSerializer(serializers.ModelSerializer):

    author_name = serializers.ReadOnlyField(
        source='author.username'
    )

    class Meta:
        model = UserPost
        fields = ['pk','author_name', 'title', 'body']

์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•œ ํ•„๋“œ๊ฐ€ ์ž˜ ๋ณด์ด๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
๋˜ํ•œ author๋ฅผ ReadOnly๋กœ ๋ณ€๊ฒฝํ•ด ์„ ํƒํ•˜๋Š” Form์ด ์‚ฌ๋ผ์กŒ๋‹ค.


3. ์ธ์ฆ ๊ณผ์ • ๊ตฌํ˜„ํ•˜๊ธฐ

views.py์—์„œ perform_create๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด ๊ตฌํ˜„ํ•œ๋‹ค.
serializer์˜ saveํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•ด authorํ•„๋“œ๋ฅผ self.request.user๋กœ ์ €์žฅํ•œ๋‹ค.

class UserPostViewSet(viewsets.ModelViewSet):
    queryset = UserPost.objects.all()
    serializer_class = UserPostSerializer

    filter_backends = [SearchFilter]
    search_fields = ('title', 'body')

    def get_queryset(self):
        qs = super().get_queryset()

        if self.request.user.is_authenticated:
            qs = qs.filter(author=self.request.user)

        else:
            qs = qs.none()

        return qs

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)

4. settings.py ์ˆ˜์ •ํ•˜๊ธฐ

์•„๋ž˜์™€ ๊ฐ™์ด settings.py๋ฅผ ์ˆ˜์ •ํ•ด์ค€๋‹ค.

DEBUG = False
ALLOWED_HOSTS = ['*']

5. ์ธ์ฆ ๋ฐฉ์‹ ๋“ฑ๋กํ•˜๊ธฐ

์œ„์—์„œ ์„ค๋ช…ํ•œ ๊ฒƒ๊ณผ ๊ฐ™์ด ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์œผ๋กœ ๋“ฑ๋ก์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

  • ์ „์—ญ์œผ๋กœ ์ธ์ฆ ๋ฐฉ์‹ ๋“ฑ๋กํ•˜๊ธฐ
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ]
}
  • views.py์—์„œ ์ธ์ฆ ๋ฐฉ์‹ ๋“ฑ๋กํ•˜๊ธฐ
...
from rest_framework.authentication \
    import BasicAuthentication, SessionAuthentication


class UserPostViewSet(viewsets.ModelViewSet):
    authentication_classes = [BasicAuthentication, SessionAuthentication]
    queryset = UserPost.objects.all()
    serializer_class = UserPostSerializer
    ...

httpie๋กœ ํ…Œ์ŠคํŠธํ•˜๊ธฐ

  • ์ด์ „๊ณผ ๊ฐ™์ด POST์š”์ฒญ ๋ณด๋‚ด๊ธฐ


์ด์ „๊ณผ ๊ฐ™์ด POST์š”์ฒญ์„ ๋ณด๋‚ผ๊ฒฝ์šฐ HTTP 500 Server Error๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.
์™œ๋ƒํ•˜๋ฉด ์š”์ฒญ์„ ๋ณด๋‚ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ๋ชจ๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  • ์ธ์ฆ ์ •๋ณด์™€ ํ•จ๊ป˜ POST์š”์ฒญ ๋ณด๋‚ด๊ธฐ
http --auth <username>:<password> --form POST http://127.0.0.1:8000/userpost/ title="" body=""


์œ„์™€ ๊ฐ™์ด POST์š”์ฒญ์ด ์ž˜ ์ฒ˜๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.