Django之JWT库与SimpleJWT库的使用

Django之JWT库与SimpleJWT库的使用

  • JWT
    • JWT概述
    • 头部(header)
    • 载荷(payload)
    • 签名(signature)
  • Django使用JWT说明
  • jwt库的使用
    • 安装依赖库
    • 配置settings.py文件
    • 配置urls.py文件
    • 创建视图
    • 配置权限
  • SimpleJWT库的使用
    • 安装SimpleJWT库
    • 配置Django项目
    • 配置路由
    • 创建用户
    • 接口测试
    • 身份认证
    • 自定义令牌声明
    • 手动创建令牌
  • SimpleJWT的应用
    • 实现用户身份验证和JWT token的生成
    • 登录实现
    • 注册实现
    • Token验证

JWT

JWT概述

JWT(JSON Web Token)是一种轻量级的认证和授权机制,它是基于 JSON 格式的标准,用于在网络应用程序或服务之间传递声明。

JWT官网:https://jwt.io/

特点:

无状态:JWT 在服务器端不保存任何信息,因此可以跨多个请求进行身份验证。自包含:JWT 包含了所有必要的信息,这样不需要去查询数据库或其他存储设施来验证用户身份。可扩展性:由于 JWT 是基于 JSON 格式的标准,因此可以很容易地扩展以添加自定义数据。强安全性:JWT 使用数字签名来验证消息的完整性和真实性,这样可以确保消息没有被篡改。跨域支持:由于 JWT 是通过 HTTP 头部传输的,因此可以轻松地在跨域场景中使用。

主要应用:

JWT通常用于身份验证和授权。当用户成功登录时,服务器会生成一个 JWT,并将其返回给客户端。客户端随后将该令牌放入每个后续请求的Authorization标头中,以证明其已通过身份验证。服务器使用私钥来验证签名,并从 JWT 中提取必要的信息,例如用户 ID 和权限。

JWT组成:

JWT由三部分组成:头部、载荷和签名。

1.头部包含关于生成 JWT的算法和类型的元数据。2.载荷是JWT的主体内容,它包含有关用户或其他实体的信息,例如其 ID 或角色。3.签名是使用密钥对头部和载荷进行加密的字符串,以确保JWT 在传输过程中不被篡改。

一个JWT Token字符串,由3部分组成,用.隔开

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

头部(header)

JWT的头部承载两部分信息:

声明类型,这里是jwt声明加密的算法 通常直接使用HMAC SHA256
{"alg": "HS256","typ": "JWT"
}

将头部进行base64加密构成了第一部分

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

载荷(payload)

载荷就是存放有效信息的地方。有效信息包含三个部分

1.标准中注册的声明(建议但不强制使用) :

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

2.公共的声明

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密

3.私有的声明

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

{"sub": "1234567890","name": "John Doe","iat": 1656239122
}

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

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ

签名(signature)

JWT的第三部分是一个签名信息,用来防止JWT token被伪造。

签名生成过程:

1.服务器在生成jwt token时,会将header和payload字符串进行拼接,用.隔开2.使用一个只有服务器知道的密钥对拼接后的内容进行加密,加密之后生成的字符串就是signature内容

签名验证过程:

1.将客户端传递的jwt token中的header和payload字符串进行拼接,用.隔开2.使用服务器自己的密钥对拼接之后的字符串进行加密3.将加密之后的内容和将客户端传递的jwt token中signature进行对比,如果不一致,就说明jwt token是被伪造的
HMACSHA256(base64UrlEncode(header) + "." +base64UrlEncode(payload),256-bit-secret
)

注意:

不要在jwt的payload部分存放敏感信息,客户端可解密得到保护好secret密钥,使用https协议

在这里插入图片描述

Django使用JWT说明

在Python项目中使用JWT生成和校验Token,可以使用django-rest-framework-jwtdjangorestframework-simplejwt扩展来完成。

django-rest-framework-jwt

  • GitHub地址:https://github.com/jpadilla/django-rest-framework-jwt

  • 文档:https://jpadilla.github.io/django-rest-framework-jwt/

