jwt authentication in drf framework and custom jwt authentication

0909 self-summary

jwt in drf framework

I. Module Installation

Official: http://getblimp.github.io/django-rest-framework-jwt/

He's a third-party open source project.

Installation: pip install djangorestframework-jwt

Using jwt with its own settings

from django.urls import path
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
    path('login/', obtain_jwt_token),
]
'''
path('login/', obtain_jwt_token)Actually, it's equivalent to path('login/', ObtainJSONWebToken.as_view())
//Because we can see the source code between us.
obtain_jwt_token = ObtainJSONWebToken.as_view()     #Get
refresh_jwt_token = RefreshJSONWebToken.as_view()   #Refresh
verify_jwt_token = VerifyJSONWebToken.as_view()     #Verification
'''

Test interface: post request

"""
postman makes a post request

Interface: http://api.luffy.cn:8000/user/login/

Data:
{
    "username":"admin",
    "password":"admin"
}
"""

II. Working Principle

"""
jwt: json web tokens uses json format to transmit authentication strings on the web

jwt string: header, payload, signature

Head: Company Basic Information, Project Group Basic Information, General Encryption Algorithms Name
 Load: User information, expiration time
 Signature: Header, payload, secret key

{Head Information Dictionary, using base64 encryption algorithm}. {Load Information Dictionary, using base64 encryption algorithm}. {Head Encryption String, Load Encryption String, Server Key, using hs256 encryption algorithm}

base64 is Reversible Encryption
 hash256 is an irreversible encryption
 Generally, we only put account information, expiration time into payload, and password and other important information into signature.
"""

Three major certifications

session authentication

The system's own

rest_framework.authentication.SessionAuthentication
The ajax request is authenticated:
The cookie should carry session id, csrftoken, and the request header should carry x-csrftoken.

jwt certification

Third party

Unlike session authentication, he doesn't need to look up the session ID table anymore, just look up the user table.

rest_framework_jwt.authentication.JSONWebTokenAuthentication
The ajax request is authenticated:
To carry authorization in the request header, the value is jwt space token

Based on jwt, others

custom

1) Customize authentication classes, inherit BaseAuthentication (or its subclasses), and override authenticate
2) Completion in authenticate

  • Get auth

  • Reverse Resolution of user User

  • The first two steps failed to return to None => Tourists

  • The first two steps returned user successfully, auth => logged-in user

    Note: If an exception is thrown in a branch, define failure => illegal user directly

4. Custom authentication based on jwt

In fact, it is based on the source code of jwt to make relevant modifications

The simplest modification

from rest_framework.exceptions import AuthenticationFailed
import jwt
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.authentication import jwt_decode_handler

from rest_framework.authentication import BaseAuthentication
def authenticate(self, request):
    auth = from request Get it
    user = from auth Get it
    if not user:
        return None
    return user, auth

If we customize a privilege, we have to add this function to our settings for global settings.

'DEFAULT_AUTHENTICATION_CLASSES': [
    'We customize the object of the authentication function',
],

We do local settings and add them to our custom classes

authentication_classes = [Object of our custom authentication function]

V. Custom permissions are relevant

It's also source code modification.

"""
System:
1) AllowAny: Allow all users to return the validation method directly to True
 2) IsAuthenticated: Only logged-in users are allowed
    Both request.user and request.user.is_authenticated must pass
 3) Is Authenticated OrReadOnly: Visitors Read Only, Login Users Unlimited
    get, option, head requests are unrestricted
    Front-end requests must verify request.user and request.user.is_authenticated
 4) IsAdminUser: Is it a background user?
    Check request.user and request.user. is_staff_staff (users who can log in to the background management system)
    

Customization: auth-based Group and Permission tables
 1) Customize permission class, inherit BasePermission, override has_permission
 2) Completed in has_permission
    Get the logged-in user <= request.user.
    Check user's grouping or permissions
    Failure in the first two steps returns False => no privileges
    The first two steps succeed in returning True => privileges
"""
#Setting related permissions according to user group information
from rest_framework.permissions import BasePermission

class AdminPermission(BasePermission):
    # Inherit BasePermission and rewrite has_permission
    def has_permission(self, request, view):
        # Right to return to True
        # No permission, return False
        user = request.user
        if not user:
            return False
        # Users are administrator groupings (administrator groupings are a custom record in the Group table)
        if not user.groups.filter(name='Administrators'):
            return False
        # The logged-in user must be a member of the customized administrator group
        return True

If we customize a permission global setting, we have to add this function in settings ourselves.

'DEFAULT_PERMISSION_CLASSES': [
    'We customize the path of the permission function',
],

