【14.0】DRF之JWT
【一】引入(cookie/session/token)
- 详见博客
【4.0】基础串联之CookieSessionToken - Chimengmeng - 博客园 (cnblogs.com)
cookie、session和token都是用于在网络应用中进行身份验证和状态管理的机制。
【1】详解
-
Cookie(HTTP Cookie):
-
Cookie是服务器发送到用户浏览器并保存在用户本地机器上的一小段数据。
-
它主要用于跟踪用户的会话状态、存储用户偏好设置以及提供个性化的服务。
-
当用户访问同一网站时,浏览器会自动将相应的Cookie信息包含在HTTP请求头中发送给服务器。
-
服务器可以根据这些信息来判断用户的身份或状态,并做出相应的响应。
-
-
Session(会话):
-
Session是一种服务器端的机制,用于跟踪用户的会话状态。
-
当用户首次访问网站时,服务器为该用户创建一个唯一的Session ID,并将其存储在服务器内存或数据库中。
-
同时,在用户的浏览器中存储一个包含Session ID的Cookie。
-
之后的每个请求都会带有这个Session ID,服务器通过它来识别用户,并可以在会话期间保存用户的相关数据。
-
Session更安全,因为Session数据保存在服务器端,用户无法直接修改。
-
-
Token(令牌):
- Token是一种在身份验证和授权方面更加灵活和安全的机制。
- 它是一个包含有关用户身份和权限的加密字符串,生成和验证均在服务器端进行。
- 当用户登录后,服务器会生成一个Token并返回给客户端。
- 客户端将此Token存储,并在每次请求时将其包含在请求头中。
- 服务器根据Token验证用户的身份和权限,并做出相应的响应。
- Token可以是无状态的,服务器端不需要存储Token相关的信息,因此有效减轻了服务器的存储压力。
【2】发展史:
-
Cookie最早由网景公司的程序员Lou Montulli于1994年提出,目的是实现在网站间共享用户状态的机制。
- 随着互联网的发展,Cookie被广泛使用,并逐渐演化成为Web开发中不可或缺的一部分。
-
Session则是作为对Cookie的补充而出现的。
- 由于Cookie存在某些安全和存储上的限制,Session被引入以解决这些问题。
- Session的概念首次由Randy Waki和Haden King于2000年在一篇名为《Session Tracking Mechanism》的研究论文中提出。
-
Token作为一种更加灵活和安全的身份验证机制,近年来得到越来越广泛的应用。
- 它主要受益于移动应用的兴起和各种Web API的普及。
- Token的概念并没有一个明确的起源,但随着JWT(JSON Web Token)的出现,Token得到了更大范围的应用。
- JWT是一种基于JSON的开放标准(RFC 7519),用于在各方之间安全地传输信息,并可以被验证和信任。
【二】base64编码解码
- Base64编码是一种将二进制数据以文本形式表示的编码方式。
- 它将3个字节的二进制数据分割为4个6位的片段,然后将每个6位片段映射到一个可打印字符。
- Base64编码主要用于在传输过程中保存二进制数据,例如在电子邮件中传输二进制附件或在网页中嵌入图像。
【1】详解
-
Base64编码原理:
- 将需要编码的数据拆分成3个字节一组(24位)。
- 将这24位按照6位一组进行分割,得到4组6位数字。
- 将每个6位数字转换成对应的ASCII码表示的可打印字符,最后得到4个字符。
- 如果数据不足3个字节,则进行补齐处理。
-
Base64编码表:
-
Base64编码使用64个字符来表示6位数字(0-9,A-Z,a-z,+和/)。
-
由于URL中对特殊字符有限制,所以有时会使用URL安全的Base64编码,将"+"和"/"替换为"-"和"_"。
-
-
Base64编码的应用案例:
- 假设有一个包含如下二进制数据的字符串: "Man"
- 首先,将字符串 "Man" 转换为ASCII码表示的二进制数据: 77, 97, 110。
- 然后,将这三个字节合并为一个24位的二进制数:01001101 01100001 01101110。
- 接下来,将这24位的二进制数按照6位一组拆分组成四组:010011 010110 000101 101110。
- 最后,将每组6位的数字转换为对应的Base64字符:S, 2, F, u。
- 结果就是编码后的Base64字符串:"S2Fu"
- 假设有一个包含如下二进制数据的字符串: "Man"
【2】案例演示
(1)基础版
解释:
-
首先
- 我们导入了Python的base64库,它提供了Base64编码和解码的功能。
-
base64_encode
函数接受一个二进制数据作为输入-
使用
base64.b64encode()
方法对数据进行Base64编码。 -
编码后的结果为字节串类型(bytes)。
-
-
base64_decode
函数接受一个Base64编码后的字节串数据作为输入-
使用
base64.b64decode()
方法对数据进行解码 -
将其还原为原始的二进制数据。
-
-
在示例中,我们使用字符串 "Hello, World!" 进行演示。
-
在进行编码时,原始数据需要以字节串(bytes)的形式传入
-
因此我们使用
b"Hello, World!"
将字符串转换为字节串。
-
-
然后
- 我们分别调用
base64_encode
和base64_decode
函数对原始数据进行编码和解码。
- 我们分别调用
-
最后
- 打印编码和解码的结果。
-
请注意
- 编码后的数据为字节串型
- 解码后的数据与原始数据相同,也是字节串型。
(2)迭代(pack
和unpack
打包数据)
- 使用Python的struct模块中的
pack
和unpack
方法来完善
解释:
-
首先
- 我们仍然使用之前的
base64_encode
和base64_decode
函数对数据进行Base64编码和解码。
- 我们仍然使用之前的
-
现在,我们引入了
pack_data
和unpack_data
两个新的函数。-
pack_data
函数接受一个字节串(bytes)作为输入- 使用
struct.pack("!I", len(data))
将数据长度打包为4个字节的二进制格式,并与原始数据拼接起来,形成打包后的数据。
- 使用
-
unpack_data
函数接受打包后的数据作为输入- 使用
struct.unpack("!I", packed_data[:4])[0]
解包前4个字节的数据长度,并根据长度获取原始数据。
- 使用
-
-
在示例中,我们先将原始数据进行Base64编码,然后将编码结果打包,得到
packed_encoded_data
。 -
接下来,展示了如何使用
unpack_data
函数将打包后的数据解包,并使用base64_decode
函数对解包后的数据进行解码,得到最终的解码结果。
(4)迭代(pad
和unpad
填充)
- 通过使用Python的Padding模块中的
pad
和unpad
方法来完善
解释:
-
首先,我们仍然使用之前的
base64_encode
和base64_decode
函数对数据进行Base64编码和解码。 -
现在,我们引入了
pad_data
和unpad_data
两个新的函数。pad_data
函数接受一个字节串(bytes)作为输入,使用Padding模块的pad
方法对数据进行PKCS7填充,并得到填充后的数据。 -
unpad_data
函数接受填充后的数据作为输入,使用Padding模块的unpad
方法去除PKCS7填充,并返回原始数据。 -
在示例中,我们先将原始数据进行Base64编码,然后对编码结果进行填充,得到
padded_encoded_data
。 -
接下来,展示了如何使用
unpad_data
函数将填充后的数据去除填充,并使用base64_decode
函数对解除填充后的数据进行解码,得到最终的解码结果。
【3】总结:
- Base64编码可以将二进制数据转换为文本形式,方便通过文本传输和展示。
- 但需要注意,Base64编码并不会增加数据安全性,而且会使数据变大约1.33倍。
- 它主要用于在各种场景中,如网络传输、数据存储和数据展示等。
【三】JWT认证和Session认证的区别
- 基于session的认证
- 基于session认证下的集群部署
- 基于JWT认证
- 基于JWT认证下的服务器集群部署
JWT(JSON Web Token)认证和Session认证是两种常见的身份认证机制。它们有一些重要的区别:
【1】会话状态:
- Session认证:
- 在Session认证中,服务器会为每个用户创建一个唯一的会话标识符,并将其存储在服务器端,通常在内存或数据库中。
- 客户端在认证成功后会收到一个Session ID,该ID需要在每次请求中通过Cookie或者其他方式发送给服务器验证。
- 服务器根据Session ID来验证用户的身份并维护会话状态。
- JWT认证:
- 在JWT认证中,服务器不需要在服务器端存储任何会话信息。
- 认证成功后,服务器生成一个JSON Web Token,并将其发送给客户端保存。
- 客户端随后会在每次请求中通过HTTP头部将该Token发送给服务器进行验证。
- 服务器使用密钥对Token进行验证并解析其中的信息来确认用户的身份。
【2】无状态性:
- Session认证:
- 由于服务器需要存储会话信息,Session认证机制被称为有状态(stateful)认证。
- 每次请求都需要服务器在会话存储中查找相关信息,导致服务器的负载较高。
- JWT认证:
- JWT认证机制是无状态(stateless)认证,因为服务器不需要在服务器端存储任何会话信息。
- 服务器只需要对接收到的令牌进行验证即可,这样减轻了服务器负担。
【3】扩展性和跨域支持:
- Session认证:
- 对于大规模分布式系统或者跨域认证,Session认证需要额外的配置和管理。
- 如果用户登录了一个服务器,但又要访问另一个服务器,那么会话信息无法共享,需要特殊处理来实现跨域认证。
- JWT认证:
- 由于JWT是基于Token的,它可以被跨域传送并在不同服务之间共享。
- 这使得JWT更容易在分布式系统中实现认证,并且适用于跨域的场景。
【4】安全性:
- Session认证:
- 由于服务器存储会话信息,一旦服务器被攻破或者会话信息被窃取,可能会导致安全问题。
- JWT认证:
- JWT通过数字签名的方式保证了数据的完整性和真实性。
- 只有使用密钥签名的Token才能被服务器接受,因此更难以伪造或篡改。
- 然而,如果令牌在传输过程中被拦截,则攻击者可以解码其中的信息,因此在使用JWT时需要采取适当的安全措施,如使用HTTPS等。
【四】JWT三段式
- JWT(JSON Web Token)是一种用于身份认证和授权的开放标准(RFC 7519)。
- 它基于JSON格式定义了一种安全的令牌,用于在客户端和服务器之间传输信息。
JWT由三个部分组成:头部(Header)、载荷(Payload)和签名(Signature):
【1】头部(Header):
-
头部通常由两部分组成:
- 令牌类型和算法。
- 令牌类型通常为"JWT"。
- 算法定义了用于生成签名的算法,例如HMAC、RSA或者ECDSA等。
-
示例:
【2】载荷(Payload):
- 载荷包含了关于用户或实体的声明和其他附加信息。
- JWT规范定义了一些标准的声明(例如:iss-签发者、exp-过期时间、sub-主题、aud-受众),并且允许自定义声明。
- 示例:
【3】签名(Signature):
- 签名是将头部和载荷进行签名,以确保令牌的完整性和真实性。
- 签名通常使用密钥进行加密,以防止其被篡改。
- 服务器在接收到请求时使用同样的密钥对签名进行验证。
- 示例:
【4】最终的JWT
- 由上述三个部分用
.
拼成一个完整的字符串,构成最终的JWT
【五】JWT开发流程
【1】JWT工作流程如下:
- 用户向服务器发送登录请求,提供用户名和密码。
- 服务器验证用户凭证,如果通过验证,生成JWT并将其返回给客户端。
- 客户端收到JWT后,保存在本地(通常在本地存储或者Cookie中)。
- 客户端每次访问受限资源时,在请求头中附带JWT。
- 服务器接收到请求后,使用相同的密钥解析JWT,验证其有效性和完整性,然后根据需要执行相应的操作。
【2】JWT开发流程
第一部分:签发token的过程(登录)
- 用户携带用户名和密码,访问我,我们校验通过,生成token串,返回给前端
- 用户携带用户名和密码访问应用后端。
- 应用后端校验用户提供的用户名和密码是否正确。
- 如果校验通过,应用后端生成一个JWT Token,并将其返回给前端。
- JWT Token包含三个部分:Header、Payload和Signature。
- Header包含了关于Token类型和所使用的算法的信息。
- Payload包含了要传递的数据,例如用户ID、角色等。
- Signature是使用密钥对Header和Payload进行签名的结果,用于验证Token的真实性。
- 这些部分通常会经过Base64编码组合成一个字符串。
- 前端收到JWT Token后,可以将其保存在本地
- 例如LocalStorage或者Cookie中,在后续需要使用Token的请求中携带它。
第二部分:token认证过程
token认证过程,登录认证时使用,其实就是咱们之前讲的认证类,在认证类中完成对token的认证操作
用户访问我们需要登陆后才能访问的接口,必须携带我们签发的token串(请求头)
我们取出token,验证该token是否过期,是否被篡改,是否是伪造的
如果正常,说明荷载中的数据,就是安全的,可以根据荷载中的用户id,查询出当前登录用户,放到request中即可
- 用户访问需要登录才能访问的接口,请求头中携带JWT Token。
- 后端从请求头中获取JWT Token。
- 后端对Token进行解析和验证,确保Token的完整性和真实性。
- 验证Token的完整性可以通过验签来实现,即使用密钥对Token的签名部分进行验证。
- 验证Token的真实性可以通过检查Token的有效期以及其他业务逻辑来实现。
- 如果Token验证通过,后端能够从Token的Payload部分获取到用户的相关信息,例如用户ID。
- 后端可以根据用户ID查询数据库或其他存储系统,获取该用户的详细信息。
- 后端将获取到的用户信息添加到请求的上下文中,以便后续的处理逻辑可以使用该信息进行权限控制、数据处理等操作。
【六】JWT的优点包括:
- 简洁:由于使用JSON格式,JWT具有易读性和可理解性。
- 自包含:JWT中包含了所有必要的信息,减少服务器端的存储开销。
- 可扩展:JWT允许自定义声明来满足特定需求。
- 跨域支持:JWT可以在不同域之间进行传递,并实现跨域认证。
然而,使用JWT需要注意以下几点:
- JWT无法撤销:一旦JWT被签发,就无法主动撤销,只能等待过期时间到达或者通过其他方式进行处理。
- 令牌大小:由于JWT包含载荷信息,其大小较大,可能会影响网络传输和存储开销。
总结来说,JWT是一种灵活且安全的身份认证和授权机制,可以用于构建分布式系统和跨域认证场景。但在使用时需注意安全性和令牌的大小。
【七】Django + JWT 快速使用
-
使用第三方模块
-
我们可以自己封装
【1】安装
【2】签发过程
- 登录过程(快速签发)
- 登录接口
- 在URL路由中添加登录接口路径,使用
obtain_jwt_token
函数进行用户身份验证并签发JWT Token。
- 在URL路由中添加登录接口路径,使用
- 基于 auth 的user表签发
- 登录接口
-
{{host}}login/
【3】总结
【1】签发:只需要在路由中配置
- 在路由中配置登录接口路径,使用
obtain_jwt_token
函数进行用户身份验证并签发JWT Token。
【2】认证:视图类上加
- 使用JWT认证方法需要在视图类中添加相应的认证类和权限类。
- 认证类:
JSONWebTokenAuthentication
,该类提供了JWT的认证功能。- 权限类:
IsAuthenticated
,该类用于验证请求是否来自已认证的用户。
- 访问的时候,要在请求头中携带,必须叫
Authorization
:jwt token串
【八】Django + JWT 定制返回格式
-
登录签发token的接口,要返回code,msg,username,token等信息
-
写个函数,函数返回字典格式,返回的格式,会被序列化,前端看到
-
写的函数配置一下
【九】Django + JWT 自定义用户表签发
【1】创建用户表
【2】登录接口
- 路由
- 视图
-
携带错误信息
{{host}}login/
-
携带正确信息
{{host}}login/
【九】Django + JWT 自定义认证类
- drf的认证类定义方式
- 在认证类中,自己写逻辑
- 视图
- 路由
-
不携带token/错误toke
【十】Django + JWT 的签发源码分析
- 引入了
rest_framework_jwt
模块,并且使用了obtain_jwt_token
函数,该函数实际上是ObtainJSONWebToken.as_view()
方法的别名。JSONWebTokenAPIView
是一个API视图类,继承自rest_framework
框架的APIView
类。
- 它用于处理接收到的包含用户用户名和密码的POST请求,并返回一个JSON Web Token,该令牌可以用于后续的身份验证请求。
obtain_jwt_token
---->ObtainJSONWebToken.as_view()
JSONWebTokenAPIView
的serializer_class
属性指定了用于序列化和验证用户输入的数据的序列化器类
- 这里使用的是
JSONWebTokenSerializer
。
JSONWebTokenAPIView
permission_classes
和authentication_classes
字段:
- 这两个字段用于定义API视图的权限和认证类,默认情况下为空元组,即没有任何限制和认证要求。
get_serializer_context
方法:
- 此方法返回给序列化器类的额外上下文信息。
- 默认情况下,提供了
request
和view
信息作为上下文。get_serializer_class
方法:
- 该方法返回用于序列化的类。
- 默认情况下使用
self.serializer_class
字段的值。- 如果需要根据请求的不同提供不同的序列化方式,可以重写此方法。
get_serializer
方法:
- 该方法返回一个序列化器的实例,用于验证、反序列化输入和序列化输出。
- 首先通过
get_serializer_class
方法获取序列化器类。- 然后将额外的上下文信息传递给序列化器实例的
context
参数。- 最后返回序列化器的实例。
post
方法:
- 这是处理POST请求的方法,负责签发JWT令牌。
- 首先通过
self.get_serializer(data=request.data)
获取序列化器的实例。- 利用序列化器的
is_valid()
方法对请求数据进行校验,包括全局钩子和字段自定义的校验规则。- 如果校验通过,从序列化器中获取用户对象和令牌对象。
- 接下来调用
jwt_response_payload_handler
方法自定义返回格式,并将令牌、用户和请求作为参数传递给它,获取返回数据字典。- 创建一个响应对象,将返回数据作为内容进行响应。
- 如果配置文件中使用了JWT的cookie认证(
api_settings.JWT_AUTH_COOKIE
),则设置JWT的cookie,设置过期时间为当前时间加上JWT的过期时间差(api_settings.JWT_EXPIRATION_DELTA
)。- 最后返回响应对象。
- 如果校验失败,返回错误信息和HTTP 400错误状态码的响应。
JSONWebTokenSerializer
的全局钩子/局部钩子- 全局钩子
上述代码是一个JSONWebTokenSerializer的全局钩子(validate方法)。
- 在该代码段中,validate方法接收前端传入的经过验证的数据(attrs),然后提取用户名和密码,并进行用户认证。
首先,定义了一个credentials字典,其中包含用户名(self.username_field)和密码('password')。
- 通过attrs.get()方法从前端传入的数据中获取对应的值,并将其赋给credentials字典中的相应键。
接下来,使用all()函数判断credentials字典中的值是否全部存在(即用户名和密码都不为空)。
- 如果是,则调用authenticate()函数进行用户认证。
authenticate()函数是在Django的auth模块中进行用户名和密码认证的函数。
- 它接收用户名和密码作为参数,在auth的user表中校验用户是否存在。
- 相当于执行了类似于User.objects.filter(username=username, password=加密后的密码).first()的查询,返回用户对象。
如果用户认证成功,继续进行进一步的操作。
- 首先判断用户是否激活,如果用户未激活,则抛出ValidationError异常,提示用户账户已被禁用。
接着,生成payload(有效载荷)对象,该对象包含了用户的信息。然后,通过jwt_encode_handler()函数对payload进行加密处理,得到一个token。
- 最后,将token和user对象作为字典返回。
如果用户认证失败,则抛出ValidationError异常,提示无法使用提供的凭据登录。
如果credentials字典中的值存在空值(即用户名或密码为空),则抛出ValidationError异常,提醒必须包含用户名和密码。
总结:该全局钩子的作用是对前端传入的数据进行校验和用户认证,并返回包含token和用户信息的字典。如果验证或认证失败,则抛出相应的异常。
【十一】Django + JWT 的认证源码分析
JSONWebTokenAuthentication
get_jwt_value(self, request)
:
- 这个方法用于从请求中获取JWT值。
- 首先,通过
get_authorization_header(request)
获取请求的Authorization header,并使用split()
方法分割字符串,得到一个包含两个元素的列表,分别是认证类型和token。- 然后,检查认证类型是否与设置中的
JWT_AUTH_HEADER_PREFIX
相匹配,如果不匹配则返回None
。- 接着,判断列表的长度,如果长度为1,则说明没有提供credentials,抛出
AuthenticationFailed
异常。- 如果长度大于2,则说明credentials中包含了空格,也不符合格式要求,同样抛出异常。
- 最后,返回提取到的token。
authenticate_header(self, request)
:
- 这个方法用于指定在
401 Unauthenticated
响应中WWW-Authenticate
头部的值。- 返回的字符串格式为
"JWT_AUTH_HEADER_PREFIX realm="api"
。
- 父类
BaseJSONWebTokenAuthentication
中的authenticate
方法
- 上述代码是一个基于JSON Web Token(JWT)的身份验证类
BaseJSONWebTokenAuthentication
,它继承自Django框架中的BaseAuthentication
类。
- 该类是用于实现基于JWT标准的身份验证。
- 这个类中最重要的方法是
authenticate
方法
- 它接受一个
request
对象作为参数,并返回一个包含User
和token的元组- 如果提供了有效的签名进行了JWT身份验证。否则,返回
None
。- 在
authenticate
方法中
- 首先通过调用
get_jwt_value
方法从请求中获取jwt_value,该方法从请求头或查询字符串中获取jwt token值。- 如果没有传入jwt token,则返回
None
。- 接下来
authenticate
方法尝试使用jwt_decode_handler
方法解码jwt token。- 如果解码失败,可能是由于过期、无效的签名等原因,将抛出
exceptions.AuthenticationFailed
异常。- 然后
- 通过调用
authenticate_credentials
方法,传入解码后的payload来获取与当前用户匹配的活跃用户。- 这里调用了Django自带的
get_user_model
方法获取用户模型并执行查询。- 如果没有找到指定的用户,将抛出
exceptions.AuthenticationFailed
异常。- 最后
- 将获取到的用户和jwt token一起返回。
- 这样,在视图中使用这个身份验证类时,可以通过访问
request.user
属性获得当前登录的用户对象。- 需要注意的是
- 如果前端没有传入jwt token,即
jwt_value
为None
,则直接返回None
,在后续的视图处理中无法控制登录用户。- 因此,在使用该身份验证类时,应结合权限类来进行进一步控制和限制。
jwt_get_username_from_payload(payload)
- 上述代码是一个身份验证函数
authenticate_credentials
,用于验证JWT (JSON Web Token) 的凭证信息。- 以下是对代码功能的详解:
- 首先,通过调用
get_user_model()
函数获取用户模型(User Model)。- 通过调用
jwt_get_username_from_payload(payload)
函数从JWT的负载中获取用户名。- 如果未能成功获取到用户名,会抛出
exceptions.AuthenticationFailed
异常,并返回一个"Invalid payload."的错误消息。- 接下来,使用
User.objects.get_by_natural_key(username)
方法查询与获取到的用户名匹配的活跃用户。- 如果找不到对应的用户,则会抛出
User.DoesNotExist
异常,并返回一个"Invalid signature."的错误消息。- 如果查询到的用户不是处于激活状态,则会抛出
exceptions.AuthenticationFailed
异常,并返回一个"User account is disabled."的错误消息。- 如果用户验证通过,则返回验证成功的用户对象。
- 这段代码的作用是根据JWT的payload中的用户信息进行用户身份验证,返回对应的已验证和激活的用户对象。
- 如果用户不携带token,也能认证通过
- 所以我们必须加个权限类来限制
- 上述代码是一个用于限制用户权限的权限类
IsAuthenticated
- 用于确保用户必须携带有效的身份认证信息(如JWT token)才能通过权限验证。
- 以下是对代码功能的详解:
IsAuth}enticated
是从Django Rest Framework中的BasePermission
类继承而来的自定义权限类,用于验证用户是否已经通过了认证和授权。has_permission
是权限类的方法,用于判断请求是否有权限执行相应的操作。- 在
has_permission
方法中,首先通过request.user
获取当前请求的用户对象。- 然后使用
request.user.is_authenticated
判断用户是否已经进行了身份认证,即用户是否处于登录状态。- 如果
request.user
存在且request.user.is_authenticated
为True,则返回True,表示用户具有权限。- 如果
request.user
不存在或request.user.is_authenticated
为False,则返回False,表示用户没有权限。- 在视图中使用该权限类,在需要限制权限的接口上添加
permission_classes = [IsAuthenticated]
即可实现只允许已认证用户访问的控制。- 该权限类的作用是在用户进行请求时,检查用户是否已经通过了身份认证
- 如果认证通过则返回True,否则返回False,从而实现对未认证用户的权限限制。
__EOF__

本文链接:https://www.cnblogs.com/dream-ze/p/17594603.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17594603.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY