Django之使用自定義用戶表(AbstractUser)/自定義登錄驗證(jwt)/獲取當(dāng)前登錄用戶

基本步驟:

一侨赡、自定義用戶表:

1冷蚂、自定義的用戶表繼承AbstractUser覆旱;
2骇塘、settings.py添加配置伊履,指向用戶表:AUTH_USER_MODEL = 'myUser.Account'(子項目名稱.用戶表models名稱);
3款违、python manage.py makemigrations
4唐瀑、python manage.py migrate

二、自定義登錄驗證:
# 簽發(fā):
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# 生成token:
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
三插爹、獲取當(dāng)前登錄用戶:
# 通過headers獲取token:
token = request.META.get('HTTP_AUTHORIZATION')
# 情況一:token的傳參格式為JWT xxxx
token = request.META.get('HTTP_AUTHORIZATION')[4:]
# 情況二:token的傳參格式為TOKEN xxxx
token = request.META.get('HTTP_AUTHORIZATION')[7:]
# 然后解析出user_id和username:
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
  • 基本目錄結(jié)構(gòu)


    基本目錄結(jié)構(gòu)

話不多說哄辣,直接上代碼

  • models:
from django.db import models
from django.contrib.auth.models import AbstractUser


"""
基類:可以把通用的字段定義這里,其他地方繼承基類即可擁有
"""
class BaseModel(models.Model):
    updated_tm = models.DateTimeField(auto_now=True)
    created_tm = models.DateTimeField(auto_now_add=True)

    class Meta:
        abstract = True

"""
用戶表:自定義的用戶表
想要使用自定義的用戶表進行登錄驗證赠尾,需要滿足下面的條件:
1力穗、需要繼承AbstractUser;
2气嫁、settings.py添加配置:AUTH_USER_MODEL = 'myUser.Account'(子項目名稱.用戶表models名稱)
"""
class Account(AbstractUser, BaseModel):
    user_id = models.AutoField(help_text="用戶id", primary_key=True)
    username = models.SlugField(max_length=128, help_text="用戶名", unique=True)
    password = models.CharField(max_length=128, help_text="用戶密碼")
    nickname = models.CharField(max_length=128, help_text="用戶昵稱")

    # 指定數(shù)據(jù)庫表信息
    class Meta:
        db_table = 'user'
        verbose_name = '用戶基礎(chǔ)信息'
        verbose_name_plural = verbose_name

"""
項目表:重點關(guān)注editor字段
"""
class ProjectList(BaseModel):
    """項目基本信息"""
    project_id = models.AutoField(help_text="項目id", primary_key=True)
    project_name = models.SlugField(max_length=128, help_text="項目名", unique=True)
    editor = models.CharField(max_length=128, default='admin', help_text="編輯者")

    class Meta:
        db_table = 'project'
        verbose_name = '項目基本信息'
        verbose_name_plural = verbose_name
  • 自定義用戶數(shù)據(jù)庫表
自定義用戶數(shù)據(jù)庫表
  • serializers
from rest_framework import serializers
from myUser.models import BaseModel, Account
from myProject.models import ProjectList
import time


class BaseSerializer(serializers.ModelSerializer):
    """基類序列化器"""
    create_tm_format = serializers.DateTimeField(source="created_tm",
                                                 format="%Y-%m-%d %H:%M:%S",
                                                 required=False,
                                                 read_only=True,
                                                 help_text='創(chuàng)建時間(北京時間)')

    update_tm_format = serializers.DateTimeField(source="updated_tm",
                                                 format="%Y-%m-%d %H:%M:%S",
                                                 required=False,
                                                 read_only=True,
                                                 help_text='更新時間(北京時間)')

    created_tm = serializers.DateTimeField(required=False,
                                           read_only=True,
                                           help_text='創(chuàng)建時間(時間戳)')

    updated_tm = serializers.DateTimeField(required=False,
                                           read_only=True,
                                           help_text='更新時間(時間戳)')

    class Meta:
        model = BaseModel
        fields = ("created_tm", "updated_tm",
                  "create_tm_format", "update_tm_format")


class UserSerializer(BaseSerializer):
    """用戶基本信息"""
    user_id = serializers.IntegerField(read_only=True)

    class Meta:
        model = Account

        fields = ('username', 'password', 'user_id')


class ProjectListSerializer(BaseSerializer):
    """項目基本信息"""
    class Meta:
        model = ProjectList

        fields = ('project_id', 'project_name', 'editor',
                  'created_start_tm', 'created_end_tm',
                  "created_tm", "updated_tm")
  • filter
import django_filters
from myUser.models import Account
from myProject.models import ProjectList


