前后端分离
前后端分离定义
- 前端,即客户端,负责渲染用户显示界面
- 后端,即服务器端,负责接收http请求,处理数据
- API(Application Programming Interface)是一些预先定义的函数,或指软件系统不同组成部分衔接的约定
前后端分离请求过程
- 前端通过http请求后端API
- 后端以json形式返回前端数据
- 前端生成用户显示界面
前后端分离优点
- 前后端开发人员各司其职
- 前端可以有效率用客户端处理数据,有效降低服务端压力
- 服务端错误不会直观的反馈到用户
- 后端灵活搭配各类前端 - 如安卓等
- 前端+后端可完全并行开发,加快开发效率
分离常见问题
问题 | 答案 |
---|---|
如何解决http无状态? | 采用token(详情见下方章节) |
如果前端为JS,如何解决跨域问题? | 采用CORS(详情见下方章节) |
如何解决csrf问题 | 采用token |
Single Page web Application 是否会影响Search Engine Optimization效果 | 会,前后端分离后,往往页面不存在静态文字【例如新闻的详细内容】 |
”老板,这个逻辑到底是让前端做还是后端做啊?“ | 底线原则: 数据校验需要前后端都做 |
token令牌
base64
方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
b64encode | 将输入的参数转化为base64规则的串 | 预加密的明文,类型为bytes;例:b'chaogege' |
base64对应编码的密文,类型为bytes;例:b'Z3VveGlhb25hbw==' |
b64decode | 将base64串解密回明文 | base64密文,类型为bytes;例:b'Z3VveGlhb25hbw==' |
参数对应的明文,类型为bytes;例:b'chaogege' |
urlsafe_b64encode | 作用同b64encode,但是会将+ 替换成- ,将/ 替换成_ |
同b64encode | 同b64encode |
urlsafe_b64decode | 作用同b64decode | 同b64decode | 同b64decode |
import base64
string_info = b'chaogege'
# base64加密
bs_result = base64.b64encode(string_info)
print(bs_result)
# bs_result: b'Y2hhb2dlZ2U='
# base64解密
ss_result = base64.b64decode(bs_result)
print(ss_result)
# ss_result: b'chaogege'
SHA-256
安全散列算法的一种(hash)
- hash三大特点
- 定长输出
- 不可逆
- 雪崩
from hashlib import sha256
s = sha256() # 1.创建sha256对象
s.update(b'chaogege') # 2.添加欲hash的内容,类型为 bytes
binary_result = s.digest() # 3.获取最终结果(纯二进制,用于计算)
hex_result = s.hexdigest() # 4.十六进制结果(十六进制,用于存储)
# binary_result: b'j\x89\x16\x18\xce\x86C\xbfz^\xf5\x83q\xad\xd6\x8a\xa7\x97\x81\xfb\xaa\xa4d\x1b\xc5\xc9\xdd\xfa\x8b\x0c(\xa0'
# hex_result: 6a891618ce8643bf7a5ef58371add68aa79781fbaaa4641bc5c9ddfa8b0c28a0
print(binary_result)
print(hex_result)
HMAC-SHA256
HMAC-SHA256是一种通过特别计算方式之后产生的消息认证码,使用散列算法同时结合一个加密密钥
- 它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证
import hmac
# 1. 生成hmac对象
# 参数1:密钥key,bytes类型,
# 参数2:欲加密的串,bytes类型
# 参数3:hmac的算法,指定为SHA256
key = b'123456'
string = b'{"username":"chaogege"}'
h = hmac.new(key, string, digestmod='SHA256')
result = h.hexdigest() # 获取最终结果
# result: 6ae909d8d5f8258d04a806d8ce1e5915e2351eda3efbcc1b9c535c41137c55ab
print(result)
JWT - json-web-token
三大组成
header
- 格式为字典-元数据格式如下
- 该部分数据需要转成json串并用base64编码
{'alg':'HS256', 'typ':'JWT'}
#alg代表要使用的 算法
#typ表明该token的类别 - 此处必须为 大写的 JWT
payload
- 格式为字典-此部分分为公有声明和私有声明
- 公共声明:JWT提供了内置关键字用于描述常见的问题
- 此部分均为可选项,用户根据自己需求按需添加key,常见公共声明如下
- 公共声明和私有声明均在同一个字典中;转成json串并用base64加密
{
'exp':xxx, # Expiration Time 此token的过期时间的时间戳
'iss':xxx, # (Issuer) Claim 指明此token的签发者
'iat':xxx, # (Issued At) Claim 指明此创建时间的时间戳
}
- 私有声明:用户可根据自己业务需求,添加自定义的key,例如如下:
{'username': 'chaogege'}
signature
- 根据header中的alg确定 具体算法进行加密,以下用HS256为例
sign = hmac.new(自定义的key,base64后的header + b'.' + base64后的payload,digestmod="SHA256")
# 对加密后的结果进行base64编码
sign = base64.b64encode(sign)
jwt结果格式
base64(header) + b'.' + base64(payload) + b'.' + base64(sign)
- 最终结果如下
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8iLCJpc3MiOiJnZ2cifQ.Zzg1u55DCBqPRGf9z3-NAn4kbA-MJN83SxyLFfc5mmM'
校验jwt规则
- 解析header, 确认alg
- 签名校验 - 根据传过来的header和payload按 alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
- 获取payload自定义内容
pyjwt
# 安装
pip3 install pyjwt
常用方法
- encode(payload, key, algorithm)
- payload:jwt三大组成中的payload,需要组成字典,按需添加公有声明和私有声明 例如:
{'username': 'chaogege', 'exp': 1562475112}
参数类型: dict - key : 自定义的加密key 参数类型:str
- algorithm: 需要使用的加密算法[HS256, RSA256等] 参数类型:str
- 若payload中添加了exp字段; 则exp字段得值需为 当前时间戳+此token得有效期时间
- decode(token, key, algorithm, issuer)
- token: token串 参数类型:bytes/str
- key: 自定义的加密key ,需要跟encode中的key保持一致 参数类型:str
- algorithm:需要使用的加密算法[HS256, RSA256等] 参数类型:str
- issuer:发布者,若encode payload中添加 'iss' 字段,则可针对该字段校验 若iss校验失败,则抛出jwt.InvalidIssuerError 参数类型:str
- 在执行decode时,若检查到exp字段,且token过期,则抛出jwt.ExpiredSignatureError
- pyjwt使用示例
import jwt
import time
# 生成token
token = jwt.encode({'uname':'chaogege'}, '123456',algorithm='HS256')
# 验证签发者:issuer
token = jwt.encode({'uname':'chaogege','iss':'dadashop.com'}, '123456', algorithm='HS256')
result = jwt.decode(token, '123456', algorithms='HS256', issuer='dadashop.com')
print(result)
# 验证有效期
token = jwt.encode({'uname':'chaogege', 'exp':time.time()+10}, '123456', algorithm='HS256')
time.sleep(2)
result = jwt.decode(token, '123456', algorithms='HS256')
print(result)
- 手写jwt验证代码
"""
实现jwt的生成和校验
"""
import base64
import hmac
import json
import time
class Jwt:
def __init__(self):
pass
def strtobase64(self,str):
return base64.urlsafe_b64encode(str.encode()).replace(b'=',b'')
def base64tostr(self,byte):
return base64.urlsafe_b64decode(byte)
def dicttojson(self,dict):
return json.dumps(dict,separators=(',',':'))
def jsontodict(self,str):
return json.loads(str)
def get_sign(self,header,payload,key):
sign = hmac.new(key.encode(),header+b'.'+payload,digestmod='SHA256').digest()
return base64.urlsafe_b64encode(sign).replace(b'=',b'')
# def make_token(self, payload, key, expire=600):
def make_token(self,payload_dict,key):
# 1.第一部分:header
header_dict = {"alg": "HS256","typ": "JWT"}
header_json = self.dicttojson(header_dict)
header = self.strtobase64(header_json)
# 2.第2部分:payload 共有声明和私有声明
payload_json = self.dicttojson(payload_dict)
payload = self.strtobase64(payload_json)
# 3.第3部分:对前两部分的和进行hmac加密,并进行base64编码
sign = self.get_sign(header,payload,key)
return header+b'.'+payload+b'.'+sign
def check_token(self,token,key):
# 1.验证签名
header = token.split('.')[0]
payload = token.split('.')[1]
sign = token.split('.')[2]
if sign.encode() != self.get_sign(header.encode(),payload.encode(),key):
return False
payload_json = self.base64tostr(payload)
payload_dict = self.jsontodict(payload_json)
if payload_dict['exp'] < time.time():
return False
return True
o = Jwt()
get_str = o.make_token({"sub": "1234567890", "name": "John Doe", "iat": 1516239022, "exp": 1716239022}, 'test')
# print(get_str)
is_ok = o.check_token('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTYyMzkwMjJ9.zYaDerrl9TYk3M17nN6237AWKP6LM7vIxg7TzaUdas0','test')
print(is_ok)
最后一次更新于2023-03-17 11:16
0 条评论