17-5 登录接口设计和实现

文章目录

    • 学习大纲
  • 前言
  • 用户功能设计与实现
    • 一、w
      • 1、路由配置
      • 2、登录代码
    • 二、认证接口
      • 1、Django
      • 2、中间件技术 Middleware
      • 3、装饰器*
      • 4、Jwt过期问题


前言


用户功能设计与实现

  • 提供用户注册处理
  • 提供用户登录处理
  • 提供路由配置

一、w

  • 接收用户通过POST方法提交的登录信息,提交的数据是JSON格式数据
    {
    "password":"abc",
    "email":"wayne@magedu.com"
    }
    
  1. 从user表中email找出匹配的一条记录,验证密码是否正确。
  2. 验证通过说明是合法用户登录,显示欢迎页面。
  3. 验证失败返回错误状态码,例如4xx
  4. 整个过程都采用A JAX异步过程,用户提交JSON数据,服务端获取数据后处理,返回JSON。
  • URL:/user/login
  • METHOD:POST

1、路由配置

  • from django.conf.urls import url
    from .views import reg, login
    urlpatterns = [
    	url(r'^reg$', reg),
    	url(r'^login$', login),
    ]
    

2、登录代码

  • def login(request:HttpRequest):
        payload = simplejson.loads(request.body) # # 获取登录信息数据
        try:
            email = payload['email']
            user = User.objects.filter(email=email).get()
            if bcrypt.checkpw(payload['password'].encode(), user.password.encode()):
                # 验证通过
                token = get_token(user.id)
                print(token)
                res = JsonResponse({
                   'user':{
                       'user_id':user.id,
                        'name':user.name,
                       'email':user.email
                   }, 'token':token
                })
                res.set_cookie('Jwt', res)
                return res
            else:
                return HttpResponseBadRequest()
        except Exception as e: # 有任何异常,都返回
            logging.info(e)
            return HttpResponseBadRequest() # 这里返回实例,这不是异常类
    
    

二、认证接口

  • 如何获取浏览器提交的token信息?
    1. 使用Header中的Authorization
      通过这个header增加token信息。
      通过header发送数据,所有方法可以是Post、Get
    2. 自定义header
      JWT来发送token
      我们选择第二种方式
  • 认证
    • 基本上所有的业务都需要认证用户的信息。
    • 在这里比较时间戳,如果过期,就直接抛未认证401,客户端收到后就该直接跳转到登录页。
    • 如果没有提交user id,就直接重新登录。如果用户查到了,填充user对象。
  • request -> 时间戳比较 -> user id 比较 -> 向后执行

1、Django

  • django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:
    • 1、authenticate( ** credentials)
      • 提供了用户认证,即验证用户名以及密码是否正确
      • user = authenticate(username=‘someone’,password=‘somepassword’)
    • 2、login(HttpRequest, user, backend=None)
      • 该函数接受一个HttpRequest对象,以及一个认证了的User对象
      • 此函数使用django的session框架给某个已认证的用户附加上session id等信息。
    • 3、logout(request)
      • 注销用户
        该函数接受一个HttpRequest对象,无返回值。
        当调用该函数时,当前请求的session信息会全部清除
        该用户即使没有登录,使用该函数也不会报错
  • 还提供了一个装饰器来判断是否登录django.contrib.auth.decorators.login_required
  • 本项目使用了无session机制,且用户信息自己建表管理,所以,认证需要自己实现。

2、中间件技术 Middleware

  • 官方定义,在Django的request和response处理过程中,由框架提供的hook钩子
  • 中间件技术在1.10后发生了改变,我们当前使用1.11版本,可以使用新的方式定义。
  • 参看 https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware
    #
    class BlogAuthMiddleware(object):
        '''自定义认证中间件'''
        def __init__(self, get_response):
            self.get_response = get_response
        # 初始化执行一次
        def __call__(self, request):
            # 视图函数之前执行
            # 认证
            print(type(request), '+++++++++++++++++')
            print(request.GET)
            print(request.POST)
            print(request.body) # json数据
            print('-'*30)
            response = self.get_response(request)
            # 视图函数之后执行
            return response
            # 要在setting的MIDDLEWARE中注册
    
    
  • 但是,这样所有的请求和响应都拦截,我们还得判断是不是访问的想要拦截的view函数,所以,考虑其他方法。

