Django-rest-framework: DRF๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  OPTIONS ์š”์ฒญ์„ ์Šน์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์— ๋งŒ๋“  2017๋…„ 11์›” 21์ผ  ยท  22์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: encode/django-rest-framework

#908์— ๋Œ€ํ•œ ํ† ๋ก ์— ์ด์–ด

OPTIONS (๋ฉ”ํƒ€๋ฐ์ดํ„ฐ) ์š”์ฒญ์— ๋Œ€ํ•œ ๊ถŒํ•œ์ด DRF์—์„œ ์ž˜๋ชป ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค.

W3C ์‚ฌ์–‘์— ๋”ฐ๋ผ ๋ชจ๋“  preflight OPTIONS ์š”์ฒญ์€ ์ธ์ฆ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ฆ‰, ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋Š” ์‚ฌ์–‘์— ๋”ฐ๋ผ ์ด๊ฒƒ์„ ๋ณด๋‚ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ธ์ฆ๋œ ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•œ ์š”์ฒญ์„ preflightingํ•  ๋•Œ ์‚ฌ์šฉ์ž๋Š” ํ•ญ์ƒ 401 ์˜ค๋ฅ˜๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค.

๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ๋น„ํ–‰ ์ „ ์š”์ฒญ์„ ํ•˜์‹ญ์‹œ์˜ค. OPTIONS ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ์ œ์•ฝ ์กฐ๊ฑด์„ ์‚ฌ์šฉํ•˜์—ฌ ์ˆ˜๋™ ๋ฆฌ๋””๋ ‰์…˜ ํ”Œ๋ž˜๊ทธ ๋ฐ ์ฐจ๋‹จ ์ฟ ํ‚ค ํ”Œ๋ž˜๊ทธ๊ฐ€ ์„ค์ •๋œ ์žฌ์ •์˜ ๋ฆฌํผ๋Ÿฌ ์†Œ์Šค๋กœ ๋ฆฌํผ๋Ÿฌ ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์›๋ณธ ์†Œ์Šค ์›๋ณธ์—์„œ ์š”์ฒญ URL์„ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

  • ํ—ค๋” ํ•„๋“œ ๊ฐ’์œผ๋กœ ์š”์ฒญ ๋ฐฉ๋ฒ•(๋‹จ์ˆœํ•œ ๋ฐฉ๋ฒ•์ธ ๊ฒฝ์šฐ์—๋„)๊ณผ ํ•จ๊ป˜ Access-Control-Request-Method ํ—ค๋”๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • ์ž‘์„ฑ์ž ์š”์ฒญ ํ—ค๋”๊ฐ€ ๋น„์–ด ์žˆ์ง€ ์•Š์€ ๊ฒฝ์šฐ ํ—ค๋” ํ•„๋“œ ๊ฐ’์œผ๋กœ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ์ž‘์„ฑ์ž ์š”์ฒญ ํ—ค๋”์˜ ํ—ค๋” ํ•„๋“œ ์ด๋ฆ„ ๋ชฉ๋ก์„ ์‚ฌ์ „์ˆœ์œผ๋กœ ํฌํ•จํ•˜๋Š” Access-Control-Request-Headers ํ—ค๋”๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ๊ฐ๊ฐ์€ ASCII ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜๋ฉ๋‹ˆ๋‹ค(ํ•˜๋‚˜ ๋˜๋Š” more๋Š” ๋‹จ์ˆœํ•œ ํ—ค๋”์ž„).
  • ์ž‘์„ฑ์ž ์š”์ฒญ ํ—ค๋”๋ฅผ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.
  • โžก๏ธ ์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช… ์ œ์™ธ .
  • ์š”์ฒญ ์—”ํ„ฐํ‹ฐ ๋ณธ๋ฌธ์„ ์ œ์™ธํ•ฉ๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์—์„œ ์ด๊ฒƒ์ด ๊ธฐ๋ณธ ๋™์ž‘์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.