djangorestframework-simplejwt

  • GitHub地址:https://github.com/jazzband/djangorestframework-simplejwt
  • 文档:https://django-rest-framework-simplejwt.readthedocs.io/en/latest/

注意:django-rest-framework-jwt不再维护,且适合低版本框架使用,若使用最新版本的Django和DRF如果使用JSON Web Token,项目启动会报错

ImportError: Could not import 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' for API setting 'DEFAULT_AUTHENTICATION_CLASSES'. ImportError: cannot import name 'smart_text' from 'django.utils.encoding'

jwt库的使用

安装依赖库

使用pip命令安装djangorestframework-jwt

pip install djangorestframework-jwt

配置settings.py文件

添加以下内容到INSTALLED_APPS和REST_FRAMEWORK配置中

INSTALLED_APPS = [...'rest_framework',
]
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': (# 引入JWT认证机制,当客户端将jwt token传递给服务器之后# 此认证机制会自动校验jwt token的有效性,无效会直接返回401(未认证错误)'rest_framework_jwt.authentication.JSONWebTokenAuthentication','rest_framework.authentication.SessionAuthentication','rest_framework.authentication.BasicAuthentication',),
}# JWT扩展配置
JWT_AUTH = {# 设置生成jwt token的有效时间'JWT_EXPIRATION_DELTA': datetime.timedelta(days=1),
}

其他可选配置项:

 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),  # 访问令牌的有效时间'REFRESH_TOKEN_LIFETIME': timedelta(days=1),    # 刷新令牌的有效时间'ROTATE_REFRESH_TOKENS': False,     # 若为True,则刷新后新的refresh_token有更新的有效时间'BLACKLIST_AFTER_ROTATION': True,   # 若为True,刷新后的token将添加到黑名单中, # When True,'rest_framework_simplejwt.token_blacklist',should add to INSTALLED_APPS'ALGORITHM': 'HS256',       # 对称算法:HS256 HS384 HS512  非对称算法:RSA'SIGNING_KEY': SECRET_KEY,'VERIFYING_KEY': None,      # if signing_key, verifying_key will be ignore.'AUDIENCE': None,'ISSUER': None,'AUTH_HEADER_TYPES': ('Bearer',),           # Authorization: Bearer <token>'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',   # if HTTP_X_ACCESS_TOKEN, X_ACCESS_TOKEN: Bearer <token>'USER_ID_FIELD': 'id',                      # 使用唯一不变的数据库字段,将包含在生成的令牌中以标识用户'USER_ID_CLAIM': 'user_id',# 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),   # default: access# 'TOKEN_TYPE_CLAIM': 'token_type',         # 用于存储令牌唯一标识符的声明名称 value:'access','sliding','refresh'## 'JTI_CLAIM': 'jti',## 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',     # 滑动令牌是既包含到期声明又包含刷新到期声明的令牌# 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),       # 只要滑动令牌的到期声明中的时间戳未通过,就可以用来证明身份验证# 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),  # path('token|refresh', TokenObtainSlidingView.as_view())

配置urls.py文件

配置urls.py文件,添加以下路由配置

from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_tokenurlpatterns = [path('api-token-auth/', obtain_jwt_token),path('api-token-refresh/', refresh_jwt_token),path('api-token-verify/', verify_jwt_token),
]

创建视图

创建自定义视图以生成JWT令牌

JWT扩展的提供了生成JWT Token的方法:

from rest_framework_jwt.settings import api_settingsdata = {"name": "Django", "name": "20"}
payload = api_settings.JWT_PAYLOAD_HANDLER(user)
jwt_token = api_settings.JWT_ENCODE_HANDLER(payload)
from rest_framework_jwt.settings import api_settings# 继承JSONWebTokenAPIView,使用CustomJWTSerializer进行序列化和验证
class CustomObtainJSONWebToken(JSONWebTokenAPIView):serializer_class = CustomJWTSerializerclass CustomJWTSerializer(JSONWebTokenSerializer):# validate 方法对提交的用户凭据进行验证,如果验证通过则生成 JWT token 并返回给客户端def validate(self, attrs):# 从请求中获取用户名和密码credentials = {self.username_field: attrs.get(self.username_field),'password': attrs.get('password')}# 通过 Django 自带的 authenticate 函数进行认证if all(credentials.values()):user = authenticate(**credentials)if user:# 检查该用户是否处于活跃状态,如果被禁用则返回错误信息if not user.is_active:raise serializers.ValidationError('User account is disabled.')# 生成JWT的payload(负载)payload = api_settings.JWT_PAYLOAD_HANDLER(user)# 生成JWT tokenjwt_token = api_settings.JWT_ENCODE_HANDLER(payload)response_data = {'token': jwt_token,}# 将生成的 JWT token 返回给客户端return response_dataelse:raise serializers.ValidationError('Unable to log in with provided credentials.')else:raise serializers.ValidationError('Must include "{username_field}" and "password".'.format(username_field=self.username_field))