We do local settings and add them to our custom classes

permission_classes = Object of our custom authentication function

6. Custom Access Number Settings

"""
System:
1) AnonRateThrottle: Restrictions on the same IP visitors
 2) UserRateThrottle: Restrictions on users logged on to the same IP
 Must be in settings.py
'DEFAULT_THROTTLE_RATES': {
    'user':'10/min', # logged-in users can access 10 times a minute
    'anon':'3/min', # Visitors can visit three times a minute
}
In view class:
class TempAPIView(APIView):
    ...
    throttle_classes = [AnonRateThrottle, UserRateThrottle]
    
    

Customization: auth-based Group and Permission tables
 1) Customize frequency class, inherit SimpleRateThrottle, rewrite get_cache_key, and define scope
    SimpleRateThrottle has helped us implement allow_request, wait
 2) scope is used in conjunction with DEFAULT_THROTTLE_RATES of settings.py
 3) Complete in get_cache_key
    Get restricted information ident <= request
    No Restriction Information Returns None => No Restriction
    Restricted Information Returns Restricted Information String=> Restricted Information String
"""

Custom Frequency Class: One Mobile Phone Number Permits Access to Interface Only Once a Minute

from rest_framework.throttling import SimpleRateThrottle

class ThreeMinRateThrottle(SimpleRateThrottle):
    scope = 'sms'
    def get_cache_key(self, request, view):
        # Frequency limit of mobile phone number
        ident = request.data.get('mobile')
        if not ident:  # In order to find the restriction condition, return None to indicate no frequency restriction
            return None
        return self.cache_format % {
            'scope': self.scope,
            'ident': ident
        }
# settings.py 
'DEFAULT_THROTTLE_RATES': {
    'user': '10/min',  # Logged-in users can access 10 times a minute if
    'anon': '3/min',  # Visitors can visit three times a minute
    'sms': '1/min',  #It's customized. By default, only user and anon are provided.
}
On the View Layer
class UserListAPIView(ListAPIView):
    throttle_classes = [our custom method path]

A piece of code about time in the source code

    def parse_rate(self, rate):
        """
        Given the request rate string, return a two tuple of:
        <allowed number of requests>, <period of time in seconds>
        """
        if rate is None:
            return (None, None)
        num, period = rate.split('/')
        num_requests = int(num)
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
        return (num_requests, duration)

Here we can see that the first letter is taken after the string segmentation. We don't necessarily use min to represent the score on this side, as long as the beginning is m.

VII. Global Settings Effective Time and the Name of jwt

import datetime
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=30000),#d Expiration Time
    'JWT_AUTH_HEADER_PREFIX': 'TOKEN',  #When we pass parameters, we start by customizing the content. Note that this must be separated from the following token by a grid.
}

In the source code, the ___________ is

USER_SETTINGS = getattr(settings, 'JWT_AUTH', None)  #He passed the name JWT_AUTH.
......
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
'JWT_AUTH_HEADER_PREFIX': 'JWT',  The system defaults to jwt Start

8. On jwt self-customized acquisition token

Source code in rest_framework_jwt.seriallizers.py JSONWebTokenSerializer class

payload = jwt_payload_handler(user)

return {
    'token': jwt_encode_handler(payload),
    'user': user
}

If we have several key points to customize, it's better to have a method of jwt_payload_handler

One is the user object

All if we want to throw token when we log in

class LoginJWTAPIView(APIView):
    authentication_classes = ()
    permission_classes = ()
    def post(self, request, *args, **kwargs):
        # Username may carry more than a username, but it may also be the user's other unique identification phone number mailbox.
        username = request.data.get('username')
        password = request.data.get('password')

        # If username matches the cell phone number rule => it may be a cell phone login.
        if re.match(r'1[3-9][0-9]{9}', username):
            try:
                # Issuing jwt-token manually through user
                user = models.User.objects.get(mobile=username)
            except:
                return APIResponse(1, 'The mobile phone is not registered')

        # Mailbox login, etc.

        # Account login
        else:
            try:
                # Issuing jwt-token manually through user
                user = models.User.objects.get(username=username)
            except:
                return APIResponse(1, 'The account is not registered')

        # After obtaining the user, verify the password and issue token
        if not user.check_password(password):
            return APIResponse(1, 'Password error')
        payload = jwt_payload_handler(user)
        token = jwt_encode_handler(payload)
        return APIResponse(0, 'ok', results={
            'username': user.username,
            'mobile': user.mobile,
            'token': token
        })

Tags: Python Mobile Session Django JSON

Posted on Mon, 09 Sep 2019 07:41:58 -0700 by davitz38