1.drf-jwt源码执行流程

1.1 签发(登录)

1.代码:
urls.py:
from rest_framework_jwt.views import obtain_jwt_token
urlpatterns = [
path('login/',obtain_jwt_token),
] 2.我们点进obtain_jwt_token源码:
drf/views.py:
obtain_jwt_token = ObtainJSONWebToken.as_view()
refresh_jwt_token = RefreshJSONWebToken.as_view()
verify_jwt_token = VerifyJSONWebToken.as_view() 3.login需要提交用户名和密码,所以是post请求,我们需要在其父类中找到post方法:
ObtainJSONWebToken>>>JSONWebTokenAPIView,在JSONWebTokenAPIView中找到了post方法:
def post(self, request, *args, **kwargs):
# serializer是序列化类的对象
serializer = self.get_serializer(data=request.data)
# 校验,如果校验通过:
if serializer.is_valid():
# 拿到user和token
user = serializer.object.get('user') or request.user
token = serializer.object.get('token')
# 拿到返回格式,之前我们自定义过token的返回格式。
"""
当我们点击方法:jwt_response_payload_handler(token, user, request),跳转到了rest_framework_jwt:jwt_response_payload_handler = api_settings.JWT_RESPONSE_PAYLOAD_HANDLER。说明JWT_RESPONSE_PAYLOAD_HANDLER需要在配置中指定返回格式。因此我们在设置中指定:JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.jwt_response.jwt_response',
}。所以返回格式才能按照我们指定的格式返回。
"""

            response_data = jwt_response_payload_handler(token, user, request)
response = Response(response_data)
return response
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) """
执行if serializer.is_valid():这句话时就会执行序列化类中的代码,但是如何得到user和token,在序列化类的全局钩子中寻找答案:
"""
4.还是回到drf/views.py中:
obtain_jwt_token = ObtainJSONWebToken.as_view()
refresh_jwt_token = RefreshJSONWebToken.as_view()
verify_jwt_token = VerifyJSONWebToken.as_view()
ObtainJSONWebToken后面跟了as_view()说明这是视图类,点进去:
class ObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
说明JSONWebTokenSerializer就是序列化类。 5.JSONWebTokenSerializer代码:
class JSONWebTokenSerializer(Serializer):
# 这是一个全局钩子,因为上面没有单个字段的校验规则,所以此时的addr就是{'username':'max','password':'max123'}
def validate(self, attrs):
credentials = {
# 这一步还是拿到了用户名,只不过是绕了一下
self.username_field: attrs.get(self.username_field),
# 拿到密码
'password': attrs.get('password')
}
# 必须用户名和密码都幼值才成立
if all(credentials.values()):
# auth模块中的,如果用户存在会拿到用户对象
user = authenticate(**credentials)
if user:
# 如果能拿到用户对象,并且用户被锁(is_active默认是1,如果用户被锁则是0)
if not user.is_active:
# 如果被锁则提示disabled
msg = _('User account is disabled.')
raise serializers.ValidationError(msg)
# 通过用户对象拿到荷载
payload = jwt_payload_handler(user)
# 通过payload生成token
return {
'token': jwt_encode_handler(payload),
'user': user
}
else:
msg = _('Unable to log in with provided credentials.')
raise serializers.ValidationError(msg)
else:
msg = _('Must include "{username_field}" and "password".')
msg = msg.format(username_field=self.username_field)
raise serializers.ValidationError(msg)

1.2 认证 (认证类)