配置权限

在视图中使用 @permission_classes 装饰器指定需要验证的权限。

from rest_framework.permissions import IsAuthenticatedclass CustomView(APIView):permission_classes = (IsAuthenticated,)

SimpleJWT库的使用

安装SimpleJWT库

通过pip命令安装SimpleJWT库:

pip install djangorestframework-simplejwt

配置Django项目

在settings.py文件中添加以下配置:

INSTALLED_APPS = ['rest_framework','rest_framework_simplejwt',
]
REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': (# 将全局权限控制方案设置为仅允许认证用户访问'rest_framework.permissions.IsAuthenticated',),'DEFAULT_AUTHENTICATION_CLASSES': (# JWT认证:使用SimpleJWT库提供的JWTAuthentication类来进行认证'rest_framework_simplejwt.authentication.JWTAuthentication',# sesssion认证'rest_framework.authentication.SessionAuthentication',# 基本认证'rest_framework.authentication.BasicAuthentication',),
}
SIMPLE_JWT = {# token有效时长(返回的 access 有效时长)'ACCESS_TOKEN_LIFETIME': datetime.timedelta(seconds=30),# token刷新的有效时间(返回的 refresh 有效时长)'REFRESH_TOKEN_LIFETIME': datetime.timedelta(seconds=20),
}

更多Simple JWT的配置参考: https://django-rest-framework-simplejwt.readthedocs.io/en/latest/settings.html

配置路由

配置项目级路由

from django.urls import path, include, re_pathurlpatterns = [path('admin/', include(('apps.admin.urls', 'admin'), namespace="admin")),
]

配置子应用JWT视图的路由

from django.urls import include, path
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyViewurlpatterns = [path('login/', TokenObtainPairView.as_view(), name='token_obtain_pair'),path('refresh/', TokenRefreshView.as_view(), name='token_refresh'),path('verify/', TokenVerifyView.as_view(), name='token_verify'),
]

上面视图路由使用的是使用JWT自身的类,也可以自定义视图实现相关功能

from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework_simplejwt.tokens import AccessToken, RefreshToken
from rest_framework.permissions import IsAuthenticatedclass TokenObtainView(APIView):# 视图需要被认证才能访问permission_classes = [IsAuthenticated]def post(self, request):# 使用了SimpleJWT提供的AccessTokenRefreshToken类,为认证成功的用户生成对应的JWT令牌access_token = AccessToken.for_user(request.user)refresh_token = RefreshToken.for_user(request.user)return Response({'access_token': str(access_token),'refresh_token': str(refresh_token),})
from django.urls import path
from .views import TokenObtainViewurlpatterns = [path('api/token/', TokenObtainView.as_view(), name='token_obtain'),
]

创建用户

使用Django自带用户认证系统,创建一个用户,用于登录

import osfrom django.test import TestCasefrom django.contrib.auth.models import User
if not os.environ.get('DJANGO_SETTINGS_MODULE'):os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'meiduo_mall.settings')import django
django.setup()class MyTest(TestCase):User.objects.create_user(username='admin', password='admin')

接口测试

1.访问login
在这里插入图片描述
2.登录
在这里插入图片描述
登录接口,返回refresh和access值

refresh用来刷新获取新的Token值access用来请求身份认证的Tokenaccess的过期时间参照配置ACCESS_TOKEN_LIFETIMErefresh的过期时间参照配置REFRESH_TOKEN_LIFETIME

当用refresh刷新后,access的过期时间等于:当前刷新的此刻时间+ACCESS_TOKEN_LIFETIME

3.Token校验
使用登录接口返回的access值,调用Token校验接口
在这里插入图片描述
4.刷新Token

使用登录接口返回的refresh值,调用Token刷新接口

当此短期访问令牌过期时,可以使用长期存在的刷新令牌来获取另一个访问令牌:
在这里插入图片描述

身份认证

使用返回的访问令牌来证明受保护视图的身份验证

path('test/', TestView.as_view(), name='test'),
from rest_framework.response import Response
from rest_framework.views import APIViewclass TestView(APIView):def get(self, request):return Response("tet successfully")

在这里插入图片描述

在这里插入图片描述

在请求头加上Authorization,格式:Bearer [token值] 有空格
在这里插入图片描述

自定义令牌声明

自定义令牌需要视图创建一个子类,并为其相应的序列化程序创建一个子类

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairViewclass MyTokenObtainPairSerializer(TokenObtainPairSerializer):def validate(self, attrs):data = super().validate(attrs)refresh = self.get_token(self.user)data['refresh'] = str(refresh)data['access'] = str(refresh.access_token)data['username'] = self.user.usernamereturn dataclass MyTokenObtainPairView(TokenObtainPairView):serializer_class = MyTokenObtainPairSerializer

配置指向子类视图的url路由

re_path(r'^login/$', views.MyTokenObtainPairView.as_view()),

在这里插入图片描述

手动创建令牌

为用户手动创建令牌,例如用户注册,注册完后直接返回token

class MyCreateTokenView(APIView):permission_classes = [permissions.AllowAny]def get(self, request, *args, **kwargs):return Response("Get method is not supported !")def post(self, request, *args, **kwargs):refresh = RefreshToken.for_user(request.user)content = {'refresh': str(refresh),'access': str(refresh.access_token),}return Response(content)
    re_path(r'^register/$', views.MyCreateTokenView.as_view()),

在这里插入图片描述

SimpleJWT的应用

实现用户身份验证和JWT token的生成

from django.contrib.auth.models import User
from django.utils import timezone
from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.tokens import RefreshTokenclass AuthSerializer(TokenObtainPairSerializer):id = serializers.IntegerField(label='用户ID', read_only=True)username = serializers.CharField(label='用户名')token = serializers.CharField(label='Token', read_only=True)refresh = serializers.CharField(label='Refresh', read_only=True)# 从attrs参数中获取到传入的用户名和密码def validate(self, attrs):# 获取username和passwordusername = attrs['username']password = attrs['password']# 进行用户名和密码校验try:user = User.objects.get(username=username)except User.DoesNotExist:raise serializers.ValidationError('用户名或密码错误.')else:# 校验密码if not user.check_password(password):raise serializers.ValidationError('用户名或密码错误')# 给attrs中添加user属性,保存登录用户attrs['user'] = userreturn attrsdef create(self, validated_data):# 获取登录用户useruser = validated_data['user']# 设置最新登录时间user.last_login = timezone.now()user.save()refresh = RefreshToken.for_user(user)# 给user对象增加属性,保存jwt token的数据user.refresh = str(refresh)user.token = str(refresh.access_token)return user

登录实现

创建了AuthSerializer对象,并将POST请求的参数传入进行校验。如果校验通过,则调用serializer.save()方法生成JWT token,并将token数据作为响应返回。

from rest_framework import status
from rest_framework.generics import CreateAPIView
from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from rest_framework.views import APIViewfrom apps.zd_admin.serializers.user import AuthSerializerclass LoginView1(APIView):permission_classes = [AllowAny]def post(self, request):# 获取参数并进行校验serializer = AuthSerializer(data=request.data)serializer.is_valid(raise_exception=True)# 调用序列化器类的create方法,实现服务器签发jwt tokenserializer.save()return Response(serializer.data, status=status.HTTP_201_CREATED)class LoginView(CreateAPIView):permission_classes = [AllowAny]serializer_class = AuthSerializer
urlpatterns = [re_path(r'^login/$', views.LoginView.as_view()),
]

