python 实现用户登录

1. JWT Token

参考:https://www.zhihu.com/question/364616467
jwt官网:https://jwt.io/#debugger-io

1.1. Token

Token 是一个宽泛的术语,它可以指代任何一种用于身份验证的机制。Token 常常被用在验证和授权流程中。Token 可以有不同的形式和结构,如随机生成的字符串或者特定格式的编码数据。

1.1.1. 特点和使用

不固定格式: Token 可以是任何格式的数据字符串,不仅限于JWT。
存储信息: Token 可能仅作为引用存储在服务器上,服务器通过该引用来获取存储的状态信息。
会话管理: 经统一的身份验证后,Token 用来管理用户会话。
传输方式灵活: 可以通过 HTTP headers、URL 参数或请求体传输。

1.1.2. Token 基本原理

Token(就是加密的字符串,使用 MD5 等不可逆加密算法,一定要保证唯一性)客户端使用用户名跟密码请求登录服务端收到请求,去验证用户名与密码验证成功,服务端会签发一个 Token 保存到(Session,redis,mysql…)中,然后再把这个 Token 发送给客户端客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里客户端每次向服务端请求资源的时候需要带着服务端签发的 Token服务端收到请求,验证密客户端请求里面带着的 Token 和服务器中保存的 Token 进行对比效验, 如果验证成功,就向客户端返回请求

1.1.3. 优缺点

优点
可以隐藏真实数据,安全系数高
适用于分布式/微服务
Token支持手动控制,过期、吊销等
可以实时查询现有Token
缺点
存放在数据库或者redis,依赖服务器资源
效率相对JWT比较低

1.2. JWT 是什么

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

1.2.1. 作用

JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源。比如用在用户登录上。
JWT 最重要的作用就是对 token 信息的防伪作用。

1.2.2. JWT 组成

一个 JWT 由三部分组成:JWT 头、有效载荷、签名哈希,这三部分分别进行 base64url 编码,之间用“ .” 相互连接,如下,一个JWT字符串:
JWT头
JWT 头部分是一个描述 JWT 元数据的JSON对象,包含两部分信息:

  • 声明类型,这里是“JWT”
  • 使用的加密算法,如HMAC、SHA256、RSA,默认为HMAC SHA256(写为HS256)
    完整的头部如下面的 JSON
{"alg": "HS256","typ": "JWT"
}

这部分 JSON 对象使用 Base64 URL 算法转换为字符串保存
有效载荷
有效载荷,是 JWT 的主体内容部分,也是一个 JSON 对象,包含需要传递的数据。 JWT 指定七个默认字段供选择。

iss # jwt签发者
sub # 主题
aud # 接收jwt的一方
exp # jwt的过期时间,这个过期时间必须要大于签发时间
nbf # 定义在什么时间之前,该jwt都是不可用的.
iat # jwt的签发时间
jti # jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

也可以自定义字段,如:

{"name": "Ann","role": "manager",
}

这部分 JSON 对象也使用 Base64 URL 算法转换为字符串保存,因此是未加密的,所以注意不要放敏感信息(如密码)
签名哈希
签名哈希部分是对上面两部分数据签名,通过指定的算法生成哈希,以确保数据不会被篡改。
首先,需要指定一个密码(secret)。该密码仅仅为保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法(默认为SHA256)根据下述公式生成签名。

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(claims), secret)    ==>   签名hash

签名的作用
签名的过程实际上是对头部和负载内容进行签名,防止内容被窜改。假如有人对头部和负载的内容解码之后进行修改,再进行编码,最后加上之前的签名组合形成新的 JWT 的话,这样服务器端可以判断出新的头部和负载形成的签名和 JWT 附带上的签名是不一样的,这样服务器端就可以知道数据被篡改了。(这是由于签名产生,需要结合头部、负载、以及密钥来生成,而密钥保存在服务器端,无法获取)在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个 JWT 对象。

1.2.3. JWT 单点登录流程

