一、Cookie Session Token介绍

1)Cookie介绍

cookie 是一个非常具体的东西 指的就是浏览器里面能永久存储的一种数据 仅仅是浏览器实现的一种数据存储功能

  • cookie由服务器生成,发送给浏览器,浏览器把cookie以kv形式保存到某个目录下的文本文件内,下一次请求同一网站时会把该cookie发送给服务器。由于cookie是存在客户端上的,所以浏览器加入了一些限制确保cookie不会被恶意使用,同时不会占据太多磁盘空间,所以每个域的cookie数量是有限的。

2)Session介绍

session 从字面上讲,就是会话。这个就类似于你和一个人交谈,你怎么知道当前和你交谈的是张三而不是李四呢?对方肯定有某种特征(长相等)表明他就是张三。

  • session 也是类似的道理,服务器要知道当前发请求给自己的是谁。为了做这种区分,服务器就要给每个客户端分配不同的“身份标识”,然后客户端每次向服务器发请求的时候,都带上这个“身份标识”,服务器就知道这个请求来自于谁了。至于客户端怎么保存这个“身份标识”,可以有很多种方式,对于浏览器客户端,大家都默认采用 cookie 的方式。

    服务器使用session把用户的信息临时保存在了服务器上,用户离开网站后session会被销毁。这种用户信息存储方式相对cookie来说更安全,可是session有一个缺陷:如果web服务器做了负载均衡,那么下一个操作请求到了另一台服务器的时候session会丢失。

3)Cookie和Session的区别

session是存储服务器端,cookie是存储在客户端,所以session的安全性比cookie高

  • 获取session里的信息是通过存放在会话cookie里的session id获取的。而session是存放在服务器的内存中里,所以session里的数据不断增加会造成服务器的负担,所以会把很重要的信息存储在session中,而把一些次要东西存储在客户端的cookie里。

session的信息是通过sessionid获取的,而sessionid是存放在会话cookie中

  • 当浏览器关闭的时候会话cookie消失,所以sessionid也就消失了,但是session的信息还存在服务器端,只是查不到所谓的session,但它并不是不存在

4)Token介绍

无状态、可扩展

  • 在客户端存储的 token 是无状态的,并且能够被扩展。基于这种无状态和不存储Session信息,负载均衡服务器 能够将用户的请求传递到任何一台服务器上,因为服务器与用户信息没有关联。相反在传统方式中,我们必须将请求发送到一台存储了该用户 session 的服务器上(称为Session亲和性),因此当用户量大时,可能会造成 一些拥堵。使用 token 完美解决了此问题。
  • 请求中发送 token 而不是 cookie,这能够防止 CSRF(跨站请求伪造) 攻击。即使在客户端使用 cookie 存储 token,cookie 也仅仅是一个存储机制而不是用于认证。另外,由于没有 session,让我们少我们不必再进行基于 session 的操作。

    Token 是有时效的,一段时间之后用户需要重新验证。我们也不一定需要等到token自动失效,token有撤回的操作,通过 token revocataion可以使一个特定的 token 或是一组有相同认证的 token 无效。

  • 使用 Tokens 能够与其它应用共享权限。例如,能将一个博客帐号和自己的QQ号关联起来。当通过一个 第三方平台登录QQ时,我们可以将一个博客发到QQ平台中。

    使用 token,可以给第三方应用程序提供自定义的权限限制。当用户想让一个第三方应用程序访问它们的数据时,我们可以通过建立自己的API,给出具有特殊权限的tokens。

多平台与跨域

  • 我们已经讨论了CORS (跨域资源共享)。当我们的应用和服务不断扩大的时候,我们可能需要通过多种不同平台或其他应用来接入我们的服务。

    可以让我们的API只提供数据,我们也可以从CDN提供服务(Having our API just serve data, we can also make the design choice to serve assets from a CDN.)。 在为我们的应用程序做了如下简单的配置之后,就可以消除 CORS 带来的问题。只要用户有一个通过了验证的token,数据和资源就能够在任何域上被请求到。

Access-Control-Allow-Origin: *   
  • 有几种不同方式来创建 token。最常用的标准就是 JSON Web Tokens。很多语言都支持它

以上Cookie与Session和Token介绍借鉴于:(Cookie与Session介绍博主之前文章介绍过)
https://www.cnblogs.com/liuqingzheng/p/8990027.html