在这里插入图片描述

注册实现

注册接口进行注册返回token认证信息也是同理

 re_path(r'^register/$', views.RegisterView.as_view()),
class RegisterView(APIView):permission_classes = [AllowAny]def post(self, request):user = request.datausername = user['username']password = user['password']# 保存注册数据try:user = User.objects.create_user(username=username, password=password)except DatabaseError:raise serializers.ValidationError('注册失败')refresh = RefreshToken.for_user(user)user = {"username": user.username, "token": str(refresh.access_token), "refresh": str(refresh)}return JsonResponse(user)

在这里插入图片描述

Token验证

使用登录、注册得到的Token随着请求携带进行测试

re_path(r'^test/$', views.TestView.as_view()),
class TestView(APIView):def get(self, request):return Response("tet successfully")

在这里插入图片描述

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

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

相关文章

c++--二叉树应用

1.根据二叉树创建字符串 力扣 给你二叉树的根节点 root &#xff0c;请你采用前序遍历的方式&#xff0c;将二叉树转化为一个由括号和整数组成的字符串&#xff0c;返回构造出的字符串。 空节点使用一对空括号对 "()" 表示&#xff0c;转化后需要省略所有不影响字符…

SpringBoot集成百度人脸识别实现登陆注册功能Demo(二)

前言 上一篇SpringBoot集成百度人脸demo中我使用的是调用本机摄像头完成人脸注册&#xff0c;本次demo根据业务需求的不同我采用文件上传的方式实现人脸注册。 效果演示 注册 后端响应数据&#xff1a; 登录 后端响应数据&#xff1a; 项目结构 后端代码实现 1、BaiduAiUtil…

SQL 表别名 和 列别名

列表名 列表名之后 order by 可以用别名 也可以用原名&#xff0c; where 中不能用别名的 SQL语句执行顺序&#xff1a; from–>where–>group by -->having — >select --> order 第一步&#xff1a;from语句&#xff0c;选择要操作的表。 第二步&#xff1…

Bug的严重等级和优先级别与分类

一、 Bug的严重等级定义&#xff1a; 1、 Blocker 即系统无法执行、崩溃或严重资源不足、应用模块无法启动或异常退出、无法测试、造成系统不稳定。 严重花屏内存泄漏 用户数据丢失或破坏系统崩溃/死机/冻结模块无法启动或异常退出严重的数值计算错误功能设计与需求严重不符其…

每日一学:什么是 Harbor ?

目录 什么是 Harbor &#xff1f; 一、Harbor 的优势 二、Harbor 架构构成 三、Core services 这是 Harbor 的核心功能 什么是 Harbor &#xff1f; Harbor 是 VMware 公司开源的企业级 Docker Registry 项目&#xff0c;其目标是帮助用户迅速搭建一个企业级的 Docker Reg…

Spring MVCSpring Boot

文章目录 Spring MVC什么是MVC模式Spring MVC优点SpringMVC 运行流程SpringMVC组件SpringMVC常用的注解有哪些SpringMVC的拦截器和过滤器有什么区别&#xff1f;执行顺序是什么 SpringBoot对SpringBoot的理解Spring和SpringBoot的关系&#xff1f;SpringBoot有哪些核心注解Spri…

【PDF密码】PDF文件不能打印,为什么?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…

react icon ant简单使用

refer&#xff1a; 文字提示 Tooltip - Ant Design 1.首先保证已经引入了Ant 2.在组件&#xff08;页面&#xff09;引入tooltip import { Form, Tooltip } from antd; 3.在合适的位置使用tooltip&#xff1a; <span>寿命 <Tooltip title"这是寿命的说明&quo…

前端 select 标签如何创建下拉菜单?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 代码示例⭐ 代码讲解⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏…

【Linux】计算机网络的背景和协议分层

文章目录 网络发展协议何为协议网络协议协议分层OSI七层模型TCP/IP五层模型&#xff08;四层&#xff09; 基本通信流程mac地址和ip地址网络通信本质 网络发展 从一开始计算机作为一台台单机使用&#xff0c;到现在网络飞速发展&#xff0c;从局域网Lan建立起局域网&#xff0…

