RESTful API এর জন্য টোকেন প্রমাণীকরণ: টোকেনটি পর্যায়ক্রমে পরিবর্তন করা উচিত?


115

আমি জ্যাঙ্গো এবং জ্যাঙ্গো -রেস্ট-ফ্রেমওয়ার্কের সাথে একটি RESTful API তৈরি করছি ।

প্রমাণীকরণ প্রক্রিয়া হিসাবে আমরা "টোকেন প্রমাণীকরণ" বেছে নিয়েছি এবং জাজানো-আরইএসটি-ফ্রেমওয়ার্কের নথিপত্র অনুসরণ করে আমি ইতিমধ্যে এটি প্রয়োগ করেছি, প্রশ্নটি হল, অ্যাপ্লিকেশনটি পর্যায়ক্রমে টোকন পুনর্নবীকরণ / পরিবর্তন করা উচিত এবং যদি হ্যাঁ কীভাবে? টোকনটি পুনর্নবীকরণের প্রয়োজন হওয়া মোবাইল অ্যাপটি হওয়া উচিত বা ওয়েব-অ্যাপ্লিকেশনটি স্বায়ত্তশাসিতভাবে করা উচিত?

সেরা অনুশীলন কি?

এখানকার যে কেউ জ্যাঙ্গো রেস্ট ফ্রেমওয়ার্ক নিয়ে অভিজ্ঞ এবং প্রযুক্তিগত সমাধানের পরামর্শ দিতে পারেন?

(শেষ প্রশ্নের নিম্ন অগ্রাধিকার আছে)

উত্তর:


101

মোবাইল ক্লায়েন্টরা তাদের প্রমাণীকরণ টোকেন পর্যায়ক্রমে পুনর্নবীকরণ করা ভাল অনুশীলন। এটি অবশ্যই প্রয়োগ করতে সার্ভারের উপর নির্ভর করে।

ডিফল্ট টোকেনআথেন্টিকেশন শ্রেণি এটি সমর্থন করে না, তবে আপনি এই কার্যকারিতা অর্জন করতে এটি প্রসারিত করতে পারেন।

উদাহরণ স্বরূপ:

from rest_framework.authentication import TokenAuthentication, get_authorization_header
from rest_framework.exceptions import AuthenticationFailed

class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        # This is required for the time comparison
        utc_now = datetime.utcnow()
        utc_now = utc_now.replace(tzinfo=pytz.utc)

        if token.created < utc_now - timedelta(hours=24):
            raise exceptions.AuthenticationFailed('Token has expired')

        return token.user, token

এটি ডিফল্ট রেস্ট ফ্রেমওয়ার্ক লগইন ভিউকে ওভাররাইড করাও প্রয়োজন, যাতে যখনই লগইন হয়ে যায় তখন টোকেনটি রিফ্রেশ হয়:

class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            token, created =  Token.objects.get_or_create(user=serializer.validated_data['user'])

            if not created:
                # update the created time of the token to keep it valid
                token.created = datetime.datetime.utcnow()
                token.save()

            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

এবং ইউআরএলগুলি সংশোধন করতে ভুলবেন না:

urlpatterns += patterns(
    '',
    url(r'^users/login/?$', '<path_to_file>.obtain_expiring_auth_token'),
)

6
আপনি পুরানোটির জন্য টাইমস্ট্যাম্পটি আপডেট করার পরিবর্তে, যদি এটির মেয়াদ শেষ হয়ে যায় তবে আপনি ObtainExperingAuthToken এ একটি নতুন টোকেন তৈরি করতে চান না?
জোয়ার লেথ

4
একটি নতুন টোকেন তৈরি করা অর্থবোধ করে। আপনি বিদ্যমান টোকেন কীটির মানটি পুনরায় তৈরি করতে পারেন এবং তারপরে আপনাকে পুরানো টোকেনটি মুছতে হবে না।
odedfos