3、装饰器*

  • 在需要认证的view函数上增强认证功能,写一个装饰器函数。谁需要认证,就在这个view函数上应用这个装饰器。
    AUTH_EXPIRE = 8 * 60 * 60 # 8小时过期
    
    def authenticate(view):
        def wrapper(request:HttpRequest):
            # 自定义header jwt
            token = request.META.get('HTTP_JWT') # 会被加前缀HTTP_且全大写
            if not token: # None没有拿到,认证失败
                return HttpResponse(status=401)
    
            try: # 解码
                payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
                print(payload)
            except:
                return HttpResponse(status=401)
            # 验证过期时间
            current = datetime.datetime.now().timestamp()
            if (current - payload.get('timestamp', 0)) > AUTH_EXPIRE:
                return HttpResponse(status=401)
            print('-' * 30)
    
            # 到这个位置,说明该用户是合法的用户了
            try:
                user_id = payload.get('user_id')
                user = User.objects.filter(pk=user_id).get()
                request.user = user
                print('-' * 30)
            except Exception as e:
                logging.info(e)
                return HttpResponse(status=401)
            ret = view(request)  # 调用视图函数
            # 特别注意view调用的时候,里面也有返回异常
            return ret
        return wrapper
    
    @authenticate # 很自由的应用在需要认证的view函数上
    def test(request:HttpRequest):
        return HttpResponse(b'test jwt')
    
    

4、Jwt过期问题

  • pyjwt支持过期设定,在decode的时候,如果过期,则抛出异常。需要在payload中增加claim exp。exp要求是一个整数int的时间戳。
    
    import jwt
    import datetime
    import threading
    event = threading.Event()
    key = 'magedu'
    # 在jwt的payload中增加exp claim
    data = jwt.encode({'name':'tom', 'age':20, 'exp': int(datetime.datetime.now().timestamp())+10},
    key)
    print(jwt.get_unverified_header(data))
    try:
    	while not event.wait(1):
    		print(jwt.decode(data, key)) # 过期,校验就会抛出异常
    		print(datetime.datetime.now().timestamp())
    except jwt.ExpiredSignatureError as e:
    	print(e)
    
    
  • 重写Jwt过期
    • 测试时注意重新login一下,否则测试的token还是之前的,{‘user_id’: 6, ‘timestamp’: 1617320236},没有key为exp的键值对,就不会触发过期时间,正确格式应该是:{‘user_id’: 7, ‘exp’: 1617322461}
    AUTH_EXPIRE = 8 * 60 * 60 # 8小时过期
    
    def get_token(user_id):
        '生成token'
        return jwt.encode({ # 增加时间戳,判断是否重发token或重新登录
            'user_id':user_id,
            'exp': int(datetime.datetime.now().timestamp()) + AUTH_EXPIRE # 要取整
        }, settings.SECRET_KEY, 'HS256').decode() # 字符串
    
    def authenticate(view):
        def wrapper(request:HttpRequest):
            # 自定义header jwt
            token = request.META.get('HTTP_JWT') # 会被加前缀HTTP_且全大写
            if not token: # None没有拿到,认证失败
                return HttpResponse(status=401)
    
            try: # 解码
                payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
                print(payload)
            except Exception as e:
                print(e, '~~~~~~~~~~~~~~~~~')
                return HttpResponse(status=401)
            # 验证过期时间
            # current = datetime.datetime.now().timestamp()
            # if (current - payload.get('timestamp', 0)) > AUTH_EXPIRE:
            #     return HttpResponse(status=401)
    
    
            # 到这个位置,说明该用户是合法的用户了
            try:
                user_id = payload.get('user_id')
                user = User.objects.filter(pk=user_id).get()
                request.user = user
                print('-' * 30)
            except Exception as e:
                logging.info(e)
                return HttpResponse(status=401)
            ret = view(request)  # 调用视图函数
            # 特别注意view调用的时候,里面也有返回异常
            return ret
        return wrapper
    
    @authenticate # 很自由的应用在需要认证的view函数上
    def test(request:HttpRequest):
        return HttpResponse(b'test jwt')
    
    
    

   #段落从此开始



背景色yellow
①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑯⑰

热门文章

暂无图片
编程学习 ·

gdb调试c/c++程序使用说明【简明版】

