Django认证插件:rest_framework_simplejwt

rest_framework_simplejwt

官方文档

环境参数

  • Python == 3.8
  • Django == 2.2.19
  • Django REST Framework == 3.12.4
  • PyJWT == 2.2.0

安装

pip install djangorestframework-simplejwt

设置配置

django-setting 中配置 simplejwt 参数

# 在setting中配置认证插件
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    )
}

# 注册应用
INSTALLED_APPS=[
'rest_framework_simplejwt',
]


#在 setting 配置认证插件的参数
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_code',
    'ALGORITHM': 'HS256',
    'SIGNING_KEY': SECRET_KEY,
    'AUTH_HEADER_TYPES': ('Token',),
}

SIMPLE_JWT 配置说明

一些 Simple JWT 的行为可以通过以下中的设置变量进行自定义
官方文档

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

    'ALGORITHM': 'HS256',
    'SIGNING_KEY': settings.SECRET_KEY,
    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': 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',

    'JTI_CLAIM': 'jti',

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

自定义方法

自定义认证-用户名-手机号-邮箱都作为认证方式

1、在用户应用下新建:utlis.py(auth_user.utlis.CustomBackend)

from .models import UserProfile
from django.contrib.auth.backends import ModelBackend
from django.db.models import Q

class CustomBackend(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        # noinspection PyBroadException
        try:
            # 添加了一个手机验证,如果需要其他验证再加
            user = UserProfile.objects.get(Q(username=username) | Q(mobile=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None

2、setting中设置:AUTHENTICATION_BACKENDS

# 自定义认证后端
AUTHENTICATION_BACKENDS = ('auth_user.utlis.CustomBackend',)

自定义获取token响应:需要新建视图-继承TokenObtainPairSerializer重写响应方式

1、在用户应用下新建视图:MyTokenObtainPairView,重写sm-jwt的响应方式

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView

class FormulaTokenObtainPairSerializer(TokenObtainPairSerializer):
    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

    def validate(self, attrs):
        data = super().validate(attrs)

        refresh = self.get_token(self.user)

        data['username'] = self.user.username
        data['mobile'] = self.user.mobile
        data['refresh'] = str(refresh)
        data['access'] = str(refresh.access_token)

        return {"code": "200", "msg": "ok", "data": data}

class FormulaTokenObtainPairView(TokenObtainPairView):
    serializer_class = FormulaTokenObtainPairSerializer

2、添加到视图url

from .authorization import FormulaTokenObtainPairView
urlpatterns = [
    path("login", FormulaTokenObtainPairView.as_view(), name="login"), # 获取token
]

3、在工程urls添加路由

urlpatterns = [
    # path('token', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('token/refresh', TokenRefreshView.as_view(), name='token_refresh'),
    path('token/verify', TokenVerifyView.as_view(), name='token_verify'),
    path('auth/', include("auth_user.urls")),  # 重写token
]

4、作为登录鉴权,获取token

自定义token异常响应

1、在新建文件:formula -> middleware.py 中间件

# 登录过期时 自定义 返回
class ExceptionChange:

    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        return response

    def process_template_response(self, request, response):
        if hasattr(response, 'data'):
            data = response.data
            if isinstance(data, dict) is True:
                if "detail" in data.keys():
                    # 用户名或密码错误
                    if data.get("detail") == "找不到指定凭据对应的有效用户":
                        del response.data["detail"]
                        response.data["code"] = 402
                        response.data["msg"] = "用户名或者密码错误!"

                    # 验证信息过期 token 过期
                    if data.get("detail") == "此令牌对任何类型的令牌无效":
                        del response.data["detail"]
                        del response.data["messages"]
                        response.data["code"] = 401
                        response.data["msg"] = "登录已过期,请重新登录"

                    # 未使用验证信息 未带验证信息请求
                    if data.get("detail") == "身份认证信息未提供。":  # 身份认证信息未提供。
                        del response.data["detail"]
                        response.data["code"] = 401
                        response.data["msg"] = "登录已过期,请重新登录"

                    # refresh 无效或者过期
                    if data.get("detail") == "令牌无效或已过期":  # 身份认证信息未提供。
                        del response.data["detail"]
                        response.data["code"] = 403
                        response.data["msg"] = "令牌无效或已过期"

        return response

2、在setting中配置

MIDDLEWARE = [
    ...
    # 自定义:错误状态返回
    "formula.middleware.ExceptionChange",
]

访问视图增加鉴权

1、 新建文件:File : formula -> mixin.py

from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticated


class FormulaApiViews(APIView):
    permission_classes = (IsAuthenticated,)

2、在之后的每个视图继承此方法,用于鉴权;可扩展

api: token-refresh-verify

获取token & refresh

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"username": "admin", "password": "000000"}' \
  http://localhost:8000/api/v1/login

{
  "access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU",
  "refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"
}

刷新token

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"refresh":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImNvbGRfc3R1ZmYiOiLimIMiLCJleHAiOjIzNDU2NywianRpIjoiZGUxMmY0ZTY3MDY4NDI3ODg5ZjE1YWMyNzcwZGEwNTEifQ.aEoAYkSJjoWH1boshQAaTkf8G3yn0kapko6HFRt7Rh4"}' \
  http://localhost:8000/api/v1/token/refresh

{
  "access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU",
}

验证token

curl \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"access":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX3BrIjoxLCJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiY29sZF9zdHVmZiI6IuKYgyIsImV4cCI6MTIzNDU2LCJqdGkiOiJmZDJmOWQ1ZTFhN2M0MmU4OTQ5MzVlMzYyYmNhOGJjYSJ9.NHlztMGER7UADHZJlxNG0WSi22a2KaYSfd1S-AuT7lU"}' \
  http://localhost:8000/api/v1/token/verify

{}

异常问题

1、PyJWKClient

  1. cannot import name ‘PyJWKClient’ from ‘jwt’

你可能感兴趣的:(django,restful,python)