1.认证类需要从JSONWebTokenAuthentication中找到authenticate方法。在其父类中找到了authenticate方法。
from rest_framework_jwt.authentication import JSONWebTokenAuthentication def authenticate(self, request):
"""
Returns a two-tuple of `User` and token if a valid signature has been
"""
# jwt_value就是token字符串
jwt_value = self.get_jwt_value(request)
# 如果token值没传,直接返回None
if jwt_value is None:
return None try:
# payload是一个字典:{'user_id': 1, 'username': 'max', 'exp': 1676113688, 'email': ''}
payload = jwt_decode_handler(jwt_value)
# 还有几种可能拿不到,分别是:篡改token、token过期了、未知错误
except jwt.ExpiredSignature:
msg = _('Signature has expired.')
raise exceptions.AuthenticationFailed(msg)
except jwt.DecodeError:
msg = _('Error decoding signature.')
raise exceptions.AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise exceptions.AuthenticationFailed()
# 如果没有错误顺利能拿到用户对象
user = self.authenticate_credentials(payload)
# 返回当前登录用户,token
return (user, jwt_value) 2.接下来我们来看刚才的方法get_jwt_value(request)是如何拿到token的,该方法在类JSONWebTokenAuthentication中:
def get_jwt_value(self, request):
auth = get_authorization_header(request).split() 3.我们需要找到方法get_authorization_header(request),在BaseAuthentication中找到了该方法:
def get_authorization_header(request):
# request.META可以拿到get请求头当中的值,结果是个字典。在数据发送到后端时键都变成了'HTTP_前端传入的键',如果拿不到就拿一个空字符串。此时的auth是jwt dfjkdlsjf...
auth = request.META.get('HTTP_AUTHORIZATION', b'')
if isinstance(auth, str):
# Work around django test client oddness
auth = auth.encode(HTTP_HEADER_ENCODING)
# 转码然后返回
return auth 4.继续回到get_jwt_value(request)方法:
def get_jwt_value(self, request):
# auth是个被分割列表:[jwt,dfjkdlsjf]
auth = get_authorization_header(request).split()
# JWT_AUTH_HEADER_PREFIX就是'JWT',转化成小写'jwt'
auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower() if not auth:
# 如果请求头没带,就去cookie中取
if api_settings.JWT_AUTH_COOKIE:
return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
return None
# 如果列表索引0不为jwt返回None
if smart_text(auth[0].lower()) != auth_header_prefix:
return None if len(auth) == 1:
msg = _('Invalid Authorization header. No credentials provided.')
raise exceptions.AuthenticationFailed(msg)
elif len(auth) > 2:
msg = _('Invalid Authorization header. Credentials string '
'should not contain spaces.')
raise exceptions.AuthenticationFailed(msg)
# 返回列表索引1,也就是token
return auth[1]

2.自定义用户表签发和认证

2.1 签发

views.py:
from rest_framework import permissions
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
from .models import Userinfo
from rest_framework_jwt.settings import api_settings
# 生成荷载的方法,我们直接调用drf的
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# 生成token的方法,我们也调用drf的
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER class UserView(ViewSet):
@action(methods=['POST'],detail=False)
def login(self,request,*args,**kwargs):
username = request.data.get('username')
password = request.data.get('password')
user = Userinfo.objects.filter(username=username,password=password).first()
if user:
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'code':100,'msg':'登录成功','token':token})
else:
return Response({'code':101,'msg':'用户名或密码错误'}) urls.py:
router = SimpleRouter()
router.register('user', UserView, 'user') # 此时路由:http://127.0.0.1:8000/api/v1/user/login/ urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls))
]
通过以上步骤,我们可以自定义出功颁布token:

2.2 认证

新建一个认证类authentication.py,在其中写认证类的代码:
authentication.py:
from rest_framework.authentication import BaseAuthentication
from rest_framework_jwt.settings import api_settings
import jwt
from rest_framework.exceptions import AuthenticationFailed
from .models import Userinfo
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER class JsonWebTokenAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN') # 前端的格式可以自定义,取的时候在前面加上HTTP_就好,并且键要大写
if token:
try:
# jwt_decode_handler()方法仅仅是通过token找到payload,内部并没有切割字符串的方法 get_jwt_value(),所以前端在传的时候不需要加jwt和空格。
payload = jwt_decode_handler(
token)
print(payload) # :{'user_id': 1, 'username': 'max', 'exp': 1676113688, 'email': ''}
user = Userinfo.objects.filter(pk=payload.get('user_id')).first()
return user, token
except jwt.ExpiredSignature:
raise AuthenticationFailed('token过期')
except jwt.DecodeError:
raise AuthenticationFailed('token认证失败')
except jwt.InvalidTokenError:
raise AuthenticationFailed('token无效')
except Exception as e:
raise AuthenticationFailed('未知异常')
raise AuthenticationFailed('token没有传 认证失败') views.py:
class BookView(ModelViewSet):
# 手写jwt认证只需要写认证类不用写权限类
authentication_classes = [JsonWebTokenAuthentication] def list(self, request, *args, **kwargs):
return Response('success')