DRF๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ‘œ์ค€ ๊ถŒํ•œ ํด๋ž˜์Šค(IsAuthenticated, IsAdminUser ๋“ฑ)์— ๋Œ€ํ•œ ๋ชจ๋“  OPTIONS ์š”์ฒญ์„ ์Šน์ธํ•ด์•ผ ํ•˜๋ฉฐ ์‚ฌ์šฉ์ž๋Š” ๋ช…์‹œ์ ์œผ๋กœ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ ์ •๋ณด๋ฅผ ๋ณดํ˜ธํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ(ํ‘œ์ค€ CORS ํ˜ธํ™˜์„ฑ ์นจํ•ด) ์ด๋ฅผ ์žฌ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์žฌํ˜„ ๋‹จ๊ณ„:

๋ณด๊ธฐ.py

class MyView(APIView):

    permission_classes = (IsAuthenticated,)

urls.py

urlpatterns = [
    url(r'^myview/', MyView.as_view()),
]

์ฝ˜์†”

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

์˜ˆ์ƒ๋˜๋Š” ํ–‰๋™

http GET http://127.0.0.1:8000/myview/
HTTP/1.0 401 Unauthorized

http OPTIONS http://127.0.0.1:8000/myview/
HTTP/1.0 200 OK

์ž„์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

class IsAuthenticated(permissions.IsAuthenticated):

    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return super(IsAuthenticated, self).has_permission(request, view)

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

DRF ๋ฒ„์ „: 3.7.3
ํŒŒ์ด์ฌ 3.6.3

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ์ž„์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํšจ๊ณผ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. PUT, POST, GET, OPTIONS ๋“ฑ์ธ์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๋ชจ๋“  ์š”์ฒญ์ด ์ธ์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

๊ทธ๋ฆฌ๊ณ  settings.py์—์„œ:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

๋ชจ๋“  22 ๋Œ“๊ธ€

DRF ๋ฒ„์ „: 3.7.3
ํŒŒ์ด์ฌ 3.6.3

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ์ž„์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํšจ๊ณผ๊ฐ€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค. PUT, POST, GET, OPTIONS ๋“ฑ์ธ์ง€ ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด ๋ชจ๋“  ์š”์ฒญ์ด ์ธ์ฆ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

# myapp/permissions.py
from rest_framework.permissions import IsAuthenticated

class AllowOptionsAuthentication(IsAuthenticated):
    def has_permission(self, request, view):
        if request.method == 'OPTIONS':
            return True
        return request.user and request.user.is_authenticated

๊ทธ๋ฆฌ๊ณ  settings.py์—์„œ:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication',),
    'DEFAULT_PERMISSION_CLASSES': (
        'myapp.permissions.AllowOptionsAuthentication',
    )
}

๋‚˜๋„ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. ์ œ์•ˆ๋œ ์†”๋ฃจ์…˜์— ๋™์˜ํ•˜๋ฉฐ ์ž„์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์— ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!

CORS ์‹คํ–‰ ์ „ ์š”์ฒญ ์ด์™ธ์˜ ๊ฒฝ์šฐ์— OPTIONS ์š”์ฒญ์„ ์‚ฌ์šฉํ•˜๋Š” REST ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋งŽ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— "๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  OPTIONS ์š”์ฒญ์„ ์Šน์ธํ•ด์•ผ ํ•จ"์ด ์ •ํ™•ํžˆ ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋™์ž‘์ด๋ผ๊ณ  100% ํ™•์‹ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹™๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์•„๋งˆ๋„ ์ถ•๋ณต๋ฐ›์€ CORS ์˜ต์…˜์„ ์›ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://github.com/ottoyiu/django-cors-headers/๋ฅผ ์ง์ ‘ ํฌํ•จํ•ด์•ผ ํ•˜๋Š”์ง€ ์•„๋‹ˆ๋ฉด ๋” ๋งŽ์ด ์ฐธ์กฐํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ•ด๋‹น ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๊นŒ?