首次登陆,客户端向服务器请求令牌,服务器接收客户端发送的用户凭证(如用户名、密码)进行身份校验,校验成功后,服务端生成 JWT(有过期时间),将其发送给客户端。
客户端接收 JWT 令牌后,存储它(通常,客户端将令牌存储在 Cookie 中)。
之后客户端每次访问服务器的应用资源,都会将 JWT 令牌发送给服务器,用以验证客户端身份。
服务端收到 JWT 令牌,对其进行验证,验证通过,则认为客户端已经被授权访问应用资源,否则拒绝客户端访问。
假如令牌过期,客户端需要重新向服务器端请求新令牌,然后再进行资源访问。

1.2.4. 优缺点

无状态: JWT 自身包含了身份验证所需要的所有信息,因此,我们的服务器不需要存储 Session 信息。这显然增加了系统的可用性和伸缩性,大大减轻了服务端的压力。
不过,也正是由于 JWT 的无状态,也导致了它最大的缺点:不可控
就比如说,我们想要在 JWT 有效期内废弃一个 JWT 或者更改它的权限的话,并不会立即生效,通常需要等到有效期过后才可以。
再比如说,当用户 Logout 的话,JWT 也还有效。除非,我们在后端增加额外的处理逻辑比如将失效的 JWT 存储起来,后端先验证 JWT 是否有效再进行处理。
有效的避免的 CSRF 攻击

1.3. jwt 实践

1.3.1. 环境安装

pip install pyjwt

1.3.2. 生成 JWT

from jose import JWTError, jwt
import datetime# 密钥,用于签名和验证JWT
secret_key = 'your-secret-key'# 载荷,即JWT中包含的信息
payload = {'user_id': 112233445566,'username': 'jack','exp': datetime.datetime.utcnow() + datetime.timedelta(days=1)
}# 生成JWT
token = jwt.encode(payload, secret_key, algorithm='HS256')
print('Generated JWT:', token)

运行结果:

Generated JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMTIyMzM0NDU1NjYsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTcxNDExNDU3OH0.AKvwYltVfQ14b9zzS6ILC9NWf9kUiEyedL2aJ_8vF9s

登录官网验证:
官网地址:https://jwt.io/#debugger-io
在这里插入图片描述

1.3.3. 验证 JWT

from jose import JWTError, jwt
import datetime# # 密钥,用于签名和验证JWT
secret_key = 'your-secret-key'# 待验证的JWT
# received_token = 'your-received-token'
received_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMTIyMzM0NDU1NjYsInVzZXJuYW1lIjoiamFjayIsImV4cCI6MTcxNDExNDU3OH0.AKvwYltVfQ14b9zzS6ILC9NWf9kUiEyedL2aJ_8vF9s'try:# 验证JWTdecoded_payload = jwt.decode(received_token, secret_key, algorithms=['HS256'])print('Decoded Payload:', decoded_payload)
except jwt.ExpiredSignatureError:print('JWT has expired.')
except jwt.InvalidTokenError:print('Invalid JWT.')

运行结果:

Decoded Payload: {'user_id': 112233445566, 'username': 'jack', 'exp': 1714114578}

1.3.4. 高级选项与定制

PyJWT还提供了一系列高级选项和定制功能,例如自定义过期时间、指定算法、添加额外的头部信息等。

import jwt
import datetime# 密钥,用于签名和验证JWT
secret_key = 'your-secret-key'# 载荷,即JWT中包含的信息
payload = {'user_id': 112233445566,'username': 'jack',
}# 自定义过期时间为10分钟后
expiration_time = datetime.datetime.utcnow() + datetime.timedelta(minutes=10)# 生成JWT并指定算法和额外的头部信息
token = jwt.encode(payload, secret_key, algorithm='HS256', headers={'kid': 'key-id'}, exp=expiration_time)
print('Generated JWT:', token)

运行结果:

Generated JWT: eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleS1pZCIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMTIyMzM0NDU1NjYsInVzZXJuYW1lIjoiamFjayJ9.ZYaXfdWodS5Nh0D0z-W5A6IhN9l6_ZHlIgechMLtB2w

登录官网验证:
官网地址:https://jwt.io/#debugger-io
在这里插入图片描述

1.4. 实例1 面向对象

from jose import JWTError, jwt
import datetimeclass JWTToken(object):def __init__(self) -> None:# 密钥,用于签名和验证JWTself._secret_key = 'a9d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e8'self._algorithm = "HS256"pass# payload: 载荷,即JWT中包含的信息def jwt_encode(self, payload: dict):# 生成JWTtoken = jwt.encode(payload, self._secret_key, algorithm=self._algorithm)print('Generated JWT:', token)return tokendef jwt_decode(self, token: str):payload = ""try:# 验证JWTpayload = jwt.decode(token, self._secret_key, algorithms=[self._algorithm])print('Decoded Payload:', payload)except jwt.ExpiredSignatureError:print('JWT has expired.')except jwt.InvalidTokenError:print('Invalid JWT.')return payloadif __name__ == '__main__':jwt_token = JWTToken()payload = {'user_id': 112233445566,'username': 'jack','jti': 'once','iss': 'server_id','exp': datetime.datetime.utcnow() + datetime.timedelta(days=1)}access_token = jwt_token.jwt_encode(payload=payload)# 服务器验证刷新令牌的有效性后,生成新的访问令牌,并返回给客户端payload = {'username': 'jack','sub': 'refresh'}refresh_token = jwt_token.jwt_encode(payload=payload)jwt_token.jwt_decode(token=access_token)jwt_token.jwt_decode(token=refresh_token)

运行结果:

Generated JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMTIyMzM0NDU1NjYsInVzZXJuYW1lIjoiamFjayIsImp0aSI6Im9uY2UiLCJpc3MiOiJzZXJ2ZXJfaWQiLCJleHAiOjE3MTQxMTg3MjR9.YsFTI8KwHeQFics2g-DdiN01a8J7xXeV_ExTf1cviWI
Generated JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImphY2siLCJzdWIiOiJyZWZyZXNoIn0.NgHJ2NCd72NxscKZboYGKJg2P_GSQLu1Ku7WINrABXE
Decoded Payload: {'user_id': 112233445566, 'username': 'jack', 'jti': 'once', 'iss': 'server_id', 'exp': 1714118724}
Decoded Payload: {'username': 'jack', 'sub': 'refresh'}

2. 非对称加密 rsa

五种常见的用户密码泄露方式:
https://cloud.tencent.com/developer/article/1903494
JWT认证中如何防止他人冒充token
https://www.zhihu.com/question/364616467

2.1. 环境安装

pip install pycryptodome # windows上使用的是pycryptodome包。
pip install pycryptodome # Linux上使用pycrypto包。

2.2. 实例1 面向对象

# -*- coding: utf-8 -*-
import base64
from Crypto import Random
from Crypto.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
from Crypto.PublicKey import RSAclass RSACrypto(object):def __init__(self):print("CipherTool init")# 获取公钥和私钥def rsa_keys(self):random_generator = Random.new().readrsa = RSA.generate(1024, random_generator)rsa_private_key = rsa.exportKey()rsa_public_key = rsa.publickey().exportKey()return {"rsa_private_key":rsa_private_key, "rsa_public_key":rsa_public_key}# 用公钥进行加密def ras_encrypt(self, public_key: str, clear_text:str):# 加密函数 encrypt 需要使用 bytes 类型数据clear_text = clear_text.encode(encoding="utf-8")rsakey = RSA.importKey(public_key)cipher = Cipher_pkcs1_v1_5.new(rsakey)cipher_text = cipher.encrypt(clear_text)# cipher_text = base64.b64encode(cipher.encrypt(message))# print("", cipher_text)return cipher_text# 用私钥进行解密def ras_decrypt(self, private_key, cipher_text: bytes):rsakey = RSA.importKey(private_key)cipher = Cipher_pkcs1_v1_5.new(rsakey)# random_generator = Random.new().readclear_text = cipher.decrypt(cipher_text, None)# text = cipher.decrypt(base64.b64decode(cipher_text), None)# print(clear_text.decode())return clear_text.decode(encoding="utf-8")if __name__ == '__main__':rsa_crypto = RSACrypto()rsa_keys = rsa_crypto.rsa_keys()print("rsa_private_key:", rsa_keys["rsa_private_key"])print("rsa_public_key:", rsa_keys["rsa_public_key"])clear_text = "hello world"cipher_text = rsa_crypto.ras_encrypt(public_key=rsa_keys["rsa_public_key"], clear_text=clear_text)print("cipher_text:", cipher_text)clear_text = rsa_crypto.ras_decrypt(private_key=rsa_keys["rsa_private_key"], cipher_text=cipher_text)print("clear_text:", clear_text)

运行结果:

CipherTool init
rsa_private_key: b'-----BEGIN RSA PRIVATE KEY-----\nMIICWwIBAAKBgQCxsXGQv4tuhdngOHQvzV6QLfiZ7aK5FL5goOVpOr4vceDZpreo\nIhPvpjj8W6gyOqBTM4D6Im/x7OWOYfB9zVwpbLYPftePK/NBbqtfWqkaLOToEbCi\ngeybrDyJBS2vqb7RLbEkiXkPgKxK7oNk/QxdKnUc32GL81jCZKB4pkBU8QIDAQAB\nAoGAEuU0l1jXAdy363D1YfPrv1c0HWI4sIe1Kt9RJdx6Rt9MMrjYxMdC6XP6kVNJ\n0nWLgO10JKUu1EIFsxtVEHua9htYlTX/m3eVz+8d30uJiSA1IvWWwNQ531k8H5Fq\nu8Vfj36JDpN1q6f4cIDiKh+7CjcK3G3jrSUasr2w8tZBA8UCQQDO1Bvsa9k27rLE\nBUYXdI/f267/OEFHZX/KawdmFmXh31dPyDozsx2vDccDYnJdpK/ykYiRKYJTzQ5K\nnvhb0RC/AkEA2/AcQIKnCTYXr/t9iBaBDaj5M51t3azG6YPk96VVBHjYhvCgHPkl\nz47/AKrGGtNYp0OVv1HADYiM0Yp2leRWTwJAN6a3BLxYLAG6NCg/HdyNQey4f4/B\ncNaMtghqazunmkkgEyWLE5IkcI/CdtSsdSn09c3W80g5+xZ3u/heV0Y/vQJADJu2\nMuiKhNeqAfer2ZpYqZzPNGtI+hVGjep2vM+okQoQd6Phued6iGyNJ8+ibbVB9szE\nD+Sy2tPCJt0GMU+WtwJAclT51+DzFVscyp0V13ocoNacTZCqJ99f8o6sEnv8znId\nEIdFS9ALoo+U2VXG815acsZLmw/2dpqiwYS5nuryIA==\n-----END RSA PRIVATE KEY-----'
rsa_public_key: b'-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxsXGQv4tuhdngOHQvzV6QLfiZ\n7aK5FL5goOVpOr4vceDZpreoIhPvpjj8W6gyOqBTM4D6Im/x7OWOYfB9zVwpbLYP\nftePK/NBbqtfWqkaLOToEbCigeybrDyJBS2vqb7RLbEkiXkPgKxK7oNk/QxdKnUc\n32GL81jCZKB4pkBU8QIDAQAB\n-----END PUBLIC KEY-----'
cipher_text: b'YG\x97\x87\xb5\xf4_\xd4\xb1\x0bR\xa0\xe8\xf6\x80x\x94+\xc4\x9a\r0\x91\xab\x95oo\xe9\xcf\xaf\xacl\xd5\x97\xe8$_5W\xc66\xa2K\x90a\x8d\x1b>\x1a\xa2\x16 \xceY\x85\x83\xa8w\x94K\xe4\x05\x8c\xa2+\xf3\xb0o\x07"\xaf\x8f\x88\x11Om\x02n\xe3\xed\xe9L\xb7( \xbfQV\xda\xd9\xed]\xa0B\x8dv\xc3\xb9\xab\xad\xdb.\xe4YB\xa4D\x8c\\ \xa9h\x97\xc2\x13\xff\n\xd0\x9a\x04\x9f\xdb\xec8\xb4O-\t'
clear_text: hello world

2.3. 实例2 面向过程

message = "hello world"
message = message.encode()# 获取公钥和私钥
random_generator = Random.new().read
rsa = RSA.generate(1024, random_generator)rsa_private_key = rsa.exportKey()
rsa_public_key = rsa.publickey().exportKey()
print("private key:", len(rsa_private_key), rsa_private_key)
print("public key:", len(rsa_public_key), rsa_public_key)# 用公钥进行加密
rsakey = RSA.importKey(rsa_public_key)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
cipher_text = cipher.encrypt(message)
# cipher_text = base64.b64encode(cipher.encrypt(message))
# print("cipher_text:", cipher_text)# 用私钥进行解密
rsakey = RSA.importKey(rsa_private_key)
cipher = Cipher_pkcs1_v1_5.new(rsakey)
clear_text = cipher.decrypt(cipher_text, None)
# text = cipher.decrypt(base64.b64decode(cipher_text), None)
print("clear_text:", clear_text.decode())

运行结果:

private key: 886 b'-----BEGIN RSA PRIVATE KEY-----\nMIICXAIBAAKBgQC4bZYjXWsNe4U4KZWSR3bykL5I55AlxVQrPabp2TmGkWqPffj2\n7gmMIlYsSJnm/RXqlGjBhSeQwrGPDgGH+d89w9m+1zI1S+l4D/w/jtWxEPMA9SqT\n95P5CPvBWt9mdUim2gso1lF3ZQ1wDBTbgns5qYk8zcIfXN0nvFvH/tZZKQIDAQAB\nAoGAEKQmw3sm8Tj/jNFHw0K6i2mfGeH3IklbbmlqObiVlbxiUp9JyzIwX1orz2Qf\nqvWUOC37A9c5ejjvH5ribXwQ9hDEE1+cmH1jfsEtoEPIR00QBUOuwT2jwwUthdc/\nWMQIlwjNTXKyuL/4s1qEZiLp3h9wnFv0dMOgOF+DbEIUQucCQQC/sPcnlMOmhCFo\njuuwKvlcE8NmHtwIGOZHlqUBLm1LKMSP4U1Rsm9ezd20Ud2ocVAlFCqFuSsCGuHm\nY6AFBw47AkEA9kzVz/ReDsQpJdzpfJb5MNI9NCJicNVe8yflk2lTlR+6v42yZEwc\nMIYfHXAl519CJFd4Hr5a4psjUq1hmINL6wJAamT3mTF5sneN73G8ISiJBPE3N/wS\n1i+zyLI1XUV+hgPXraA4gQrPw8fxsP7rT22tNRdPTq9qzp1LGsva6k9zNwJBANeP\n27nLd96YlCLNO5SNVb8C4goU5e8274kErAreLgbf5EPuMelSK4HUgLr1AleDqZHA\n9CKEG2skuD+N+1LN5s0CQEVkeiPTlEM7hg+HG7fnE0Qzin4S+0JJ14V3fnKbJ4fG\n+PlW9tj2Rq4l2zNDJ+AiDNfv0JkYdrVbBqBXyVU/Ofs=\n-----END RSA PRIVATE KEY-----'
public key: 271 b'-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4bZYjXWsNe4U4KZWSR3bykL5I\n55AlxVQrPabp2TmGkWqPffj27gmMIlYsSJnm/RXqlGjBhSeQwrGPDgGH+d89w9m+\n1zI1S+l4D/w/jtWxEPMA9SqT95P5CPvBWt9mdUim2gso1lF3ZQ1wDBTbgns5qYk8\nzcIfXN0nvFvH/tZZKQIDAQAB\n-----END PUBLIC KEY-----'
clear_text: hello world

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/3717.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言笔试题之找出数组的最大公约数

找出数组的最大公约数 实例要求 1、给定一个整数数组 ,返回数组中最大数和最小数的最大公约数;2、两个数的最大公约数是能够被两个数整除的最大正整数;示例: 实例分析 1、要找到数组中最大数和最小数的最大公约数&#xff1b…

python 中使用 ESP8266 实现语音识别(或热词检测)

介绍 我的大部分家庭自动化都是通过对网络中的设备执行 HTTP 请求来控制的。 (例如:开灯、打开收音机、控制加热系统...... 这可以使用ESP8266轻松完成。我有一个控制器和一个触摸传感器,当我在床上时用它来控制灯光和音乐。 像 Amazon Echo 或 Google Homepod 一样添加语…

Apache RocketMQ ACL 2.0 全新升级

作者:徒钟 引言 RocketMQ 作为一款流行的分布式消息中间件,被广泛应用于各种大型分布式系统和微服务中,承担着异步通信、系统解耦、削峰填谷和消息通知等重要的角色。随着技术的演进和业务规模的扩大,安全相关的挑战日益突出&am…

《AI创作类工具之十四——​ Verse》

一.简介 官网:Verse - 新一代生产力工具 Verse是一款功能丰富的智能写作工具,它集合了实时预览、代码高亮、表格编辑和数学公式支持等特色功能,为用户提供了高效的文档编写和管理体验。Verse不仅界面设计简洁,使用户能够更专注于文档内容,还提供了丰富的功能来帮助用户更…

Elment ui 表单上滑 加载更多数据方法

方法记录 方便以后使用 方法一&#xff1a; <template><div><el-table:data"tableData"height"calc(100vh - 300px)"ref"table":show-header"false"><el-table-columnprop"date"label"日期"…

HPE Aruba Networking推出新一代Wi-Fi 7接入点 助力企业高效应对安全、AI与物联网挑战

HPE ArubaNetworking推出的全新Wi-Fi 7接入点&#xff0c;提供全面的AI就绪边缘IT解决方案&#xff0c;旨在为用户和物联网设备提供安全、高性能的连接服务&#xff0c;以实现数据的捕获和路由&#xff0c;从而满足AI训练和推理需求 休斯顿-2024年4月23日-慧与科技(NYSE: HPE)近…

vue+html5+css制作日历代码,工作日配置

目录 1.日历页面 2.工作日查询、自然日查询 js 3.修改工作日配置 4.数据库&#xff0c;表结构 5.初始化数据 因系统需要&#xff0c;需要制作一个功能--工作日配置。 需要的业务有&#xff1a; 1.初始化与国家放假情况一致&#xff0c;之后支持手动进行工作日配置&#…

Python 网络与并发编程(四)

文章目录 协程Coroutines协程的核心(控制流的让出和恢复)协程和多线程比较协程的优点协程的缺点 asyncio实现协程(重点) 协程Coroutines 协程&#xff0c;全称是“协同程序”&#xff0c;用来实现任务协作。是一种在线程中&#xff0c;比线程更加轻量级的存在&#xff0c;由程…

《欢乐钓鱼大师》攻略,钓友入坑必备!

欢迎来到《欢乐钓鱼大师》&#xff01;在这个游戏里&#xff0c;你可以尽情享受垂钓的乐趣&#xff0c;通过不断更换和升级高阶鱼竿&#xff0c;轻松地钓到各种稀有鱼类。因为许多玩家在挑战关卡时遇到了一些困难&#xff0c;所以今天我给大家带来了《欢乐钓鱼大师攻略指南》&a…

日志框架整合SpringBoot保姆级教程+日志文件拆分(附源码)

目录 介绍 日志概述 日志文件 调试日志 系统日志 日志框架 日志框架的作用 日志框架的价值 流行的日志框架 SLF4J日志门面 介绍 环境搭建简单测试 集成log4j logback Logback简介 Logback中的组件 Logback配置文件 日志输出格式 控制台输出日志 输出日志到…

代谢网络模型学习笔记(序章)

代谢模型学习笔记&#xff08;序章&#xff09; 全文目录 代谢模型学习笔记&#xff08;序章&#xff09;-1、 闲言碎语0 、前言说明重点说明 1 、内容概述1.1 文献分享 Shifts in growth strategies reflect tradeoffs in cellular economics 2、 论文笔记3、思考讨论 -1、 闲…

vue-admin-template项目实现中英文切换

实现效果&#xff1a; 1.安装 *注意版本号 npm install vue-i18n8.24.5 -S2.新建文件夹 在src目录下新建lang文件夹&#xff0c;里面有3个文件 // index.js import Vue from vue import VueI18n from vue-i18n import Cookies from js-cookie import elementEnLocale fr…

OpenHarmony音视频—opus

简介 Opus是一种用于在互联网上进行交互式语音和音频传输的编解码器。它可以从低比特率窄带语音扩展到非常高的高品质立体声音乐。 下载安装 直接在OpenHarmony-SIG仓中搜索opus并下载。 使用说明 以OpenHarmony 3.1 Beta的rk3568版本为例 将下载的opus库代码存在以下路径&a…

深入解析面向对象编程(OOP)的三大核心特性:封装、继承与多态性

文章目录 1. 封装&#xff1a;保护数据和隐藏实现细节2. 继承&#xff1a;提高代码复用性3. 多态&#xff1a;接口一致&#xff0c;实现多样 面向对象编程&#xff08;Object-oriented programming&#xff0c;OOP&#xff09;的三大特性——封装、继承和多态。 1. 封装&#x…

软件架构设计 Azure架构

软件架构 是指软件系统的组织结构&#xff0c;它定义了软件组件之间的关系、交互方式以及系统整体的设计原则和思想。在软件开发领域&#xff0c;有许多种不同类型的架构&#xff0c;其中一些常见的包括&#xff1a; 客户端-服务器架构&#xff08;Client-Server Architecture…

【spark】spark使用sql读取elasticsearch es索引,使用keystore配置用户密码

参考文章 spark配置elasticsearch属性汇总(基于es7) es-offical-doc Spark多方案读取Es性能比较 Spark读写ES数据时遇到的问题总结 es 查询多个索引的文档 spark table中使用明文密码 set es.index.auto.createtrue drop table if exists default.test_es01; create table d…

怎样选购内衣洗衣机?2024年5款最新推荐机型种草

随着科技的不断发展&#xff0c;内衣洗衣机成为了家家户户必备的小家电之一&#xff0c;为我们的生活带来了极大的便利。但面对市场上众多的内衣洗衣机品牌&#xff0c;如何选择一款质量好的内衣洗衣机呢&#xff1f;本文将为您推荐5款最新的内衣洗衣机品牌&#xff0c;从而帮助…

vue的优化手段

vue常见优化手段 使用key 对于通过循环生成的列表,应给每个列表项一个稳定且唯一的key,这有利于在列表变动时,尽量少的删除、新增、改动元素。 使用 index 作为 key 值,唯一但是不稳定。 一般情况下,应该选取 id 作为key值。 使用冻结对象 冻结的对象不会被响应化。…

二倍体毛白杨(Populus tomentosa Carr.)基因组-春天都是杨树毛子???-文献精读-11

High quality haplotype-resolved genome assemblies of Populus tomentosa Carr., a stabilized interspecific hybrid species widespread in Asia 高质量二倍体解析的毛白杨&#xff08;Populus tomentosa Carr.&#xff09;基因组组装&#xff0c;这是一种在亚洲广泛分布的…

SCSS的基本使用(一)

目录 一、使用&符号来引用父选择器 二、scss的语法 三、变量&#xff08;Variables&#xff09; 四、嵌套&#xff08;Nesting&#xff09; 五、mixin 和 include 六、extend 继承 七、import 与 Partials 八、if简单判断 九、if复杂判断 一、使用&符号来引用父…