zoukankan      html  css  js  c++  java
  • 登录接口设计和实现

    ---恢复内容开始---

    1、用户功能设计与设计:

      提供用户注册处理

      提供用户登录处理

      提供路由配置

    2、用户登录接口设计:

      接受用户通过POST 方法提交的登录信息,提交的数据是JSON 格式数据。

      

      从user表中 email 找出匹配的一条记录, 验证密码是否正确

      验证通过说明是合法的用户登录,显示欢迎页面

      验证失败返回错误状态码,4XX

      整个过程都采用AJAX异步过程,用户提交JSON 数据,服务端回去数据后处理,返回JSON  

      URL: /user/login

      METHOD:POST

    3、路由配置:

        

    4、登录代码:   

     1 # 登录业务
     2 def login(request:HttpRequest):
     3     play = simplejson.loads(request.body)
     4     try:
     5         # 一般推荐先有索引的放前面
     6         email = play['email']
     7         user = User.objects.filter(email=email).get()
     8 
     9         # 输入密码 和 数据库中密码对比
    10         if bcrypt.checkpw(play['password'].encode(), user.password.encode()):
    11             # 验证通过
    12             token = gen_token(user.id)
    13             res = JsonResponse({
    14                 'user':{
    15                     "user_id":user.id,
    16                     "name":user.name,
    17                     "email":user.email
    18                 },
    19                 'token':token
    20             })
    21             res.set_cookie('Jwt', token) # set cookie
    22             return res
    23         else:
    24             return HttpResponseBadRequest(status=400)
    25     except Exception as e:
    26         return JsonResponse("输入有误")

      1、将用户信息返回去,浏览器可以使用,处了密码

        2、服务器端通过set_cookie 让客户端强行修改cookie(客户端一般都开启的cookie)

    5、接口认证:

      如何获取浏览器提交的token信息?

      1、使用Header中的Authorization  

        通过这个header增加token信息

        通过header发送数据,方法可以是post , get

      2、自定义header

        JWT来发送token  

        我们选择第二种

       认证:

        基本上所有的业务都需要认证用户的信息

        在这里比较时间戳,如果过期,就直接抛未认证401,客户端收到后就该直接跳转到登录页

        如果没有提交user id,就直接重新登录,如果用户查到了,填充user对象。

         request -》 时间戳比较-》 user id 比较 --》向后执行。

        

        测试: 没有报错,就证明是没有修改过的
        

          提供一个函数,调用业务函数之前,看下,之前是否登陆过

     1 #  只要需要认证的地方都可以加这个功能,是否登陆过
     2 def auth(view_func):
     3     def wrapper(request:HttpRequest):
     4         token = request.META.get('HTTP_JWT', None)
     5         print(token,type(token),'== = = = = ') # str
     6         try:# 获取到 token中的payload,证明是之前登录过的用户
     7             play = jwt.decode(token, KEY, algorithms=['HS256'])
     8             print(play, type(play),'=============')
     9             # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等
    10             user = User.objects.get(pk=play["user_id"])
    11             print(user,'====  = = = = = = == ')
    12             # 如果查到了,接下来的业务处理:
    13             if user:
    14                 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中
    15                 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了
    16             # 如果没查到,user就报错了,所以这块没必要写
    17             # else:
    18             #     return HttpResponseBadRequest()
    19         except Exception as e:
    20             print(e)
    21             return HttpResponseBadRequest('n or p 错误')
    22         ret = view_func(request)
    23         # 这个中间还可以执行去其他的业务。。。。。
    24         return ret
    25     return wrapper
    26 
    27 @auth -----装饰器实现
    28 def show(request:HttpRequest):
    29     # 例如:
    30     print(request.user,'==')
    31     print(type(request.user))
    32     return JsonResponse({'1':7})

        

    ---恢复内容结束---

    1、用户功能设计与设计:

      提供用户注册处理

      提供用户登录处理

      提供路由配置

    2、用户登录接口设计:

      接受用户通过POST 方法提交的登录信息,提交的数据是JSON 格式数据。

      

      从user表中 email 找出匹配的一条记录, 验证密码是否正确

      验证通过说明是合法的用户登录,显示欢迎页面

      验证失败返回错误状态码,4XX

      整个过程都采用AJAX异步过程,用户提交JSON 数据,服务端回去数据后处理,返回JSON  

      URL: /user/login

      METHOD:POST

    3、路由配置:

        

    4、登录代码:   

     1 # 登录业务
     2 def login(request:HttpRequest):
     3     play = simplejson.loads(request.body)
     4     try:
     5         # 一般推荐先有索引的放前面
     6         email = play['email']
     7         user = User.objects.filter(email=email).get()
     8 
     9         # 输入密码 和 数据库中密码对比
    10         if bcrypt.checkpw(play['password'].encode(), user.password.encode()):
    11             # 验证通过
    12             token = gen_token(user.id)
    13             res = JsonResponse({
    14                 'user':{
    15                     "user_id":user.id,
    16                     "name":user.name,
    17                     "email":user.email
    18                 },
    19                 'token':token
    20             })
    21             res.set_cookie('Jwt', token) # set cookie
    22             return res
    23         else:
    24             return HttpResponseBadRequest(status=400)
    25     except Exception as e:
    26         return JsonResponse("输入有误")

      1、将用户信息返回去,浏览器可以使用,处了密码

        2、服务器端通过set_cookie 让客户端强行修改cookie(客户端一般都开启的cookie)

    5、接口认证:

      如何获取浏览器提交的token信息?

      1、使用Header中的Authorization  

        通过这个header增加token信息

        通过header发送数据,方法可以是post , get

      2、自定义header

        JWT来发送token  

        我们选择第二种

       认证:

        基本上所有的业务都需要认证用户的信息

        在这里比较时间戳,如果过期,就直接抛未认证401,客户端收到后就该直接跳转到登录页

        如果没有提交user id,就直接重新登录,如果用户查到了,填充user对象。

         request -》 时间戳比较-》 user id 比较 --》向后执行。

        

        测试: 没有报错,就证明是没有修改过的
        

          提供一个函数,调用业务函数之前,看下,之前是否登陆过

     1 #  只要需要认证的地方都可以加这个功能,是否登陆过
     2 def auth(view_func):
     3     def wrapper(request:HttpRequest):
     4         token = request.META.get('HTTP_JWT', None)
     5         print(token,type(token),'== = = = = ') # str
     6         try:# 获取到 token中的payload,证明是之前登录过的用户
     7             play = jwt.decode(token, KEY, algorithms=['HS256'])
     8             print(play, type(play),'=============')
     9             # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等
    10             user = User.objects.get(pk=play["user_id"])
    11             print(user,'====  = = = = = = == ')
    12             # 如果查到了,接下来的业务处理:
    13             if user:
    14                 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中
    15                 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了
    16             # 如果没查到,user就报错了,所以这块没必要写
    17             # else:
    18             #     return HttpResponseBadRequest()
    19         except Exception as e:
    20             print(e)
    21             return HttpResponseBadRequest('n or p 错误')
    22         ret = view_func(request)
    23         # 这个中间还可以执行去其他的业务。。。。。
    24         return ret
    25     return wrapper
    26 
    27 @auth -----装饰器实现
    28 def show(request:HttpRequest):
    29     # 例如:
    30     print(request.user,'==')
    31     print(type(request.user))
    32     return JsonResponse({'1':7})

        

         Django的认证:

          

           本项目使用了无session的机制,且用户信息自己建表管理,所以认证需要自己实现

    6、中间件技术Midleware      

       官方定义:在Django的request 和response处理过程中,由框架提供的hook钩子

       中间件技术,在1.10之后,发生改变,使用新的定义方式

      参看:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware

       中间件实现方式:有两种

         

         

        自定义的中间件,也要在这里注册:一般写在最后,先用框架自己的中间件。

         

         自己写中间件:https://docs.djangoproject.com/en/1.11/topics/http/middleware/#writing-your-own-middleware

           

           右击中间件名,选择copyreference,添加到settings.py中。     

         但是,这样所有的请求和响应都拦截,我们还得判断是不是访问的想要拦截的view函数,所以,考虑其他的方法。中间件有很多用途,适当的拦截所有请求和响应,例如浏览器端的IP 是否被禁用,UserAgent分析,异常响应的统一处理。

         例如本项目的认证,登录的时候,就不能用中间件,所以不适合注册一个中间件来拦截,而是使用装饰器,需要拦截的就加上此功能。   

      装饰器:

        在需要认证 的view 函数上增加认证功能,写一个装饰器函数,谁需要认证,就在这个view函数上应用这个装饰器

      

     1 AUTH_EXPIRE = 8*60*60 # 8 小时过期,可以卸载settings中,通过from django.conf import settings调用
     2 #  只要需要认证的地方都可以加这个功能,是否登陆过
     3 def auth(view_func):
     4     def wrapper(request:HttpRequest):
     5         token = request.META.get('HTTP_JWT', None)
     6         print(token,type(token),'== = = = = ') # str
     7         try:# 获取到 token中的payload,证明是之前登录过的用户
     8             play = jwt.decode(token, KEY, algorithms=['HS256'])
     9             # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等
    10             # 验证过期时间:
    11             current = datetime.datetime.now().timestamp()
    12             if (current - play.get('timestamp', 0)) > AUTH_EXPIRE:
    13                 return HttpResponse("过期了")
    14 
    15             user = User.objects.get(pk=play["user_id"])
    16             # 如果查到了,接下来的业务处理:
    17             if user:
    18                 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中
    19                 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了
    20             # 如果没查到,user就报错了,所以这块没必要写
    21             # else:
    22             #     return HttpResponseBadRequest()
    23         except Exception as e:
    24             print(e)
    25             return HttpResponseBadRequest('n or p 错误')
    26         ret = view_func(request)
    27         # 这个中间还可以执行去其他的业务。。。。。
    28         return ret
    29     return wrapper
    30 
    31 @auth # 很自由的应用在需要认证的view 函数上。
    32 def show(request:HttpRequest):
    33     # 例如:
    34     print(request.user,'==')
    35     print(type(request.user))
    36     return JsonResponse({'1':7})

         Jwt 过期问题:(过期两种方式:过期的起点时间    和     到期时间)

          pyjwt 支持过期设定,在decode的时候,如果过期,则抛出异常,

          需要在payload中增加  claim exp。exp要求是一个整数int的时间戳。

              

     1 #  只要需要认证的地方都可以加这个功能,是否登陆过
     2 def auth(view_func):
     3     def wrapper(request:HttpRequest):
     4         token = request.META.get('HTTP_JWT', None)
     5         print(token,type(token),'== = = = = ') # str
     6         try:# 获取到 token中的payload,证明是之前登录过的用户
     7             # 认证的同时,验证过期时间:过期或抛异常(可以通过时间判断,块过期的时候,续期,set cookie重新发一次)
     8             play = jwt.decode(token, KEY, algorithms=['HS256'])
     9             # 但是虽然是之前的,但是得确保,这一时刻,数据库中还存在这个用户吗,是否激活状态等
    10 
    11             user = User.objects.get(pk=play["user_id"])
    12             # 如果查到了,接下来的业务处理:
    13             if user:
    14                 #查到,也就是已经登录,要利用这些用户信息,所以要动态注册到request中
    15                 request.user = user # 这样,下面执行show方法的时候,就可以利用这个用户属性了
    16             # 如果没查到,user就报错了,所以这块没必要写
    17             # else:
    18             #     return HttpResponseBadRequest()
    19         except Exception as e:
    20             print(e)
    21             return HttpResponseBadRequest('n or p 错误')
    22         ret = view_func(request)
    23         # 这个中间还可以执行去其他的业务。。。。。
    24         return ret
    25     return wrapper

          测试用的:exp  claim,此代码,可以用于续期,通过判断,快过期,就通过set cookie重新发一个jwt 过去。 

     1 import jwt
     2 import datetime
     3 import threading
     4 
     5 event = threading.Event()
     6 key = 'jerry'
     7 # 在jwt  的payload中增加 exp  claim
     8 data = jwt.encode({'name':'jerry','exp':int(datetime.datetime.now().timestamp() + 3)}, key)
     9 print(jwt.get_unverified_header(data))# 获取没有过期的头
    10 try:
    11     while not event.wait(1):
    12         print(jwt.decode(data, key))
    13         print(datetime.datetime.now().timestamp())
    14 except jwt.ExpiredSignatureError as e:# 过期就抛异常
    15     print(e)
    16     
    17 print(jwt.get_unverified_header(data))

       

  • 相关阅读:
    Leetcode:Convert Sorted List to Binary Search Tree
    Leetcode:Unique Binary Search Trees & Unique Binary Search Trees II
    Leetcode::Longest Common Prefix && Search for a Range
    Leetcode::Flatten Binary Tree to Linked List
    Leetcode::JumpGame
    leetcode power(x,n)
    Leetcode Letter Combinations of a Phone Number
    leetcode Reverse Nodes in k-Group
    leetcode Merge k Sorted Lists
    word ladder
  • 原文地址:https://www.cnblogs.com/JerryZao/p/10021967.html
Copyright © 2011-2022 走看看