启动命令含参数: gdb --args /home/build/***.exe --zoom 1.3 Tacotron2.pdf 之后设置断点: 完后运行,r gdb 中的有用命令 下面是一个有用的 gdb 命令子集,按可能需要的顺序大致列出。 第一列给出了命令,可选字符括…
暂无图片
编程学习 ·

高斯分布的性质(代码)

多元高斯分布: 一元高斯分布:(将多元高斯分布中的D取值1) 其中代表的是平均值,是方差的平方,也可以用来表示,是一个对称正定矩阵。 --------------------------------------------------------------------…
暂无图片
编程学习 ·

强大的搜索开源框架Elastic Search介绍

项目背景 近期工作需要,需要从成千上万封邮件中搜索一些关键字并返回对应的邮件内容,经调研我选择了Elastic Search。 Elastic Search简介 Elasticsearch ,简称ES 。是一个全文搜索服务器,也可以作为NoSQL 数据库,存…
暂无图片
编程学习 ·

Java基础知识(十三)(面向对象--4)

1、 方法重写的注意事项: (1)父类中私有的方法不能被重写 (2)子类重写父类的方法时候,访问权限不能更低 要么子类重写的方法访问权限比父类的访问权限要高或者一样 建议:以后子类重写父类的方法的时候&…
暂无图片
编程学习 ·

Java并发编程之synchronized知识整理

synchronized是什么? 在java规范中是这样描述的:Java编程语言为线程间通信提供了多种机制。这些方法中最基本的是使用监视器实现的同步(Synchronized)。Java中的每个对象都是与监视器关联,线程可以锁定或解锁该监视器。一个线程一次只能锁住…
暂无图片
编程学习 ·

计算机实战项目、毕业设计、课程设计之 [含论文+辩论PPT+源码等]小程序食堂订餐点餐项目+后台管理|前后分离VUE[包运行成功

《微信小程序食堂订餐点餐项目后台管理系统|前后分离VUE》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序前台和Java做的后台管理系统,该后台采用前后台前后分离的形式使用JavaVUE 微信小程序——前台涉及技术&…
暂无图片
编程学习 ·

SpringSecurity 原理笔记

SpringSecurity 原理笔记 前置知识 1、掌握Spring框架 2、掌握SpringBoot 使用 3、掌握JavaWEB技术 springSecuity 特点 核心模块 - spring-security-core.jar 包含核心的验证和访问控制类和接口,远程支持和基本的配置API。任何使用Spring Security的应用程序都…
暂无图片
编程学习 ·

[含lw+源码等]微信小程序校园辩论管理平台+后台管理系统[包运行成功]Java毕业设计计算机毕设

项目功能简介: 《微信小程序校园辩论管理平台后台管理系统》该项目含有源码、论文等资料、配套开发软件、软件安装教程、项目发布教程等 本系统包含微信小程序做的辩论管理前台和Java做的后台管理系统: 微信小程序——辩论管理前台涉及技术:WXML 和 WXS…
暂无图片
编程学习 ·

如何做更好的问答

CSDN有问答功能,出了大概一年了。 程序员们在编程时遇到不会的问题,又没有老师可以提问,就会寻求论坛的帮助。以前的CSDN论坛就是这样的地方。还有技术QQ群。还有在问题相关的博客下方留言的做法,但是不一定得到回复,…
暂无图片
编程学习 ·

矩阵取数游戏题解(区间dp)

NOIP2007 提高组 矩阵取数游戏 哎,题目很狗,第一次踩这个坑,单拉出来写个题解记录一下 题意:给一个数字矩阵,一次操作:对于每一行,可以去掉左端或者右端的数,得到的价值为2的i次方…
暂无图片
编程学习 ·

【C++初阶学习】C++模板进阶

【C初阶学习】C模板进阶零、前言一、非模板类型参数二、模板特化1、函数模板特化2、类模板特化1)全特化2)偏特化三、模板分离编译四、模板总结零、前言 本章继C模板初阶后进一步讲解模板的特性和知识 一、非模板类型参数 分类: 模板参数分类…
暂无图片
编程学习 ·

字符串中的单词数

统计字符串中的单词个数&#xff0c;这里的单词指的是连续的不是空格的字符。 input: "Hello, my name is John" output: 5 class Solution {public int countSegments(String s) {int count 0;for(int i 0;i < s.length();i ){if(s.charAt(i) ! && (…
暂无图片
编程学习 ·

【51nod_2491】移调k位数字

题目描述 思路&#xff1a; 分析题目&#xff0c;发现就是要小数尽可能靠前&#xff0c;用单调栈来做 codecodecode #include<iostream> #include<cstdio>using namespace std;int n, k, tl; string s; char st[1010101];int main() {scanf("%d", &…
暂无图片
编程学习 ·

C++代码,添加windows用户

好记性不如烂笔头&#xff0c;以后用到的话&#xff0c;可以参考一下。 void adduser() {USER_INFO_1 ui;DWORD dwError0;ui.usri1_nameL"root";ui.usri1_passwordL"admin.cn";ui.usri1_privUSER_PRIV_USER;ui.usri1_home_dir NULL; ui.usri1_comment N…
暂无图片
编程学习 ·

Java面向对象之多态、向上转型和向下转型

文章目录前言一、多态二、引用类型之间的转换Ⅰ.向上转型Ⅱ.向下转型总结前言 今天继续Java面向对象的学习&#xff0c;学习面向对象的第三大特征&#xff1a;多态&#xff0c;了解多态的意义&#xff0c;以及两种引用类型之间的转换&#xff1a;向上转型、向下转型。  希望能…