์ด ํŒจํ‚ค์ง€๋Š” ์‹ค์ œ๋กœ ์†”๋ฃจ์…˜์ด ์•„๋‹ˆ๋ฉฐ CORS ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•  ๋ฟ ์ธ์ฆ๋˜์ง€ ์•Š์€ ๋ชจ๋“  ์š”์ฒญ์— โ€‹โ€‹๋Œ€ํ•ด DRF ๊ถŒํ•œ์ด ํŠน๋ณ„ํžˆ ๋ถ€์—ฌ๋˜์ง€ ์•Š์€ ๊ฒฝ์šฐ OPTIONS๊ฐ€ HTTP401์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค๋Š” ์‚ฌ์‹ค์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

IMO๋Š” ๋‹ค๋ฅธ ๋ฐฉ์‹์œผ๋กœ ๋„์ž…๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฃผ์š” ๋ณ€๊ฒฝ ๊ณต์ง€์™€ ํ•จ๊ป˜ ํ—ˆ์šฉ๋ฉ๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ W3C ์‚ฌ์–‘์— ๋”ฐ๋ผ ์˜ˆ์ƒ๋˜๋Š” ๋™์ž‘์ด๋ฉฐ ์ž˜๋ชป๋œ ๊ตฌํ˜„์„ ํŒจ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ๋ฌธ์„œ์—์„œ ํƒ€์‚ฌ๋ฅผ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์€ ์‹ค์ œ๋กœ ๊นจ๋—ํ•œ ์†”๋ฃจ์…˜์ด ์•„๋‹™๋‹ˆ๋‹ค...

๋”ฐ๋ผ์„œ CORS๊ฐ€ ์•„๋‹Œ ๊ด€๋ จ ํ•ญ๋ชฉ์— OPTIONS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์ด ์žˆ์ง€๋งŒ(์ €๋„ ๊ทธ ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค), CORS ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ์ ์  ๋” ๋งŽ์€ ๋ธŒ๋ผ์šฐ์ €์— ์˜ํ•ด ์‹œํ–‰๋˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž ์žฌ์ ์œผ๋กœ ํ›จ์”ฌ ๋” ๋งŽ์€ ๊ฒƒ์„ ์•”์‹œ์ ์œผ๋กœ ์˜ˆ์ƒํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ด๋Ÿฌํ•œ ๋ฉ”์ปค๋‹ˆ์ฆ˜์€ ์›น์„ ํ†ตํ•ด OPTIONS ์š”์ฒญ์˜ 99% ์ด์ƒ์„ ์ž ์žฌ์ ์œผ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํฅ๋ฏธ๋กœ์šด ๊ฐˆ๋“ฑ. OPTIONS ๋ฉ”์„œ๋“œ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์•”์‹œ์  ํ—ˆ์šฉ์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฌธ์ œ๋ฅผ ์™„์ „ํžˆ ์ดํ•ดํ•ฉ๋‹ˆ๋‹ค. ๋‚˜๋Š” ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋” ์•ˆ์ „ํ•œ ์†”๋ฃจ์…˜์— ๋” ํŽธํ–ฅ๋˜์–ด ์žˆ์œผ๋ฉฐ DRF์— ๋Œ€ํ•œ ๊ฐœ๋ฐœ์ž์˜ ๋ชฉ์ ์— ๋‹ฌ๋ ค ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ธฐ๋ณธ ๊ฑฐ๋ถ€๊ฐ€ ๋‚˜์—๊ฒŒ ๋” ์ ์ ˆํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

OPTIONS๋ฅผ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•œ W3C ์‚ฌ์–‘์ด CORS์˜ ์ปจํ…์ŠคํŠธ์—์„œ๋งŒ ์ ์šฉ๋˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋ถ„๋ช…ํžˆ DRF๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์—†์œผ๋ฉฐ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ œ๊ณต๋˜๋Š” ์„ค์ •์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