আমি যদি মেয়াদোত্তীকরণের টোকেনটি সাফ করতে চাই? আমি যখন get_or_create আবার কি একটি নতুন টোকেন উত্পন্ন হবে বা টাইমস্ট্যাম্প আপডেট হবে?
Sayok88

3
এছাড়াও, আপনি বৈধতা বাধা না দিয়ে, ক্রোনজব (সেলারি বিট বা অনুরূপ) সময়ে পর্যায়ক্রমে পুরানোগুলি উচ্ছেদ করে টেবিল থেকে টোকেনের মেয়াদ শেষ করতে পারেন
BjornW

1
@ জর্জনডাব্লু আমি কেবল উচ্ছেদের কাজটি করব এবং আমার মতে, কোনও ব্যক্তির অনুরোধ করা API (বা আপনার সামনের দিকের) সাথে সংহত করার দায়িত্ব, তারা "অবৈধ টোকেন" পেয়েছে এবং তারপরে রিফ্রেশ / নতুন টোকেন শেষ পয়েন্ট তৈরি করুন
শিববিশাম

25

যদি কেউ এই সমাধানটিতে আগ্রহী হন তবে একটি নির্দিষ্ট সময়ের জন্য বৈধ এমন একটি টোকেন রাখতে চান তবে একটি নতুন টোকেন দ্বারা প্রতিস্থাপিত হয়ে নিন এখানে সম্পূর্ণ সমাধান (জাজানো 1.6):

yourmodule / views.py:

import datetime
from django.utils.timezone import utc
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from django.http import HttpResponse
import json

class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.DATA)
        if serializer.is_valid():
            token, created =  Token.objects.get_or_create(user=serializer.object['user'])

            utc_now = datetime.datetime.utcnow()    
            if not created and token.created < utc_now - datetime.timedelta(hours=24):
                token.delete()
                token = Token.objects.create(user=serializer.object['user'])
                token.created = datetime.datetime.utcnow()
                token.save()

            #return Response({'token': token.key})
            response_data = {'token': token.key}
            return HttpResponse(json.dumps(response_data), content_type="application/json")

        return HttpResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

obtain_expiring_auth_token = ObtainExpiringAuthToken.as_view()

yourmodule / urls.py:

from django.conf.urls import patterns, include, url
from weights import views

urlpatterns = patterns('',
    url(r'^token/', 'yourmodule.views.obtain_expiring_auth_token')
)

আপনার প্রকল্প urls.py (urlpatterns অ্যারে মধ্যে):

url(r'^', include('yourmodule.urls')),

yourmodule / authentication.py:

import datetime
from django.utils.timezone import utc
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions

class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):

        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        utc_now = datetime.datetime.utcnow()

        if token.created < utc_now - datetime.timedelta(hours=24):
            raise exceptions.AuthenticationFailed('Token has expired')

        return (token.user, token)

আপনার REST_FRAMEWORK সেটিংসে এক্সপায়ারিং টোকেন অটোথেন্টিকেশন টোকেনআথেন্টিফিকেশনের পরিবর্তে একটি প্রমাণীকরণ শ্রেণি হিসাবে যুক্ত করুন:

REST_FRAMEWORK = {

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.SessionAuthentication',
        #'rest_framework.authentication.TokenAuthentication',
        'yourmodule.authentication.ExpiringTokenAuthentication',
    ),
}

আমি 'ObtainExpiringAuthToken' object has no attribute 'serializer_class'এপিআই শেষ পয়েন্টটি অ্যাক্সেস করার চেষ্টা করলে ত্রুটিটি পাচ্ছি। আমি কী মিস করছি তা নিশ্চিত নয়।
ধর্মিত

2
আকর্ষণীয় সমাধান, যা আমি পরে পরীক্ষা করব; এই মুহুর্তে আপনার পোস্টটি আমাকে সঠিক ট্র্যাকটিতে উঠতে সহায়তা করেছিল কারণ আমি সহজভাবে AUTHENTICATION_CLASSES সেট করতে ভুলে গেছি।
normic