class UserFilter(django_filters.rest_framework.FilterSet):
    """用戶基本信息"""
    user_id = django_filters.NumberFilter(field_name='user_id', lookup_expr='exact')
    username = django_filters.CharFilter(field_name='username', lookup_expr='icontains')
    nickname = django_filters.CharFilter(field_name='nickname', lookup_expr='icontains')
    created_start_tm = django_filters.DateTimeFromToRangeFilter(field_name='創(chuàng)建開始時間')
    created_end_tm = django_filters.DateTimeFromToRangeFilter(field_name='創(chuàng)建結(jié)束時間')

    class Meta:
        model = Account
        fields = ('user_id', 'username', 'created_start_tm', 'created_end_tm')


class ProjectListFilter(django_filters.rest_framework.FilterSet):
    """項目基本信息"""
    project_id = django_filters.NumberFilter(field_name='project_id', lookup_expr='exact')
    project_name = django_filters.CharFilter(field_name='project_name', lookup_expr='icontains')
    editor = django_filters.CharFilter(field_name='editor', lookup_expr='exact')
    created_start_tm = django_filters.DateTimeFromToRangeFilter(field_name='創(chuàng)建開始時間')
    created_end_tm = django_filters.DateTimeFromToRangeFilter(field_name='創(chuàng)建結(jié)束時間')

    class Meta:
        model = ProjectList
        fields = ('project_id', 'project_name', 'created_start_tm', 'created_end_tm')
  • 用戶登錄views
from drf_yasg.utils import swagger_auto_schema
from myUser.models import Account
from rest_framework import mixins
from rest_framework.generics import GenericAPIView
from serializers import UserSerializer
from render_response import APIResponse
from rest_framework_jwt.settings import api_settings

# 簽發(fā)
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# 生成token
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER


# Create your views here.
class LoginView(mixins.UpdateModelMixin, GenericAPIView):
    authentication_classes = ()
    permission_classes = ()

    queryset = Account.objects.all()
    serializer_class = UserSerializer
    ordering = ['-created_tm']
    tag = ['用戶']

    @swagger_auto_schema(tags=tag,
                         operation_id="login",
                         operation_summary='用戶登錄',
                         operation_description='明文密碼',
                         responses={400010: "賬號密碼錯誤", 200: UserSerializer})
    def post(self, request, *args, **kwargs):
        """
        post: 用戶登錄

        400010:賬號密碼錯誤
        """
        username = str(request.data.get('username'))
        password = str(request.data.get('password'))

        try:
            Account.objects.get(username=username)
        except Account.DoesNotExist:
            return APIResponse(400010, '賬號密碼錯誤', success=False)

        try:
            Account.objects.get(password=password, username=username)
        except Account.DoesNotExist:
            return APIResponse(400010, '賬號密碼錯誤', success=False)

        user = Account.objects.filter(username=username, password=password).first()
        if user:
            # 登錄成功当窗,簽發(fā)token,通過當(dāng)前登錄用戶獲取荷載(payload)
            payload = jwt_payload_handler(user)
            # 通過payload生成token串(三段:頭,payload寸宵,簽名)
            token = jwt_encode_handler(payload)
            response = {"user_id": user.user_id, "username": username, "token": token}
            return APIResponse(200, '登錄成功', response)
  • 項目創(chuàng)建views
from drf_yasg.utils import swagger_auto_schema
from myProject.models import ProjectList
from rest_framework import mixins
from rest_framework.viewsets import GenericViewSet
from serializers import ProjectListSerializer
from render_response import APIResponse
from rest_framework.response import Response
from get_login_user_info import GetLoginUser