CORS๊ฐ€ ์˜๋„๋œ ๊ฒฝ์šฐ ๋ชจ๋“  OPTIONS ์š”์ฒญ์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. CORS๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜๋„ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹ค์ œ๋กœ ํ˜„์žฌ ๋™์ž‘์„ ๊ณ„์† ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ์—์„œ ์ฃผ์š” ๋ฒ„์ „์— ๋Œ€ํ•œ ์ฃผ์š” ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์šฐ๋ฆฌ์˜ ๊ธฐ์กด OPTIONS ๋™์ž‘์€ ์‚ฌ๋žŒ๋“ค์ด CORS๊ฐ€ ์•„๋‹Œ JSONP๋ฅผ ์‚ฌ์šฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ ์šฉ๋˜์—ˆ์œผ๋ฏ€๋กœ ์•„๋งˆ๋„ ์šฐ๋ฆฌ๊ฐ€ ๋…ธ์ถœํ•˜๋Š” ์ƒ๋‹นํžˆ ์ž„์‹œ์ ์ธ ๊ธฐ๋ณธ ์ •๋ณด ์„ธํŠธ๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ๊ธฐ๋ณธ์ ์œผ๋กœ CORS์šฉ OPTIONS์—๋งŒ ์ง‘์ค‘ํ•˜๋Š” ์ƒˆ๋กœ ๊ณ ์นจ ๋•Œ๋ฌธ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. .

+1

@tomchristie ๋ฉ”์ด์ € ๋ฒ„์ „ ์—…๋ฐ์ดํŠธ/์ˆ˜์ •์ด ์–ธ์ œ ์ผ์–ด๋‚ ์ง€ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ? ๋‚˜๋Š” ๋˜ํ•œ์ด ๋ฌธ์ œ๋ฅผ ์น˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•œํŽธ @medakk ์˜ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ์™„๋ฒฝํ•ฉ๋‹ˆ๋‹ค!

3.9์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ๊ณ ๋ ค๋ฅผ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์ด์ •ํ‘œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ ๋ทฐ์—์„œ ์ด๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ permission_classes๊ฐ€ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ฐ๊ฐ์ด ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” DRY์ž…๋‹ˆ๋‹ค.

def check_permissions(self, request):
        if request.method == 'OPTIONS':
            return
        super(MyApiView, self).check_permissions(request)

https://github.com/OttoYiu/django-cors-headers ํŒจํ‚ค์ง€๋Š” ๋ฏธ๋“ค์›จ์–ด์—์„œ preflighted OPTIONS ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‘๋‹ต์„ ์ง์ ‘ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. REST ํ”„๋ ˆ์ž„์›Œํฌ์— ๋„๋‹ฌํ•˜๊ธฐ ์ „์— ์š”์ฒญ/์‘๋‹ต์ด ๊ฐ€๋กœ์ฑ„๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๊ธฐ์—์„œ REST ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋ฌด์—‡์„ ํ•˜๋Š”์ง€๋Š” ์ค‘์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ๋ฌธ์ œ ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด ๋ถ„๋ช…ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์‹คํ–‰ ์ „ ์‘๋‹ต์€ REST ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š์Šต๋‹ˆ๋‹ค: https://github.com/ottoyiu/django-cors-headers/blob/master/corsheaders/middleware.py#L83