二、JWT介绍

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token(本质就是token)认证机制。

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT的构成
jwt就是一段字符串 由三段信息构成 将这三段信息用.链接起来构成jwt字符串
第一部分我们称为头部Header 第二部分称为荷载Payload 第三部分是签证Signature

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

header

  • jwt的头部承载两部分信息(类型是jwt 机密的算法通常使用HMAC SHA256)
'type':'jwt' 'alg': HS256,
  • 然后讲头部进行加密(该加密是可以对称解密的) 构成了第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

Payload
载荷就是存放有效信息的地方 这个名字像是特指飞机上承载的货品 这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

定义一个Payload

"sub": "1234567890", "name": "John Doe", "admin": true

然后将其进行base64加密,得到JWT的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

Signature
JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了 关于签发和核验JWT,我们可以使用Django REST framework JWT扩展来完成。

三、Base64编码与解码

首先Base64是python内置的模块 base64可以把字符串编码成base64的编码格式(大小写字母 包括数据与=号)

eyJOYW1lIjogIkxpa2UiLCAiVXNlcklEIjogODgsICJhZ2UiOiAyMH0=

base64可以把base64编码的网络传输的字符串、图片解码回原来的格式

使用Base64编码

import json
import base64
L = {'Name': 'Like', 'UserID': 88, 'age': 20}
userinfo = json.dumps(L)
print(userinfo)     # {"Name": "Like", "UserID": 88, "age": 20}
res = base64.b64encode(userinfo.encode('utf-8'))
print(res)      # eyJOYW1lIjogIkxpa2UiLCAiVXNlcklEIjogODgsICJhZ2UiOiAyMH0=
res1 = base64.b64decode(res)
print(res1)		# {"Name": "Like", "UserID": 88, "age": 20}

使用Base64解码

img = 'iVBORw0KGgoAAAANSUhEUgAAAMcAAADHC=='		# 经过base64编码的图片
code = base64.b64decode(img)		# 进行解码
with open('code.png', 'wb')as f:	# wb模式新建写入
    f.write(code)

四、JWT快速使用

JWT主要用于签发登录接口需要配合认证类 JWT目前有两种 Jtw&Simplejwt(jwt比较老了 simple现在比较流行)

安装jwt

pip install djangorestframework-jwt

快速使用jwt签发

  • 1.创建一个新项目 直接迁移表 因为它默认使用auth的User表签发Token
  • 2.创建超级用户createsuperuser(右侧的auth_user表中需要有记录)
  • 3.不需要写任何接口 如果使用的auth_user表作为用户表 它可以快速签发
  • 4.签发登录: 只需要在路由中配置(因为它帮我们写好了登录接口)
from rest_framework_jwt.views import obtain_jwt_token
	urlpatterns = [
		path('login/', obtain_jwt_token),

这个时候直接访问即可 它都帮我们写好了 请求体中带入超级用户的账号密码就会返回Token了

"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imxpa2UiLCJleHAiO......."

但是目前只有签发的功能 即然都我们写了登录 肯定也有权限功能 随便写一个视图类 给它加上认证

from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
class JwtView(APIView):
    authentication_classes = [JSONWebTokenAuthentication, ]     # 登录认证
    permission_classes = [IsAuthenticated, ]                    # 权限认证
    def get(self, request):
        return Response('JWT认证啦!!!')
		这个时候直接访问我们的接口 会发生报错 	"detail": "身份认证信息未提供。"
		因为我们访问的时候需要带上Jwt的Token
		固定格式:Authorization: jwt < 注意这里有一个空格 后面填写签发过后的Token
		Authorization:[jwt eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLC]

五、JWT处理返回格式

目前我们写完了基于auth_user表完成签发登录 但是它返回的格式太固定了只有Token 但是我们想自定义格式呢?

ex:	{code:100, msg:'登录成功', user:'like', token:JustYourSelf}

去response返回值中查看源码发现是返回数据的是jwt_response_payload_handler函数 所以我们重写它就好了

from rest_framework_jwt.utils import jwt_response_payload_handler
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'code': 100,
        'msg': '登录成功',
        'username': user.username,
        'token': token
import datetime
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1), # 过期时间一天
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.response.jwt_response_payload_handler',

这个时候朝我们登录接口发送登录请求就会返回我们自定义的信息了

"code": 100, "msg": "登录成功", "username": "like", "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6Imxpa2UiLCJleHA"