# Create your views here.
class AddProjectViews(mixins.CreateModelMixin, GenericViewSet):
    authentication_classes = []
    permission_classes = ()

    queryset = ProjectList.objects.all().order_by("-created_tm")
    serializer_class = ProjectListSerializer
    tag = ['項目']

    @swagger_auto_schema(tags=tag,
                         operation_summary='創(chuàng)建項目',
                         operation_id="project_create",
                         operation_description='項目名稱必填',
                         responses={400014: "參數(shù)錯誤", 
                                    200: ProjectListSerializer,
                                    400013: "請檢查輸入字段是否正確(必填字段崖面、未定義字段)", 
                                    500001: "項目名稱長度需要1到20位", 
                                    500002: "項目已存在", 
                                    500003: "項目創(chuàng)建失敗", })
    def create(self, request, *args, **kwargs):
        """新增項目"""
        try:
            project_name = request.data.get("project_name")
            project_desc = request.data.get("project_desc")
        except Exception:
            return APIResponse(400014, '參數(shù)錯誤', success=False)

        field_list = {}
        if project_name:
            field_list["project_name"] = project_name
        if project_desc:
            field_list["project_desc"] = project_desc

        # 獲取當(dāng)前登錄用戶信息
        user = GetLoginUser().get_login_user(request)
        if user["code"] == 200:
            field_list["editor"] = user["username"]
        else:
            return Response(user)

        # 檢查賬號密碼是否有填寫
        if "project_name" not in list(field_list.keys()):
            return APIResponse(400013, '請檢查輸入字段是否正確(必填字段、未定義字段)', success=False)
        else:
            if len(field_list["project_name"]) > 20 or len(field_list["project_name"]) < 1:
                return APIResponse(500001, '項目名稱長度需要1到20位', success=False)

        try:
            ProjectList.objects.get(project_name=field_list["project_name"])
            return APIResponse(500002, '項目已存在', success=False)
        except ProjectList.DoesNotExist:
            try:
                ProjectList.objects.create(**field_list)
                return APIResponse(200, '項目創(chuàng)建成功')
            except Exception as e:
                print(e)
                return APIResponse(500003, '項目創(chuàng)建失敗', success=False)
  • token的傳參
token的傳參
  • 返回我是這么定義的(來自網(wǎng)友)
"""
自定義返回處理
"""
from rest_framework.response import Response


class APIResponse(Response):
    def __init__(self, code=200, msg='請求成功', data=None, status=None, headers=None, success=True, **kwargs):
        dic = {'code': code, 'message': msg, 'success': success, 'data': None}
        if data:
            dic['data'] = data
        dic.update(kwargs)  # 可以靈活的添加梯影,需要返回的鍵值對
        super().__init__(data=dic, status=status, headers=headers)
  • 獲取當(dāng)前登錄用戶信息我是這么寫的(原創(chuàng))
from myUser.models import Account
from jwt import ExpiredSignatureError
from render_response import APIResponse
from rest_framework_jwt.settings import api_settings

# 解析token
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER


class GetLoginUser:
    @staticmethod
    def get_login_user(request):
        try:
            token = request.META.get('HTTP_AUTHORIZATION')
        except Exception:
            return APIResponse(400014, '參數(shù)錯誤', success=False)

        if token:
            try:
                # 解密token巫员,提取user_id
                user_id = jwt_decode_handler(token)["user_id"]
                username = Account.objects.filter(user_id=user_id).values('username').first()
                return {"user_id": user_id, "username": username["username"], "code": 200}
            except ExpiredSignatureError:
                return APIResponse(4031, 'token已過期', success=False)
        else:
            return APIResponse(403, '無訪問權(quán)限,請重新登錄或稍后再試光酣!', success=False)
  • 簡易的swagger文檔


    簡易的swagger文檔
  • 用戶登錄


    用戶登錄
  • 項目創(chuàng)建

項目創(chuàng)建
項目表
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末疏遏,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子救军,更是在濱河造成了極大的恐慌,老刑警劉巖倘零,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件唱遭,死亡現(xiàn)場離奇詭異,居然都是意外死亡呈驶,警方通過查閱死者的電腦和手機拷泽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人司致,你說我怎么就攤上這事拆吆。” “怎么了脂矫?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵枣耀,是天一觀的道長。 經(jīng)常有香客問我庭再,道長捞奕,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任拄轻,我火速辦了婚禮颅围,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恨搓。我一直安慰自己院促,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布斧抱。 她就那樣靜靜地躺著一疯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪夺姑。 梳的紋絲不亂的頭發(fā)上墩邀,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音盏浙,去河邊找鬼眉睹。 笑死,一個胖子當(dāng)著我的面吹牛废膘,可吹牛的內(nèi)容都是我干的竹海。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼丐黄,長吁一口氣:“原來是場噩夢啊……” “哼斋配!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灌闺,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤艰争,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后桂对,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體甩卓,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年蕉斜,在試婚紗的時候發(fā)現(xiàn)自己被綠了逾柿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缀棍。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖机错,靈堂內(nèi)的尸體忽然破棺而出爬范,到底是詐尸還是另有隱情,我是刑警寧澤弱匪,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布青瀑,位于F島的核電站,受9級特大地震影響痢法,放射性物質(zhì)發(fā)生泄漏狱窘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一财搁、第九天 我趴在偏房一處隱蔽的房頂上張望蘸炸。 院中可真熱鬧,春花似錦尖奔、人聲如沸搭儒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽淹禾。三九已至,卻和暖如春茴扁,著一層夾襖步出監(jiān)牢的瞬間铃岔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工峭火, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留毁习,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓卖丸,卻偏偏與公主長得像纺且,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子稍浆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容