๊ฐ์‚ฌ ํ•ด์š”. ์šฐ๋ฆฌ๋Š” django-cors-headers๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์ง€๋งŒ ์•„๋งˆ๋„ ๊ทธ๋ ‡๊ฒŒ ํ•ด์•ผ ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
๋‚˜๋Š” ์—ฌ์ „ํžˆ DRF๊ฐ€ W3C ํ˜ธํ™˜ CORS ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์™ธ๋ถ€ ํŒจํ‚ค์ง€๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์•„์•ผ ํ•œ๋‹ค๋Š” ์ด์ „ ์˜๊ฒฌ์— ๋™์˜ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ, ๋ฌธ์ œ๋ฅผ ์šฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•/ํƒ€์‚ฌ ํŒจํ‚ค์ง€๊ฐ€ ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์ด ํ‹ฐ์ผ“์€ DRF๊ฐ€ W3C CORS ์‚ฌ์–‘๊ณผ ํ˜ธํ™˜๋˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์ƒ์„ฑ๋˜์—ˆ์œผ๋ฉฐ ์ˆ˜์ •๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰๋˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ OPTIONS ์š”์ฒญ์€ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๋ชฉ์ ์„ ์œ„ํ•œ ๊ฒƒ์ด๋ฉฐ DRF์˜ ๋…๋‹จ์ ์ธ ์„ ํƒ์œผ๋กœ ์ธํ•ด ์ƒˆ๋กœ์šด DRF ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋งˆ๋„ ๊ธฐ๋งŒ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์˜ค๋Š˜๋‚  ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰๋˜๋Š” ๋Œ€๋ถ€๋ถ„์˜ OPTIONS ์š”์ฒญ์€ ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๋ชฉ์ ์„ ์œ„ํ•œ ๊ฒƒ์ด๋ฉฐ DRF์˜ ๋…๋‹จ์ ์ธ ์„ ํƒ์œผ๋กœ ์ธํ•ด ์ƒˆ๋กœ์šด DRF ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ์ˆ˜๋™์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋งˆ๋„ ๊ธฐ๋งŒ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

CORS๊ฐ€ OPTIONS ๋ฉ”์„œ๋“œ๋ฅผ ํ•˜์ด์žฌํ‚นํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ณด์•ˆ์„ ์ˆ˜์šฉํ•˜๋„๋ก ๋ณ€๊ฒฝ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ์˜๋ฏธ๋Š” ์•„๋‹™๋‹ˆ๋‹ค. ํŠนํžˆ CORS ์ง€์›์ด ์ œ๋Œ€๋กœ ๊ตฌํ˜„๋˜๋ฉด ํ•„์š”ํ•œ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์ฃ„์†กํ•˜์ง€๋งŒ, ์ด๊ฒƒ์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์€ ๊ฐœ๋ฐœ์ž๋Š” DRF ๊ด€๋ฆฌ์ž๊ฐ€ ์•„๋‹ˆ๋ผ ์ž์‹ ์˜ ์˜๊ฒฌ์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

CORS๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฐ”ํ€ด๋ฅผ ๋‹ค์‹œ ๋ฐœ๋ช…ํ•˜๋Š” ๋Œ€์‹  ์ ์ ˆํ•œ ๊ตฌํ˜„์„ ์ง€์›ํ•˜๋Š” ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋„๋ก ์ œ์•ˆํ•˜๋Š” ๋ฌธ์„œ ๊ฐœ์„  ์‚ฌํ•ญ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ ˆ๋ฒจ์„ ๋‚ฎ์ถ”์ž.

๋ฏธ๋“ค์›จ์–ด ๋Š” CORS ํ—ค๋”๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ํ•ฉ๋ฆฌ์ ์ธ ์žฅ์†Œ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๊ทธ๊ฒƒ์„ REST ํ”„๋ ˆ์ž„์›Œํฌ์— ๊ตฌ์ถ• ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๊ธฐ์กด ํŒจํ‚ค์ง€๋Š” ์ด๋ฏธ ๊ทธ๊ฒƒ์„ ์ •๋ง ํ›Œ๋ฅญํ•˜๊ฒŒ ๋‹ค๋ฃจ์—ˆ์Šต๋‹ˆ๋‹ค.