2
পার্টিতে দেরি হয়ে আসছে তবে এটি কার্যকর করার জন্য আমার কিছু সূক্ষ্ম পরিবর্তন করা দরকার। 1) utc_now = ডেটটাইম.ডেটটাইম.টুকনো () উটক_নো = ডেটটাইম.ডেটটাইম.টাকনো () হওয়া উচিত get_model ()
ভট্ট

5

আমি @odedfos উত্তর চেষ্টা করেছি কিন্তু আমার বিভ্রান্তিকর ত্রুটি ছিল । এখানে একই উত্তর, স্থির এবং সঠিক আমদানি সহ।

views.py

from django.utils import timezone
from rest_framework import status
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken

class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request):
        serializer = self.serializer_class(data=request.DATA)
        if serializer.is_valid():
            token, created =  Token.objects.get_or_create(user=serializer.object['user'])

            if not created:
                # update the created time of the token to keep it valid
                token.created = datetime.datetime.utcnow().replace(tzinfo=utc)
                token.save()

            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

authentication.py

from datetime import timedelta
from django.conf import settings
from django.utils import timezone
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions

EXPIRE_HOURS = getattr(settings, 'REST_FRAMEWORK_TOKEN_EXPIRE_HOURS', 24)

class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        try:
            token = self.model.objects.get(key=key)
        except self.model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        if token.created < timezone.now() - timedelta(hours=EXPIRE_HOURS):
            raise exceptions.AuthenticationFailed('Token has expired')

        return (token.user, token)

4

ভেবেছিলাম আমি ডিআরওয়াই ব্যবহার করে একটি জ্যাঙ্গো 2.0 উত্তর দেব answer গুগল জ্যাঙ্গো ওআউথ সরঞ্জামকিট গুগল ইতিমধ্যে আমাদের জন্য এটি তৈরি করেছে। পাইপ সহ উপলব্ধ pip install django-oauth-toolkit,। রাউটারগুলির সাথে টোকেন ভিউসেটগুলি যুক্ত করার নির্দেশাবলী: https://django-oauth-toolkit.readthedocs.io/en/latest/rest-framework/getting_st সূত্র html । এটি সরকারী টিউটোরিয়ালের অনুরূপ।

সুতরাং মূলত ওআউথ 1.0 ছিল গতকালের সুরক্ষা যা টোকেনআউথেন্টিকেশনটি। অভিনব মেয়াদ উত্তীর্ণ টোকেন পেতে, OAuth2.0 আজকাল সমস্ত ক্রোধ। অনুমতিগুলি জরিমানা করার জন্য আপনি একটি অ্যাক্সেস টোকেন, রিফ্রেশ টোকেন এবং স্কোপ ভেরিয়েবল পাবেন। আপনি এই জাতীয় ক্রেডিট দিয়ে শেষ:

{
    "access_token": "<your_access_token>",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "<your_refresh_token>",
    "scope": "read"
}

4

লেখক জিজ্ঞাসা করলেন

প্রশ্নটি হ'ল, অ্যাপ্লিকেশনটি পর্যায়ক্রমে টোকনকে পুনর্নবীকরণ / পরিবর্তন করা উচিত এবং যদি হ্যাঁ কীভাবে? টোকনটি পুনর্নবীকরণের প্রয়োজন হওয়া মোবাইল অ্যাপটি হওয়া উচিত বা ওয়েব-অ্যাপ্লিকেশনটি স্বায়ত্তশাসিতভাবে করা উচিত?

তবে উত্তরগুলির সমস্তগুলি কীভাবে স্বয়ংক্রিয়ভাবে টোকেন পরিবর্তন করতে হবে সে সম্পর্কে লিখছেন।