六、自定义User表 签发Token

上面我们都是基于auth_user表去做签发认证的 但是我们日常基本程序都是用自己定义的表来做认证的 所以我们该怎么做呢?

创建User表模型
	class UserInfo(models.Model):
		username = models.CharField(max_length=32)
		password = models.CharField(max_length=32)
写一个登录接口
	from rest_framework.exceptions import APIException
	from rest_framework_jwt.settings import api_settings
	from .models import UserInfo
	jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
	jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
	class UserView(APIView):
	    def post(self, request):
	        try:
	            username = request.data.get('username')
	            password = request.data.get('password')
	            user = UserInfo.objects.get(username=username, password=password)
	            payload = jwt_payload_handler(user)     # 根据User 签发token > 头部,荷载,签名
	            token = jwt_encode_handler(payload)     # 使用DjangoRestWork-jwt模块提供的签发token的函数,生成token
	            return Response({'code': 100, 'msg': '登录成功', 'token': token})
	        except Exception as e:
	            raise APIException('用户名或密码错误')
	urlpatterns = [
    	path('authlogin/', views.UserView.as_view()),
 

技术小白记录学习过程,有错误或不解的地方请指出,如果这篇文章对你有所帮助请点点赞收藏+关注谢谢支持 !!!

在前后端分离开发时为什么需要用户认证呢?原因是由于HTTP是无状态的协议,当我们通过帐号密码验证一个用户时,下一个request请求时就把刚刚的用户忘了。于是我们就无法确认该用户的情况,就要再验证一次。所以为了保证系统安全,我们就需要验证用户否处于登录状态。 前后端分离通过Restful API进行数据交互时,如何验证用户的登录信息及权限。在原来的项目中,使用的是最传统也是最简单的... 目前绝大多数的系统都少不了登录验证的功能,这主要是为了保存用户的状态,以此来限制用户的各种行为,从而方便有效的控制用户的权限。比如一个用户登录微博、发布、关注、评论等操作都应是在登录后的用户状态下进行的。实现验证登录的功能主要有两种方式,这一节我们将先对的工作原理做详细的介绍。 1.在users模块创建utils.py,通过这个方法验证是否为正确的用户 from django.contrib.auth.backends import ModelBackend import re from . import models class UserPhoneEmail(ModelBackend): 当前的类是用来定义自定义的认证方法 目录一:web开发模式1.1 前后端不分离1.2 前后端分离二:API接口三:接口测试工具:Postman四:RESTful API规范restful十条规范1 数据的安全保障2 接口特征现3 多数据版本共存4 (重点)数据即是资源,均使用名词(可复数)5 (重点)资源操作由请求方式决定(method)过滤,通过在url上传参的形式传递搜索条件7 响应状态码7.1 正常响应7.2 重定向响应7.3 客户端异常7.4 服务器异常8 错误处理,应返回错误信息,error当做key9 返回结果,针对不同操作,服 Django REST framework是基于Django的一套扩展,可以快速方便写出RESTful API。DRF给我提供了 序列化、请求和响应、@apiview装饰器、类视图、认证和权限、jwt(扩展)认证、版本、分页、控制频率、解析器、视图集、路由器、文档(扩展)等等功能,建议有Django基础的人学习。 如果我们使用drf框架状态保持使用的是session的话,而不是jwt,那么我们的后台肯定要保存数据,用于对比验证,这样保存到那里就成了问题, 保存到mysql中,这是框架默认的存储地址,在setting中可以不用设置,但是这种当用户少的时候是没问题的,但是用户量很大的时候,服务器开销就会很大,影响性能 保存到缓存中redis中,这样的话查询速度就会很快,但是我们都知道redis数据一旦存储满的话,就会实行删除策略,这样会丢失一部分数据,导致用户状态无法保持,所以最好的办法就是 数据库-缓存 并用,两者. cookie,session,tokenjwt原理介绍base64编码解码drf修改返回格式自定义user签发token 12.6 http.cookies: HTTP cookie http.cookies模块为大多数符合RFC 2109的cookie实现一个解析器。这个实现没有标准那么严格,因为MSIE 3.0x不支持完整的标准。 12.6.1 创建和设置cookie 可以用cookie为基于浏览器的应用实现状态管理,因此,cookie通常由服务器设置,并由客户存储和返回。下面给出一个最简单的例子,创建一个coo...