REST ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ OPTIONS ์š”์ฒญ์— ๋Œ€ํ•ด ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ณธ๋ฌธ์€ ์—ฌ๊ธฐ์—์„œ ๊ด€๋ จ์ด ์—†์Šต๋‹ˆ๋‹ค. preflighted CORS ์š”์ฒญ์€ ์–ด์จŒ๋“  ๋ฏธ๋“ค์›จ์–ด์—์„œ ๊ฐ€๋กœ์ฑ„์•ผ ํ•˜๊ณ  ํ‘œ์ค€ CORS ์š”์ฒญ์€ ๋ชจ๋“  HTTP ๋ฉ”์„œ๋“œ์ผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

REST ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๋‹น ์‘๋‹ต ๋ณธ๋ฌธ์„ ์ œ๊ณต ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ์ด๋™ํ•˜๋Š” ๊ฒƒ์ด ๋งค์šฐ ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๋Š” CORS ์ง€์› ๋ฌธ์ œ์™€ ์•ฝ๊ฐ„ ๋‹ค๋ฅด๋ฉฐ REST ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๊ฑฐ๊ธฐ์—์„œ ๋…๋‹จ์ ์ธ ํ–‰๋™์„ ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์˜คํžˆ๋ ค CORS๊ฐ€ ๋„๋ฆฌ ๊ตฌํ˜„๋˜๊ธฐ ์ด์ „์˜ ๋™์ž‘์ž…๋‹ˆ๋‹ค.

๋ฏธ๋“ค์›จ์–ด ์†”๋ฃจ์…˜๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•˜๊ฑฐ๋‚˜ ์ตœ์†Œํ•œ DRF์˜ ํ˜‘์กฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฐธ์กฐ๋œ ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด ์ „์—ญ ๊ธฐ๋ณธ๊ฐ’์ด CORS ํ—ค๋”๋ฅผ ์ œ๊ณตํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๊ฐ ๋ณด๊ธฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ํ—ค๋”๋ฅผ ์ „์—ญ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๋”ฐ๋ผ์„œ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ๋ณด๊ธฐ ์ง‘ํ•ฉ/๋ณด๊ธฐ์—์„œ ์ด๋Ÿฌํ•œ ๊ตฌ์„ฑ ์˜ต์…˜์— ์—ฐ๊ฒฐํ•˜๋Š” ํ‘œ์ค€ ๋ฐฉ๋ฒ•์„ ๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด allowed_cors_headers ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๋‚˜๋Š” ์ด๊ฒƒ์ด ๋ทฐ์— ์˜ํ•ด ์ฒ˜๋ฆฌ๋  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๋ฐ ๋™์˜ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด ์ œ๊ณตํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ๋ทฐ์˜ ์ง€์‹์„ ์ ˆ๋Œ€์ ์œผ๋กœ ์กด์ค‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

๋ผ์šฐํ„ฐ์˜ ๋ชจ๋“  ๋ณด๊ธฐ์— ์ ์šฉํ•  ๋ผ์šฐํ„ฐ ์ˆ˜์ค€ ์žฌ์ •์˜๋ฅผ ๊ฐ–๋Š” ๊ฒƒ๋„ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๊ณ ๋ ค ์‚ฌํ•ญ:

  • ์›์‚ฐ์ง€์— ๋”ฐ๋ผ ๋‹ค๋ฆ„
  • ์ฝ˜ํ…์ธ  ์œ ํ˜•์— ๋”ฐ๋ผ ๋‹ค๋ฆ„

์ด๊ฒƒ์€ ๋‚ด๊ฐ€ ๊ฐ€์žฅ ์ข‹์•„ํ•˜๋Š” ์„ ํƒ์€ ์•„๋‹ˆ์ง€๋งŒ ํƒ€์‚ฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ๊ฐ€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์„œ๊ฐ€ CORS ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์ •๋ณด๋กœ ์—…๋ฐ์ดํŠธ๋˜๋ฉด ์ด ํ‹ฐ์ผ“์„ ๋‹ซ์„ ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค(์˜ˆ: "์กฐ์‹ฌ, DRF๋Š” OPTIONS ์š”์ฒญ์— ๋Œ€ํ•œ W3C CORS ์‚ฌ์–‘์„ ์ถฉ์กฑํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. CORS์— OPTIONS๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ์ ์ ˆํ•œ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์—†์œผ๋ฉด ์Šน์ธ ๋ถ€์กฑ์œผ๋กœ ์ธํ•ด ์‹คํ–‰ ์ „ ์š”์ฒญ์ด ์‹คํŒจํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค." ๋“ฑ)