আমি মনে করি পর্যায়ক্রমে টোকেন দ্বারা টোকেন পরিবর্তন অর্থহীন। বাকি ফ্রেমওয়ার্কটি একটি টোকেন তৈরি করে যাতে 40 টি অক্ষর থাকে, যদি আক্রমণকারী প্রতি সেকেন্ডে 1000 টোকেন পরীক্ষা করে, এটি 16**40/1000/3600/24/365=4.6*10^7টোকেন পেতে কয়েক বছর সময় প্রয়োজন । আপনার উদ্বেগ হওয়া উচিত নয় যে আক্রমণকারী আপনার টোকেনটি একে একে পরীক্ষা করবে। এমনকি আপনি নিজের টোকেনটি পরিবর্তন করেছেন, আপনার টোকেন অনুমান করার সম্ভাবনাও একই।

যদি আপনি উদ্বিগ্ন থাকেন যে সম্ভবত আক্রমণকারীরা আপনাকে টোকেন পেতে পারে, তাই আক্রমণকারীটি টোকেন পাওয়ার পরে, আপনি সময় সময়ত এটি পরিবর্তন করেন, আসল ব্যবহারকারীর বাইরে চলে যাওয়ার চেয়ে তিনি আপনাকে টোকেনও পরিবর্তন করতে পারেন।

আপনার যা করা উচিত তা হ'ল থা আক্রমণকারীকে আপনার ব্যবহারকারীর টোকেন পেতে বাধা দেওয়া, https ব্যবহার করুন

যাইহোক, আমি কেবল টোকেন দ্বারা টোকেন পরিবর্তন অর্থহীন, ইউজারনেম এবং পাসওয়ার্ড দ্বারা টোকেন পরিবর্তন কখনও কখনও অর্থবোধক হয়। হতে পারে টোকেনটি কিছু HTTP পরিবেশে ব্যবহার করা হবে (আপনার সর্বদা এই ধরণের পরিস্থিতি এড়ানো উচিত) বা কোনও তৃতীয় পক্ষ (এই ক্ষেত্রে আপনার বিভিন্ন ধরণের টোকেন তৈরি করা উচিত, oauth2 ব্যবহার করা উচিত) এবং যখন ব্যবহারকারী কোনও বিপজ্জনক জিনিস যেমন পরিবর্তন করার মতো করছে বাঁধাই করা মেলবক্স বা অ্যাকাউন্ট মুছুন, আপনাকে অবশ্যই নিশ্চিত করতে হবে যে আপনি আর মূল টোকেনটি ব্যবহার করবেন না কারণ এটি আক্রমণকারী দ্বারা স্নিফার বা tcpdump সরঞ্জাম ব্যবহার করে প্রকাশিত হতে পারে।


হ্যাঁ, সম্মত হন, আপনার অন্য কোনও উপায়ে (পুরানো অ্যাক্সেস টোকেনের চেয়ে) নতুন অ্যাক্সেস টোকেন পাওয়া উচিত। রিফ্রেশ টোকেনের মতো (বা কমপক্ষে পাসওয়ার্ড দিয়ে একটি নতুন লগইন জোর করার পুরানো উপায়)।
বজর্নডাব্লু

3

আপনি http://getblimp.github.io/django-rest-framework-jwt উপার্জন করতে পারেন

এই লাইব্রেরিটি টোকেন তৈরি করতে সক্ষম যার মেয়াদ শেষ হওয়ার তারিখ রয়েছে

ডিআরএফের ডিফল্ট টোকেন এবং ডিআরএফ দ্বারা সরবরাহিত টোকেনের মধ্যে পার্থক্য বুঝতে একবার দেখুন:

মাল্টিপল ওয়েবসার্স দিয়ে জ্যাঙ্গো REST JWT প্রমাণীকরণ স্কেলটি কীভাবে তৈরি করবেন?


1

