转载请著名出处:https://blog.csdn.net/qq_32506429/article/details/89641123
初学Python Web,环境是python3 +Django2,然后Web想做简单的用户token验证,验证通过才能进行其他操作;在网上找了好久,先学了装饰器,才看懂很多教程,但是没有直接上代码的,对伸手党的我很不友好(>.<羞耻...),所以研究了一天后决定写一篇博客,好了不废话,上干货。
第一步:引入pyjwt:
pip3 install pyjwt
第二步:在models里建立自己的用户类 Member
from django.db import models from DjangoUeditor.models import UEditorField import jwt from InterviewQA import settings import datetime class Member(models.Model): username = models.CharField(max_length=11, verbose_name='用户名') password = models.CharField(max_length=48, verbose_name='密码') create_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间') phone = models.CharField(max_length=11, verbose_name='手机号') account_type_choice = ((1, "普通会员"), (2, "高级会员"), (3, "企业普通会员"), (4, "企业高级会员")) account_type = models.IntegerField(choices=account_type_choice, default=1, verbose_name='账号类型') age = models.IntegerField(default=0, verbose_name='年龄') birthday = models.DateField(verbose_name='生日', auto_now=True, blank=True) update_time = models.DateTimeField(auto_now=True, verbose_name='修改时间', blank=True, null=True) #real_name = models.OneToOneField("RealName", on_delete=models.SET_NULL, null=True, blank=True) nick_name = models.CharField(max_length=24, verbose_name='昵称', default="新用户") login_time = models.DateTimeField(verbose_name='登录时间', auto_now=True, blank=True) last_login_time = models.DateTimeField(verbose_name='上次登录时间', auto_now=False, blank=True, default=datetime.datetime.utcnow()) vip_start_time = models.DateTimeField(verbose_name='会员开始时间', auto_now=True, blank=True) vip_end_time = models.DateTimeField(verbose_name='会员结束时间', auto_now=True, blank=True) account_status_choice = ((1, "正常"), (2, "冻结"), (3, "删除")) account_status = models.IntegerField(choices=account_status_choice, default=1, verbose_name='账户状态') email = models.EmailField(verbose_name='邮箱', blank=True) QQ = models.CharField(max_length=24, verbose_name='QQ', blank=True) WeChart = models.CharField(max_length=32, verbose_name='微信', blank=True) sign = models.CharField(max_length=32, verbose_name='签名', blank=True) balance = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='余额', blank=True, default=0.00) integral = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='积分', blank=True, default=0.00) head = models.ImageField(upload_to="head", default='head/7d9d46ae3c9edc877151647bf9c6560020190422165247_90.jpg', verbose_name='头像', null=True, blank=True) exp_time = models.DateTimeField(verbose_name='Token过期时间', auto_now=False, blank=True, default=datetime.datetime.utcnow() + datetime.timedelta(days=1)) def __str__(self): return self.nick_name @property def token(self): return self._generate_jwt_token() def _generate_jwt_token(self): exp = datetime.datetime.utcnow() + datetime.timedelta(days=1) token = jwt.encode({ 'exp': exp, 'iat': datetime.datetime.utcnow(), 'data': { 'username': self.username } }, settings.SECRET_KEY, algorithm='HS256') lt = self.login_time nt = datetime.datetime.utcnow() # print("exp=", exp) self.exp_time = exp self.last_login_time = lt self.login_time = nt self.save() return token.decode('utf-8') class Meta: verbose_name = '用户' verbose_name_plural = '用户'
第三步:创建验证token的装饰器
from django.conf import settings from django.http import JsonResponse from django.core.exceptions import PermissionDenied import jwt # 引入自己建的数据库model类 from app.models import Member def auth_permission_required(perm): def decorator(view_func): def _wrapped_view(request, *args, **kwargs): # 格式化权限 perms = (perm,) if isinstance(perm, str) else perm if request.user.is_authenticated: # 正常登录用户判断是否有权限 if not request.user.has_perms(perms): raise PermissionDenied else: try: auth = request.META.get('HTTP_AUTHORIZATION').split() except AttributeError: return JsonResponse({'status': 0, 'err': '缺少参数Token'}) # return JsonResponse({"code": 401, "message": "No authenticate header"}) # 用户通过API获取数据验证流程 if auth[0].lower() == 'token': try: dict = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256']) username = dict.get('data').get('username') except jwt.ExpiredSignatureError: return JsonResponse({'status': 0, 'err': 'Token已过期'}) # return JsonResponse({"status_code": 401, "message": "Token expired"}) except jwt.InvalidTokenError: return JsonResponse({'status': 0, 'err': '无效的Token'}) except Exception as e: return JsonResponse({'status': 0, 'err': '获取用户失败'}) try: user = Member.objects.get(username=username) except Member.DoesNotExist: return JsonResponse({'status': 0, 'err': "用户不存在"}) if user.account_status != 1: return JsonResponse({'status': 0, 'err': "账户异常"}) # # Token登录的用户判断是否有权限 # if not user.has_perms(perms): # return JsonResponse({'status': 0, 'err': "未授权用户,被拒绝访问"}) else: return JsonResponse({'status': 0, 'err': "不支持身份验证类型"}) return view_func(request, *args, **kwargs) return _wrapped_view return decorator def get_user(req): auth = req.META.get('HTTP_AUTHORIZATION').split() dict = jwt.decode(auth[1], settings.SECRET_KEY, algorithms=['HS256']) username = dict.get('data').get('username') try: user = Member.objects.get(username=username) except Member.DoesNotExist: return JsonResponse({'status': 0, 'err': "用户不存在"}) return user
第四步:登录获取token
from app.models import Member
#登录 def login(req): res = {'status': 1, 'err': '', 'data': {'is_success': False, "token": "", 'last_login_time': '', 'login_time': '', 'exp_time': ''}} if req.method == 'POST': phone = req.POST.get("phone") pwd = req.POST.get("password") print(phone, pwd) if not phone: res["err"] = "请输入手机号" return json_response(res) if not pwd: res["err"] = "请输入密码" return json_response(res) try: user = Member.objects.get(username=phone) except Member.DoesNotExist: res["err"] = "用户不存在" return json_response(res) if user: if user.account_status == 1: print(user.nick_name) p = sha1_encode(pwd) if p != user.password: res["err"] = "用户名密码错误" return json_response(res) else: res["msg"] = "登录成功" res["data"]["is_success"] = True #调用user.token会创建token res["data"]["token"] = user.token res["data"]["last_login_time"] = user.last_login_time res["data"]["login_time"] = user.login_time res["data"]["exp_time"] = user.exp_time return json_response(res) res["err"] = "用户不存在" return json_response(res) else: res["err"] = "用户不存在" return json_response(res) else: res["err"] = "请求方式错误" return json_response(res)
第五步:用token获取用户信息、通过token修改用户信息等等
from app.decorator.UserAuth import auth_permission_required, get_user from app.models import Member
# token验证装饰器 @auth_permission_required('account.select_user') def info(req): res = {'status': 1, 'err': '', 'data': {}} if req.method == 'GET': user = get_user(req) res['data']["username"] = user.username res['data']["phone"] = user.phone res['data']["account_type"] = user.account_type res['data']["age"] = user.age res['data']["birthday"] = user.birthday res['data']["real_name"] = user.real_name res['data']["nick_name"] = user.nick_name res['data']["account_status"] = user.account_status res['data']["email"] = user.email res['data']["QQ"] = user.QQ res['data']["WeChart"] = user.WeChart res['data']["sign"] = user.sign res['data']["balance"] = user.balance res['data']["integral"] = user.integral res['data']["head"] = settings.HTTP_PORT + user.head.url return json_response(res) res["err"] = "请求方式错误" return json_response(res)
# token验证装饰器 @auth_permission_required('account.change_user') def update(req): res = {'status': 1, 'err': '', 'data': {'is_success': False}} if req.method == 'POST': nick_name = req.POST.get("nickname") phone = req.POST.get("phone") head = req.POST.get("head") QQ = req.POST.get("QQ") email = req.POST.get("email") WeChart = req.POST.get("WeChart") sign = req.POST.get("sign") birthday = req.POST.get("birthday") user = get_user(req) try: with transaction.atomic(): if phone: user.username = phone user.phone = phone if nick_name: user.nick_name = nick_name if head: user.head = head if QQ: user.QQ = QQ if email: user.email = email if WeChart: user.WeChart = WeChart if sign: user.sign = sign if birthday: user.birthday = birthday user.update_time = datetime.datetime.utcnow() user.save() res["msg"] = "修改成功" res["data"]["is_success"] = True return json_response(res) except Exception as e: print(e) res["err"] = "修改失败" return json_response(res) else: res["err"] = "请求方式错误" return json_response(res)
登录:
![](https://i-blog.csdnimg.cn/blog_migrate/8944209f2e75690c1dfad7bc0de772d5.png)
获取用户信息:header里添加Authorization 值为"Token 登录时返回的token" ;"Token"后有个空格;
用token修改用户信息:
修改前:
修改后: