python 实现用户登录

news2025/6/19 6:45:57

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:
    # 验证JWT
    decoded_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 datetime

class JWTToken(object):
    def __init__(self) -> None:
        # 密钥,用于签名和验证JWT
        self._secret_key = 'a9d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e8'
        self._algorithm = "HS256"
        pass

    # payload: 载荷,即JWT中包含的信息
    def jwt_encode(self, payload: dict):
        # 生成JWT
        token = jwt.encode(payload, self._secret_key, algorithm=self._algorithm)
        print('Generated JWT:', token)
        return token

    def jwt_decode(self, token: str):
        payload = ""
        try:
            # 验证JWT
            payload = 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 payload

if __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 RSA

class RSACrypto(object):
    def __init__(self):
        print("CipherTool init")

    # 获取公钥和私钥
    def rsa_keys(self):
        random_generator = Random.new().read
        rsa = 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().read
        clear_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.coloradmin.cn/o/1626186.html

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

相关文章

标准版/开源版 移动端新增页面使用文档

在标准版开发的实际使用中,随着用户移动端的产品和信息内容不断增多,新增页面来展示对应的产品详情、模块等内容。针对一些概念或者步骤较多的内容,可以新增子页面构建多级模块结构,帮助用户快速定位。 下面就如何新增页面做一讲…

Linux中手工创建一个用户

当我们需要新创建一个用户时,有两种方法 1.使用命令添加用户 2.去配置文件里面添加用户 1,使用useradd命令: [rootlocalhost /]# useradd tmg 然后给它设置一个密码 [rootlocalhost etc]# passwd tmg Changing password for user tmg. N…

janus模块介绍-SIP Gateway

模块启动 默认的SIP GateWay也是https协议,端口为8088或者8089 如果需要在自己搭建的测试服务上测试SIP GateWay模块,则也需要修改为wss 具体改动如下: 找到/opt/janus/share/janus/demos/siptest.js var server "wss://" window.location…

Python基础知识—运算符和if语句(二)

🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》 《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 1.输入和输出函数1.1输出函数1.2输入函数 2.常见运算符2.1赋值运算符2.2比较运算符2.3逻辑运算符2.4and逻辑与2.5or逻辑或2.6not逻…

前端JS必用工具【js-tool-big-box】,防抖和节流的方法调用学习

这一小节,我们针对前端工具包(npm)js-tool-big-box的使用做一些讲解,主要是防抖和节流方面的。 目录 前言 1 安装和引入 2 防抖的调用学习 3 节流的调用学习 4 使用方法总结 前言 在前端项目中,经常涉及到防抖…

漏斗分析方法

目录 1.什么是漏斗分析方法 2.基本概念 3.漏斗步骤的构建 4.漏斗分析的意义 5.漏斗分析的挑战和限制 6.进行漏斗分析的步骤与方法 7.在数据分析中应用漏斗分析的策略 8.示例 1.什么是漏斗分析方法 漏斗分析方法是数据分析中一种常见的技术,专门用于优化和提…

Python 网络与并发编程(四)

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

走进电线电缆行业龙头金杯电工,助推湖南“智赋万企”行动热潮

湖南省政府推动的“智赋万企”行动掀起千行百业万企的数智化浪潮,在企业、服务商、行业协会等多方共推下,湖南省的数字化生态越发繁荣。 4月23日,纷享销客举办的【走进数字化游学示范基地之金杯电工】活动在长沙顺利举行。本期活动走进电线电…

ThingsBoard远程RPC调用设备

使用 RPC 功能 客户端 RPC 从设备发送客户端 RPC 平台处理客户端RPC 服务器端 RPC 服务器端RPC结构 发送服务器端RPC 使用 RPC 功能 ThingsBoard 允许您从服务器端应用程序向设备发送远程过程调用 (RPC),反之亦然。基本上,此功能允许您向设备发送命…

vue2项目升级到vue3经历分享1

依据vue官方文档,vue2在2023年12月31日终止维护。因此决定将原来的岁月云记账升级到vue3,预计工作量有点大,于是想着把过程记录下来。 原系统使用的技术栈 "dependencies": {"axios": "^0.21.1","babel-…

Qt配置CMake出错

一个项目需要在mingw环境下编译Opencv源码,当我用Qt配置opencv的CMakeLists.txt时,出现了以下配置错误: 首先我根据下述博文介绍,手动配置了CMake,但仍不能解决问题。 Qt(MinGW版本)安装 - 夕西行 - 博客园 (cnblogs.…

数之寻软件怎么样?

数之寻软件是一款功能强大的数据恢复和备份软件,以下是对其特点和功能的详细评价: 一、数据恢复方面: 高效的数据恢复能力:数之寻软件采用了先进的算法和数据恢复技术,能够快速有效地恢复丢失或损坏的数据。无论是文…

laravel视频对接aws

本次对接文件上传,目标是实现超级大文件的上传任务,可能就是4~5个g的视频文件,折腾了蛮久熟悉s3,因此记录一下。 大家要是对filesystem不清楚去看一下官方文档不然可能有点懵逼。 首先我先是对接了一个普通的s3存储文件的功能&a…

[解决] 为什么 App Inventor 扩展导入了,但是没啥反应?

大概率是导入拓展后,没有拖动拓展到界面上! 导入拓展后,别忘了拖动拓展到主界面上,这样才算真正创建了拓展对象,这时才能使用拓展的方法。 原文:为什么 App Inventor 扩展导入了,但是没啥反应&…

了解Cookie登录:原理、实践与安全指南

什么是Cookie登录? Cookie是什么 当你首次登录网站时,你会输入用户名和密码。在后台,网站的服务器验证这些凭据是否正确。一旦确认你的身份无误,服务器就会创建一个Cookie,并将其发送到你的浏览器。这了解Cookie登录…

量子+AI,实用还需多久?

生成式人工智能正在席卷全球。OpenAI的GPT-4能够通过律师资格考试,Midjourney的图像作品能够赢得艺术大奖,而Sora则能够根据文本创造出令人难以置信的逼真视频。 这些AI模型的成就预示着通用人工智能的曙光——一个曾经只存在于科幻小说中的概念。然而&a…

快速了解网站访问为什么提示存在安全隐患,该怎么解决

这通常是由于网站使用了不安全的HTTP协议进行通信,或者网站的SSL证书存在问题,或者网站被标记为危险,或者网页中混杂了非HTTPS的内容。 网站访问提示不安全通常是由于以下原因之一引起的,可以按照相应的解决方案进行排查和解决&…

Java集合相关的List、Set、Map基础知识

目录 一、集合介绍 二、List 三、Map HashMap的数据结构 如何理解红黑树 四、set 一、集合介绍 在Java中,集合是一种用于存储对象的数据结构,它提供了一种更加灵活和强大的方式来处理和操作数据。Java集合框架提供了一系列接口和类,用…

CyberData统一元数据服务

CyberData统一元数据服务功能完善,实现了湖仓平台元数据在整个平台的统一管理以及外部数据源元数据的主动发现和多计算引擎间元数据的互通互联。 同时,我们支持跨多元计算场景,以及在元数据基础上的统一数据权限管理和数据湖的自动化优化加速…

2024年好用又便宜的云手机!哪款性价比高?

随着科技的飞速发展,云计算技术也在不断演进,而云手机作为其创新之一,已经开始在我们的生活中崭露头角。它通过将手机的硬件和软件功能移到云端,让用户能够借助强大的云计算资源完成各种任务。2024年,哪款云手机性价比…