Vue3 第四节 自定义hook函数以及组合式API

1.自定义hook函数 2.toRef和toRefs 3.shallowRef和shallowReactive 4.readonly和shallowReadonly 5.toRaw和markRaw 6.customref 一.自定义hook函数 ① 本质是一个函数&#xff0c;把setup函数中使用的Composition API 进行了封装,类似于vue2.x中的mixin 自定义hook函数…

TCP和UDP

目录 TCP和UDP是什么&#xff1f; TCP和UDP有什么区别? 三次握手和四次挥手 TCP维护可靠的通信方式 拥塞控制 滑动窗口的原理 什么是粘包以及粘包的原因 粘包的处理方式 TCP和UDP使用场景 TCP和UDP是什么&#xff1f; TCP&#xff1a; 传输控制协议&#xff08;TCP&am…

Maven介绍-下载-安装-使用-基础知识

Maven介绍-下载-安装-使用-基础知识 Maven的进阶高级用法可查看这篇文章&#xff1a; Maven分模块-继承-聚合-私服的高级用法 文章目录 Maven介绍-下载-安装-使用-基础知识01. Maven1.1 初识Maven1.1.1 什么是Maven1.1.2 Maven的作用 02. Maven概述2.1 Maven介绍2.2 Maven模型…

postgresql|数据库|MySQL数据库向postgresql数据库迁移的工具pgloader的部署和初步使用

前言&#xff1a; MySQL数据库和postgresql数据库之间的差异并不多&#xff0c;这里的差异指的是对SQL语言的支持两者并不大&#xff0c;但底层的东西差异是非常多的&#xff0c;例如&#xff0c;MySQL的innodb引擎概念&#xff0c;数据库用户管理&#xff0c;这些和postgresq…

【设计模式】-建造者模式

Java建造者模式&#xff1a;创建复杂对象的灵活构建者 在软件开发中&#xff0c;我们经常遇到需要创建一个复杂对象的情况。如果使用传统的构造函数进行对象创建&#xff0c;可能会导致构造函数参数过多&#xff0c;难以管理和维护。建造者模式&#xff08;Builder Pattern&am…

使用eXosip+ffmpeg、ffplay命令行实现sip客户端

文章目录 前言一、关键实现1、主要流程2、解决端口冲突&#xff08;1&#xff09;、出现原因&#xff08;2&#xff09;、解决方法 3、解析sdp&#xff08;1&#xff09;、定义实体&#xff08;2&#xff09;、解析视频&#xff08;3&#xff09;、解析音频 4、命令行推拉流&am…

Ctfshow web入门 XXE 模板注入篇 web373-web378 详细题解 全

CTFshow XXE web373 学习资料&#xff1a; &#xff08;梭哈~&#xff09; https://www.cnblogs.com/20175211lyz/p/11413335.html https://www.cnblogs.com/zhaijiahui/p/9147595.html https://www.cnblogs.com/r00tuser/p/7255939.html https://mp.weixin.qq.com/s?__bizMz…

stable diffusion(1): webui的本地部署(windows)

一、前言 是的&#xff0c;现在是202308月份了&#xff0c;网上已经有很多打包好的工具&#xff0c;或者直接进一个web就能用SD的功能&#xff0c;但是我们作为程序员&#xff0c;就应该去躺坑&#xff0c;这样做也是为了能够有更多自主操作的空间。 像其他AI一样&#xff0c…

【类和对象】基础知识

目录 一、类的定义 定义方式一&#xff1a;定义与声明都在类中 定义方式二&#xff1a;定义与声明分离 二、类的实例化&&类对象存储方式 类的实例化 类对象存储模式 三、this指针 一、类的定义 定义方式一&#xff1a;定义与声明都在类中 #include<iostream&…

进阶:Docker容器管理工具——Docker-Compose使用

文章目录 前言Compose大杀器编排服务 1、docker-compose安装curl方式安装增加可执行权限查看版本 2、Docker-compose.yaml命令3、 docker-compose实战4、Docker网络路由docker的跨主机网络路由**问题由来**:方案两台机分别配置路由表ip_forward配置 总结 前言 容器的管理工具&…