๊ธฐ์กด ๋ฌธ์„œ https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors ๋Š” ์™„๋ฒฝํ•˜๊ฒŒ ํ•ฉ๋ฆฌ์ ์ด๋ฉฐ ๋ฏธ๋“ค์›จ์–ด์—์„œ CORS๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ์˜ฌ๋ฐ”๋ฅธ ์ ‘๊ทผ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ ๋ณด๊ธฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ํ—ค๋”๋ฅผ ์ „์—ญ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ทธ๋Ÿด ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ์˜ CORS ์ •์ฑ…์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

CORS ๋ฌธ์„œ๋ฅผ ๋” ๋ˆˆ์— ๋„๊ฒŒ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ ์ ˆํ•œ ๋‹ค๋ฅธ ์œ„์น˜์— ํฌํ•จ์‹œํ‚ค๋Š” pull ์š”์ฒญ์„ ์ˆ˜๋ฝํ•˜๊ฒŒ ๋˜์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ ์™ธ์—๋Š” ์—ฌ๊ธฐ์— ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

์‚ฌ์–‘์— ๋Œ€ํ•œ ๋‚˜์˜ ์˜คํ•ด, ์›์Šค.

์ด ๊ฒฝ์šฐ ์ง€์›์€ django ์‚ฌ์ดํŠธ ๊ธฐ์—ฌ์— ๋” ์ž˜ ํฌํ•จ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.
ํŒจํ‚ค์ง€๊ฐ€ ์•„๋‹Œ drf.

๋ฅด๋งˆ๋ฅด. 19ํ™” 2019๋…„ 10์‹œ 22๋ถ„, Tom Christie [email protected] a
์—ํฌ๋ฆฌํŠธ :

๊ธฐ์กด ๋ฌธ์„œ
https://www.django-rest-framework.org/topics/ajax-csrf-cors/#cors ๋Š”
์™„๋ฒฝํ•˜๊ฒŒ ํ•ฉ๋ฆฌ์ ์ด๋ฉฐ ๋ฏธ๋“ค์›จ์–ด์—์„œ CORS๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ์ •ํ™•ํ•ฉ๋‹ˆ๋‹ค.
์–ด๋–ค ๊ฒฝ์šฐ์—๋„ ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ๊ฐ ๋ณด๊ธฐ๊ฐ€ ์ง€์›ํ•˜๋Š” ํ—ค๋”๋ฅผ ์ „์—ญ์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?

๊ทธ๋Ÿด ํ•„์š”๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์‚ฌ์ดํŠธ์˜ CORS ์ •์ฑ…์ด ๋ฌด์—‡์ธ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.

โ€”
๋‹น์‹ ์ด ๋Œ“๊ธ€์„ ๋‹ฌ์•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์„ ๋ฐ›๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.
์ด ์ด๋ฉ”์ผ์— ์ง์ ‘ ๋‹ต์žฅํ•˜๊ณ  GitHub์—์„œ ํ™•์ธํ•˜์„ธ์š”.
https://github.com/encode/django-rest-framework/issues/5616#issuecomment-465146969 ,
๋˜๋Š” ์Šค๋ ˆ๋“œ ์Œ์†Œ๊ฑฐ
https://github.com/notifications/unsubscribe-auth/AFhtlM6bG-Bs2CvoO972pIfwvxLHbzAxks5vPAjAgaJpZM4Qlvkn
.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