3.auth_user表密码加密

3.1 手动定义类似token的加密方式:

1.token的加密方式:token由三段构成,第一段声明加密算法和类型,第二段存放有效信息的地方:过期时间、签发时间、用户id、用户名等。第三段是加密后的header和base64加密后的payload。

2.我们也可以定义一中类似token的加密方式:改密码分为三段,用两个$连接起来,第一段是密码加密后的密文,第二段是随机生成的盐(不加密),第三段是加密后的原密码和盐连接在一起(中间不加符号),在通过md5加密。

3.代码:
views.py:
import uuid
import hashlib def register_hash(request):
"""
password:原密码
res:原密码加密之后的密文
salt:随机生成的盐(不加密)
pwd1:res$salt
pwd_part3:password+salt
res2:给pwd_part3加密之后的密文
pwd2:最终密码:pwd1+res2
"""
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# print(password) # 123
md51 = hashlib.md5()
md51.update(password.encode('utf8'))
res = md51.hexdigest()
# print('res',res) # 202cb962ac59075b964b07152d234b70
# 随机生成一个盐(不加密)
salt = str(uuid.uuid4())
print('salt',salt)
# 将加密的原密码和不加密的盐组合起来,组成密码的前两部分
pwd1 = res + '$' + salt # 202cb962ac59075b964b07152d234b70$44590a73-2602-4f96-a718-972d83fb7ae6
# 将不加密的密码和盐组合起来,组成明文
pwd_part3 = res + salt
md52 = hashlib.md5()
md52.update(pwd_part3.encode('utf8'))
# 原密码和盐组成的明文加密,组成密码的第三部分
res2 = md52.hexdigest()
# 最终的密码
pwd2 = pwd1 + '$' + res2
print(pwd2)
User_hash.objects.create(username=username,hash_pwd=pwd2)
return HttpResponse('注册成功') return render(request, 'pwd.html', locals()) def login_view(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
md51 = hashlib.md5()
md51.update(password.encode('utf8'))
res = md51.hexdigest()
user_obj = User_hash.objects.filter(username=username).first()
if not user_obj:
return HttpResponse('用户未注册')
if not res == user_obj.hash_pwd.split('$')[0]:
return HttpResponse('密码错误')
salt = user_obj.hash_pwd.split('$')[1]
pwd_part3 = res + salt
md52 = hashlib.md5()
md52.update(pwd_part3.encode('utf8'))
res2 = md52.hexdigest()
if not res2 == user_obj.hash_pwd.split('$')[2]:
return HttpResponse('密码错误')
return HttpResponse('登陆成功')
return render(request,'login.html',locals()) urls.py:
urlpatterns = [
path('register/',views.register_hash),
path('login1/',views.login_view)
]

3.2 利用django自带的方法make_password()和check_password()来编写登录注册

1.make_password()只有一个参数,就是原密码。返回值是加密后的密码,也是django的auth_user表中的用户密码的加密方式:

from django.contrib.auth.hashers import make_password, check_password
from .models import User1
# 用djanngo的make_password方法注册
def register2(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
# 密码加密:
pwd = make_password(password)
User1.objects.create(username=username,password=pwd)
return HttpResponse('注册成功')
return render(request,'register2.html',locals()) 2.check_password()方法用来校验密码,里面有两个参数,第一个是明文密码,第二个参数是密文密码,如果这两个密码匹配那么结果是True,不匹配返回结果是False。
# 用django的check_password方法登陆
def login2(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
real_pwd = User1.objects.filter(username=username).first().password
is_correct = check_password(password,real_pwd)
if is_correct:
return HttpResponse('登陆成功')
return render(request,'login2.html',locals())
"""
如果超级管理员密码忘记了,可以再创建一个超级管理员,然后将新创建的管理员密码(密文)复制到前一个超级管理员的密码处,这两个管理员就会使用同一个密码。
"""

4.simpleui使用

1.之前公司里,做项目,要使用权限,要快速搭建后台管理,使用djagno的admin直接搭建,django的admin界面不好。所以采用第三方软件。

2.第三方的美化:
xadmin:作者弃坑了,bootstrap+jq
simpleui: vue,界面更好看 3.现在阶段,一般前后端分离比较多:django+vue

4.1 使用步骤

1.安装:pip install simpleui

2.在app中注册
要注册在最上面
INSTALLED_APPS = [
'simpleui'
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01',
'rest_framework',
]
然后当我们登录到admin后台管理就变成了这样:

3.然后我们在models.py中构造以下几张表,并且在admin.py中注册:
models.py:
class Book(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateField()
publish = models.ForeignKey(to='Publish',to_field='nid',on_delete=models.CASCADE)
authors=models.ManyToManyField(to='Author')
def __str__(self):
return self.name class Author(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.IntegerField()
author_detail = models.OneToOneField(to='AuthorDetail',to_field='nid',unique=True,on_delete=models.CASCADE) class AuthorDetail(models.Model):
nid = models.AutoField(primary_key=True)
telephone = models.BigIntegerField()
birthday = models.DateField()
addr = models.CharField(max_length=64) class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
city = models.CharField(max_length=32)
email = models.EmailField() admin.py:
from .models import Book,Publish,AuthorDetail,Author
admin.site.register(Book)
admin.site.register(Publish)
admin.site.register(AuthorDetail)
admin.site.register(Author)
然后我们就可以在admin后台管理页看到这几张表:

4.在apps.py中加入verbose_name = '图书管理系统',就可以将左侧列表中的app名改成自定义的名字:
class App01Config(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'app01'
verbose_name = '图书管理系统'

5.在models.py中每张表下面加入:
class Meta:
verbose_name_plural = '作者表'
在后台管理就可以将表名显示成中文:

然后再数据库加一些数据(可以在admin后台管理加,也可以在pycharm中加),添加好之后可以直接点进去修改,这就完成了对一个图书管理系统增删改查的创建。
"""
DataTimeField字段刚开始默认是英文,如果我们想要把它设置成中文,需要在settings.py中设置:LANGUAGE_CODE = 'zh-hans'。
"""

6.当我们在admin.py中注册好之后,我们在页面上只能看到书名。注册还有一种方式,在admin.py中写一个类,定义哪张表选择显示的字段就继承哪张表,用list_play=('字段名')来定义显示的字段名,但是不能上传多对多的外键字段:

7.还可以在页面上增加按钮:在刚才定义的BookAdmin中继续加内容:
actions = ['custom_button'] # custom_button不能更改 def custom_button(self, request, queryset):
print(queryset) # queryset就是选中对象的queryset,可以额外做一些操作 custom_button.short_description = '额外操作' # 按钮的中文名
custom_button.type = 'success' # 设置按钮颜色 8.侧边栏设置,需要在settings.py中进行如下设置:
SIMPLEUI_CONFIG = {
'system_keep': False,
'menu_display': ['图书管理', '权限认证', '外链'], # 开启排序和过滤功能, 不填此字段为默认排序和全部显示, 空列表[] 为全部不显示.
'dynamic': True, # 设置是否开启动态菜单, 默认为False. 如果开启, 则会在每次用户登陆时动态展示菜单内容
'menus': [
# name要和menu_display中注册的名字保持一致
{
'name': '图书管理',
'app': 'app01',
'icon': 'fas fa-code',
# models继续往下写下面的子目
'models': [
{
'name': '图书',
'icon': 'fa fa-user',
'url': '/admin/app01/book/'
},
#url只能是自己在urls.py中配置的路由或者是自动生成的路由
{
'name': '出版社',
'icon': 'fa fa-user',
'url': 'app01/publish/'
},
{
'name': '作者',
'icon': 'fa fa-user',
'url': 'app01/author/'
},
{
'name': '作者详情',
'icon': 'fa fa-user',
'url': 'app01/authordetail/'
},
]
},
{
'app': 'auth',
'name': '权限认证',
'icon': 'fas fa-user-shield', # 图标
'models': [
{
'name': '用户',
'icon': 'fa fa-user',
'url': 'auth/user/'
},
{
'name': '组',
'icon': 'fa fa-user',
'url': 'auth/group/'
},
]
},
{ 'name': '外链',
'icon': 'fa fa-file',
'models': [
{
'name': 'Baidu',
'icon': 'far fa-surprise',
# 第三级菜单 ,
'models': [
{
'name': '爱奇艺',
'url': 'https://www.iqiyi.com/dianshiju/'
# 第四级就不支持了,element只支持了3级
}, {
'name': '百度问答',
'icon': 'far fa-surprise',
'url': 'https://zhidao.baidu.com/'
}
]
},
# 我们自己定义的页面也可以直接写路由:
{
'name': '大屏展示',
'url': '/show/',
'icon': 'fab fa-github'
}]
}
]
} 9.其他配置项:
SIMPLEUI_LOGIN_PARTICLES = False #登录页面动态效果
SIMPLEUI_LOGO = 'https://avatars2.githubusercontent.com/u/13655483?s=60&v=4'#图标替换
SIMPLEUI_HOME_INFO = False #取消首页右侧github提示
SIMPLEUI_HOME_QUICK = False #快捷操作
SIMPLEUI_HOME_ACTION = False # 动作

5.权限控制

5.1 互联网项目:

	alc:访问控制列表,权限放在列表中
用户表:存储用户信息,和权限表是一对多的关系
权限表:每个用户拥有的权限 比如:
权限列表:[发视频,发评论,开直播]
max拥有的权限:[发视频,发评论,开直播]
jerry拥有的权限:[发视频]

5.2 公司内部项目(python写公司内部项目居多):

1.rbac:是基于角色的访问控制(Role-Based Access Control )在 RBAC  中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

2表关系:
用户表:用户和角色是多对多关系(一个用户可以对应多个角色)
角色表:类似于公司中的岗位
权限表:用户表不直接和用户表建立联系,而是和角色表建立联系(某个用户成为了某个角色之后才拥有某项权限)。角色表和权限表是多对多关系。 所以描述以上三者关系需要建立5张表:
用户表、角色表、权限表、用户角色表、角色权限表 3.用户和权限不直接建立联系是为了简化流程方便管理,但是也有特殊情况:比如公司人资想要获取拉取代码的权限,但是开发角色拥有的权限不仅仅是拉取代码而且还能操作代码。
如果将开发的角色赋给人资就会导致人资的权限过大。所以角色和权限直接监理联系,产生第6张表:角色权限中间表。 4.以图书管理系统为例,目前设置2个用户,一个是root(超级管理员),一个是max(普通用户)。目前想要设置max的权限为查看书籍列表和作者列表,需要首先创建一个组(角色),该组中规定了查看书籍列表和作者列表的权限。

在进入到用户设置列表中:首先取消该用户超级管理员身份(公司内超级管理员数量很有限)。

再登陆用户max,发现系统中只有作者和图书两个选项,并且只能查看:

5.管理员也可以直接设置用户和权限的对应关系:

6.在表中权限、组以及它们的对应关系都在以下6张表中:
auth_user:用户表
auth_group:角色表,组表
auth_permission:权限表
auth_user_groups:用户和角色中间表
auth_group_permissions:角色和权限中间表
auth_user_user_permissions:用户和权限中间表

7.用管理员给用户max通过用户和权限对应关系给max添加了一个权限(不通过角色),该功能也可以叠加到max的权限中,用户max现在有三个功能:查看图书和作者(通过角色添加权限)、查看出版社(通过用户添加权限):

drf-jwt源码分析以及自定义token签发认证、alc和rbac的更多相关文章

  1. Django(63)drf权限源码分析与自定义权限

    前言 上一篇我们分析了认证的源码,一个请求认证通过以后,第二步就是查看权限了,drf默认是允许所有用户访问 权限源码分析 源码入口:APIView.py文件下的initial方法下的check_per ...

  2. asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证

    原文:asp.net mvc源码分析-DefaultModelBinder 自定义的普通数据类型的绑定和验证 在前面的文章中我们曾经涉及到ControllerActionInvoker类GetPara ...

  3. Django(64)频率认证源码分析与自定义频率认证

    前言 有时候我们发送手机验证码,会发现1分钟只能发送1次,这是做了频率限制,限制的时间次数,都由开发者自己决定 频率认证源码分析 def check_throttles(self, request): ...

  4. JUnit源码分析 - 扩展 - 自定义Rule

    JUnit Rule简述 Rule是JUnit 4.7之后新加入的特性,有点类似于拦截器,可以在测试类或测试方法执行前后添加额外的处理,本质上是对@BeforeClass, @AfterClass, ...

  5. JUnit源码分析 - 扩展 - 自定义RunListener

    RunListener简述 JUnit4中的RunListener类用来监听测试执行的各个阶段,由RunNotifier通知测试去运行.RunListener与RunNotifier之间的协作应用的是 ...

  6. DRF cbv源码分析 restful规范10条 drf:APIView的源码 Request的源码 postman的安装和使用

    CBV 执行流程 路由配置:url(r'^test/',views.Test.as_view()),  --> 根据路由匹配,一旦成功,会执行后面函数(request) --> 本质就是执 ...

  7. Netty源码分析之自定义编解码器

    在日常的网络开发当中,协议解析都是必须的工作内容,Netty中虽然内置了基于长度.分隔符的编解码器,但在大部分场景中我们使用的都是自定义协议,所以Netty提供了  MessageToByteEnco ...

  8. Django(44)drf序列化源码分析(1)

    序列化与反序列化   一般后端数据返回给前端的数据格式都是json格式,简单易懂,但是我们使用的语言本身并不是json格式,像我们使用的Python如果直接返回给前端,前端用的javascript语言 ...

  9. ArrayList 源码分析和自定义ArrayList实现

    概述 ArrayList 是基于数组实现的,是一个能自动扩展的动态数组. ArrayList 是线程不安全的,多线程情况下添加元素会出现数组越界的情况,而且数组赋值操作不是原子操作,会导致多线程情况下 ...

  10. Django(60)Django内置User模型源码分析及自定义User

    前言 Django为我们提供了内置的User模型,不需要我们再额外定义用户模型,建立用户体系了.它的完整的路径是在django.contrib.auth.models.User. User模型源码分析 ...

随机推荐

  1. OS-HACKNOS-2.1靶机之解析

    靶机名称 HACKNOS: OS-HACKNOS 靶机下载地址 https://download.vulnhub.com/hacknos/Os-hackNos-1.ova 实验环境 : kali 2. ...

  2. Dockerfile 使用 SSH docker build

    如果在书写 Dockerfile 时,有些命令需要使用到 SSH 连接,比如从私有仓库下载文件等,那么我们应该怎么做呢? Dockerfile 文件配置 为了使得 Dockerfile 文件中的命令可 ...

  3. 原来用 MySQL 也可以做全文检索

    我是风筝,公众号「古时的风筝」,专注于 Java技术 及周边生态. 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在里面. 有朋友聊到他们的系统中要接入全 ...

  4. [ERROR] mariadbd: The table 'INNODB_BUFFER_PAGE' is full

    问题描述:将information_schema导出sql文件到新库中恢复,sql中的表都是临时表,存储引擎都是memory,在导入的过程中实际大量会占用临时表. 报错信息:ERROR 1114 (H ...

  5. bug处理记录:java.util.UnknownFormatConversionException: Conversion = 'Y'

    1. 报错: java.util.UnknownFormatConversionException: Conversion = 'Y' at java.util.Formatter$FormatSpe ...

  6. Dubbo-服务暴露

    前言 Dubbo源码阅读分享系列文章,欢迎大家关注点赞 SPI实现部分 Dubbo-SPI机制 Dubbo-Adaptive实现原理 Dubbo-Activate实现原理 Dubbo SPI-Wrap ...

  7. 快速学会慢查询SQL排查

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/c56bd0c5.html 你好,我是测试蔡坨坨. 在往期文章中,我们聊过数据库基础知识,可参考「数据库基础,看完这篇就够了! ...

  8. Ubuntu20.04 Java相关环境(JDK、Mysql、Redis、nacos、influxdb)部署以及运行

    重装了系统,系统版本号为:Ubuntu20.04 1.云平台 登录云平台,选择要重装的服务器,关机.一键重装即可 2.安装jdk 下载jdk-8u341-linux-x64.tar.gz,并复制到服务 ...

  9. 02.JavaScript学习笔记1

    1.强制类型转换 当使用加号进行运算时,会将数字强制转换为字符串,然后再进行运算. const year = '1991'; console.log(year + 18); console.log(t ...

  10. Go DevOps大厂运维平台开发进阶实战营

    使用 Jenkinsfile 创建流水线已报名老男孩运维课,见底下评论.enkinsfile 是一个文本文件,它包含 Jenkins 流水线的定义,并被检入源代码控制仓库.Jenkinsfile 将整 ...