আপনি যদি খেয়াল করেন যে একটি টোকেনটি সেশন কুকির মতো হয় তবে আপনি জাঙ্গোতে সেশন কুকিজের ডিফল্ট জীবনকালকে আটকে রাখতে পারেন: https://docs.djangoproject.com/en/1.4/ref/settings/#session-cookie-age

জাজানো রেস্ট ফ্রেমওয়ার্কটি স্বয়ংক্রিয়ভাবে পরিচালনা করে কিনা তা আমি জানি না তবে আপনি সর্বদা একটি স্বল্প স্ক্রিপ্ট লিখতে পারেন যা পুরানোগুলিকে ফিল্টার করে এবং মেয়াদোত্তীর্ণ হিসাবে চিহ্নিত করে।


1
টোকেন প্রমাণীকরণ কুকি ব্যবহার করে না
s29

0

এটি ভেবেছিল আমি আমার যোগ করব কারণ এটি আমার পক্ষে সহায়ক। আমি সাধারণত জেডাব্লুটি পদ্ধতিতে যাই তবে কখনও কখনও এর মতো কিছু ভাল হয়। আমি সঠিক আমদানি সহ জ্যাঙ্গো ২.১ এর জন্য গৃহীত উত্তরটি আপডেট করেছি ..

authentication.py

from datetime import timedelta
from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.utils import timezone
from rest_framework.authentication import TokenAuthentication
from rest_framework import exceptions

EXPIRE_HOURS = getattr(settings, 'REST_FRAMEWORK_TOKEN_EXPIRE_HOURS', 24)


class ExpiringTokenAuthentication(TokenAuthentication):
    def authenticate_credentials(self, key):
        try:
            token = self.get_model().objects.get(key=key)
        except ObjectDoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        if token.created < timezone.now() - timedelta(hours=EXPIRE_HOURS):
            raise exceptions.AuthenticationFailed('Token has expired')

    return token.user, token

views.py

import datetime
from pytz import utc
from rest_framework import status
from rest_framework.response import Response
from rest_framework.authtoken.models import Token
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.serializers import AuthTokenSerializer


class ObtainExpiringAuthToken(ObtainAuthToken):
    def post(self, request, **kwargs):
        serializer = AuthTokenSerializer(data=request.data)

        if serializer.is_valid():
            token, created = Token.objects.get_or_create(user=serializer.validated_data['user'])
            if not created:
                # update the created time of the token to keep it valid
                token.created = datetime.datetime.utcnow().replace(tzinfo=utc)
                token.save()

            return Response({'token': token.key})
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

0

কেবল @odedfos জবাব যোগ করার জন্য, আমি মনে করি সিনট্যাক্সে কিছু পরিবর্তন হয়েছে তাই এক্সপায়ারিং টোকেনআউথেন্টিকেশনের কোডটির কিছু সামঞ্জস্যতা প্রয়োজন:

from rest_framework.authentication import TokenAuthentication
from datetime import timedelta
from datetime import datetime
import datetime as dtime
import pytz

class ExpiringTokenAuthentication(TokenAuthentication):

    def authenticate_credentials(self, key):
        model = self.get_model()
        try:
            token = model.objects.get(key=key)
        except model.DoesNotExist:
            raise exceptions.AuthenticationFailed('Invalid token')

        if not token.user.is_active:
            raise exceptions.AuthenticationFailed('User inactive or deleted')

        # This is required for the time comparison
        utc_now = datetime.now(dtime.timezone.utc)
        utc_now = utc_now.replace(tzinfo=pytz.utc)

        if token.created < utc_now - timedelta(hours=24):
            raise exceptions.AuthenticationFailed('Token has expired')

        return token.user, token

এছাড়াও, এটিকে বিশ্রাম_ ফ্রেমওয়ার্ক.অটেনটিকেশন এর পরিবর্তে DEFAULT_AUTHENTICATION_CLASSES এ যুক্ত করতে ভুলবেন না

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.