登录接口设计和实现

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

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))

   

原文地址:https://www.cnblogs.com/JerryZao/p/10021967.html