Django REST Framework完整教程-认证与权限-JWT的使用
文章目录
- 1.认证(Authentication)与权限(Permission)
- 1.1.视图添加权限
- 1.2.登录验证
- 1.3.常用DRF自带权限类
- 1.4.自定义权限类
- 1.5.全局权限
- 1.6.函数视图权限
- 2.认证详解
- 2.1.认证方案
- 2.2.如何使用TokenAuthentication?
- 3.JSON Web Token(JWT)认证
- 3.1.工作原理
- 3.2.安装
- 3.3.使用
- 3.4.更改Simple JWT的默认设置
- 3.5.自定义令牌(token)
- 3.6.自定义认证后台(Backend)
阅读本文之前,请读者先阅读: https://plugin.blog.csdn.net/article/details/133853377,如果已经知晓Django REST Framework的基础,可以继续阅读本文内容。
1.认证(Authentication)与权限(Permission)
认证(Authentication)与权限(Permission)不是一回事。认证是通过用户提供的用户ID/密码组合或者Token来验证用户的身份。权限(Permission)的校验发生验证用户身份以后,是由系统根据分配权限确定用户可以访问何种资源以及对这种资源进行何种操作,这个过程也被称为授权(Authorization)。
无论是Django还是DRF, 当用户成功通过身份验证以后,系统会把已通过验证的用户对象与request请求绑定,这样一来你就可以使用request.user获取这个用户对象的所有信息了。
在前面的教程中我们编写ArticleList和ArticleView两个基于类的视图(如下所示)。前者如果收到GET请求会返回文章资源列表,如果收到POST请求则添加文章;后者如果收到GET请求就返回单篇文章资源,如果收到PUT或DELETE请求,就对文章资源进行修改或删除。
# coding=utf-8
from .models import Article
from .serializers import ArticleSerializer# generic class-based views
from rest_framework import genericsclass ArticleList(generics.ListCreateAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializer# 将request.user与author绑定def perform_create(self, serializer):serializer.save(author=self.request.user)class ArticleDetail(generics.RetrieveUpdateDestroyAPIView):queryset = Article.objects.all()serializer_class =ArticleSerializer
以上两个视图其实是有很大问题的,因为任何用户包括匿名用户也可以对文章资源进行修改。比如当你访问单篇文章资源时,你不仅可以看到红色的delete按钮和修改文章内容的表单,而且可以在未登录的情况对它们进行操作。
1.1.视图添加权限
在Django传统视图开发中你可能会使用@login_required和@permission_required这样的装饰器要求用户先登录或进行权限验证。在DRF中你不需要做,这是因为REST framework 包含许多默认权限类,我们可以用来限制谁可以访问给定的视图。在这种情况下,我们需要的是 IsAuthenticatedOrReadOnly 类,它将确保经过身份验证的请求获得读写访问权限,未经身份验证的请求将获得只读读的权限。
现在修改我们的视图(zlblog/views.py),添加如下代码:
from rest_framework import generics
from rest_framework import permissions
from .permissions import IsOwnerOrReadOnlyclass ArticleList(generics.ListCreateAPIView):queryset = Article.objects.all()serializer_class = ArticleSerializerpermission_classes = (permissions.IsAuthenticatedOrReadOnly,)# importantdef perform_create(self, serializer):serializer.save(author=self.request.user)class ArticleDetail(generics.RetrieveUpdateDestroyAPIView):queryset = Article.objects.all()serializer_class =ArticleSerializerpermission_classes = (permissions.IsAuthenticatedOrReadOnly,)
此时再访问文章资源列表或单篇文章资源时,你会看到红色的delete按钮和添加修改表单都已消失。当你重新登录验证身份后,你又可以看到delete按钮和修改表单了。
1.2.登录验证
你可能会问,DRF中用户应该访问哪个url登录验证身份呢? 是admin吗?当然不是admin页面,因为只有管理员才能通过admin页面登录。DRF中你可以将登录页面api-auth添加到你的项目urls中,如下所示:
#apiproject/urls.py
from django.contrib import admin
from django.urls import path, includeurlpatterns = [path('admin/', admin.site.urls),path('v1/', include('zlblog.urls')),#包含zlblog中的urlspath('api-auth/', include('rest_framework.urls')), # 用户登录页面
]
然后访问http://127.0.0.1:8000/api-auth/login/你就可以看到专门的DRF的登录页面了,如下所示:
1.3.常用DRF自带权限类
除了IsAuthenticatedOrReadOnly 类,DRF自带的常用权限类还包括:
IsAuthenticated类:仅限已经通过身份验证的用户访问;
AllowAny类:允许任何用户访问;
IsAdminUser类:仅限管理员访问;
DjangoModelPermissions类:只有在用户经过身份验证并分配了相关模型权限时,才会获得授权访问相关模型。
DjangoModelPermissionsOrReadOnly类:与前者类似,但可以给匿名用户访问API的可读权限。
DjangoObjectPermissions类:只有在用户经过身份验证并分配了相关对象权限时,才会获得授权访问相关对象。通常与django-gaurdian联用实现对象级别的权限控制。
1.4.自定义权限类
IsAuthenticatedOrReadOnly 类并不能实现只有文章 article 的创建者才可以更新或删除它,这时我们还需要自定义一个名为IsOwnerOrReadOnly 的权限类,把它加入到ArticleDetail视图里。
首先我们在zlblog文件夹下创建permissions.py,添加如下代码:
# coding=utf-8
from rest_framework import permissionsclass IsOwnerOrReadOnly(permissions.BasePermission):"""自定义权限只允许对象的创建者才能编辑它。"""def has_object_permission(self, request, view, obj):# 读取权限被允许用于任何请求,# 所以我们始终允许 GET,HEAD 或 OPTIONS 请求。if request.method in permissions.SAFE_METHODS:return True# 写入权限只允许给 article 的作者。return obj.author == request.user
然后修改我们的视图,IsOwnerOrReadOnly 的权限类,把它加入到ArticleDetail视图的permission_classes里。这样就完美实现了文初我们想要实现的三个功能。DRF支持权限类的插拔,是不是很帅?
1.5.全局权限
在前面的案例中,我们都是在基于类的API视图里通过permission_classes属性设置的权限类。如果你有些权限是全局或全站通用的,你还可以在settings.py中使用 DEFAULT_PERMISSION_CLASSES 全局设置默认权限策略。
REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',)
}
如果未指定,则此设置默认为允许无限制访问:
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.AllowAny',
)
1.6.函数视图权限
如果你习惯使用基于函数的视图编写API,你可以按如下方式给你的函数视图添加权限。
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response@api_view(['GET'])
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):content = {'status': 'request was permitted'}return Response(content)
注意:当通过类属性或装饰器设置新的权限类时,您会告诉视图忽略 settings.py 文件上设置的默认列表。
2.认证详解
身份验证是将传入的请求对象(request)与一组标识凭据(例如请求来自的用户或其签名的令牌token)相关联的机制。REST framework 提供了一些开箱即用的身份验证方案,并且还允许你实现自定义方案。
DRF的每个认证方案实际上是一个类。你可以在视图中使用一个或多个认证方案类。REST framework 将尝试使用列表中的每个类进行身份验证,并使用成功完成验证的第一个类的返回的元组设置 request.user 和request.auth。
用户通过认证后request.user返回Django的User实例,否则返回AnonymousUser的实例。request.auth通常为None。如果使用token认证,request.auth可以包含认证过的token。
2.1.认证方案
Session认证SessionAuthentication类:此认证方案使用Django的默认session后端进行身份验证。当客户端发送登录请求通过验证后,Django通过session将用户信息存储在服务器中保持用户的请求状态。Session身份验证适用于与你的网站在相同的Session环境中运行的AJAX客户端 (注:这也是Session认证的最大弊端)。
基本认证BasicAuthentication类:此认证方案使用HTTP 基本认证,针对用户的用户名和密码进行认证。使用这种方式后浏览器会跳出登录框让用户输入用户名和密码认证。基本认证通常只适用于测试。
远程认证RemoteUserAuthentication类:此认证方案为用户名不存在的用户自动创建用户实例。这个很少用,具体见文档。
Token认证TokenAuthentication类:该认证方案是DRF提供的使用简单的基于Token的HTTP认证方案。当客户端发送登录请求时,服务器便会生成一个Token并将此Token返回给客户端,作为客户端进行请求的一个标识以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。后面我们会详细介绍如何使用这种认证方案。
注意:如果你在生产环境下使用BasicAuthentication和TokenAuthentication认证,你必须确保你的API仅在https可用。
如何在DRF中使用你的认证方案 ?
方式1:settings.py中设置默认的全局认证方案
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication',)}
**方式2:基于类的视图(CBV)中使用-authentication_classes **
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIViewclass ExampleView(APIView):authentication_classes = (SessionAuthentication, BasicAuthentication)permission_classes = (IsAuthenticated,)
方式3:函数视图中使用
@api_view(['GET'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
def example_view(request, format=None):content = {'user': unicode(request.user), # `django.contrib.auth.User` 实例。'auth': unicode(request.auth), # None}return Response(content)
如何自定义认证方案?
要实现自定义的认证方案,要继承BaseAuthentication类并且重写.authenticate(self, request)方法。如果认证成功,该方法应返回(user, auth)的二元元组,否则返回None。
以下示例将以自定义请求标头中名称为’X_USERNAME’提供的用户名作为用户对任何传入请求进行身份验证,其它类似自定义认证需求比如支持用户同时按用户名或email进行验证。
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptionsclass ExampleAuthentication(authentication.BaseAuthentication):def authenticate(self, request):username = request.META.get('X_USERNAME')if not username:return Nonetry:user = User.objects.get(username=username)except User.DoesNotExist:raise exceptions.AuthenticationFailed('No such user')return (user, None)
2.2.如何使用TokenAuthentication?
DRF自带的TokenAuthentication方案可以实现基本的token认证,整个流程如下:
首先,你需要将修改settings.py, 加入如下app。
INSTALLED_APPS = (...'rest_framework.authtoken')
后文再单独讲解一个例子。
3.JSON Web Token(JWT)认证
然而JSON Web Token(JWT)是一种更新的使用token进行身份认证的标准。与DRF内置的TokenAuthentication方案不同,JWT身份验证不需要使用数据库来验证令牌, 而且可以轻松设置token失效期或刷新token, 是API开发中当前最流行的跨域认证解决方案。本文将详细介绍JWT认证的工作原理以及如何通过djangorestframework-simplejwt 这个第三方包轻松实现JWT认证。
3.1.工作原理
JSON Web Token(JWT)是一种开放标准,它定义了一种紧凑且自包含的方式,用于各方之间安全地将信息以JSON对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。JWT用于为应用程序创建访问token,通常适用于API身份验证和服务器到服务器的授权。那么如何理解紧凑和自包含这两个词的含义呢?
- 紧凑:就是说这个数据量比较少,可以通过url参数,http请求提交的数据以及http header多种方式来传递。
- 自包含:这个字符串可以包含很多信息,比如用户id,用户名,订单号id等,如果其他人拿到该信息,就可以拿到关键业务信息。
那么JWT认证是如何工作的呢? 首先客户端提交用户登录信息验证身份通过后,服务器生成一个用于证明用户身份的令牌(token),也就是一个加密后的长字符串,并将其发送给客户端。在后续请求中,客户端以各种方式(比如通过url参数或者请求头)将这个令牌发送回服务器,服务器就知道请求来自哪个特定身份的用户了。
JSON Web Token由三部分组成,这些部分由点(.)分隔,分别是header(头部),payload(有效负载)和signature(签名)。
header(头部): 识别以何种算法来生成签名;
pyload(有效负载): 用来存放实际需要传递的数据;
signature(签名): 安全验证token有效性,防止数据被篡改。
通过http传输的数据实际上是加密后的JWT,它是由两个点分割的base64-URL长字符串组成,解密后我们可以得到header, payload和signature三部分。我们可以简单的使用 https://jwt.io/ 官网来生成或解析一个JWT,如下所示:
接下来我们将使用django-rest-framework-simplejwt这个第三方软件包进行JWT身份验证。
django-rest-framework-simplejwt为Django REST框架提供了JSON Web令牌认证后端。它提供一组保守的默认功能来涵盖了JWT的最常见用例。它还非常容易扩展。
3.2.安装
pip install djangorestframework-simplejwt
3.3.使用
首先,我们需要告诉DRF我们使用jwt认证作为后台认证方案。修改apiproject/settings.py:
REST_FRAMEWORK = {'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_simplejwt.authentication.JWTAuthentication',],
}
其次,我们需要提供用户可以获取和刷新token的urls地址,这两个urls分别对应TokenObtainPairView和TokenRefreshView两个视图。
# coding=utf-8
# apiproject/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from django.conf import settings
from django.conf.urls.static import static
from rest_framework_simplejwt.views import (TokenObtainPairView,TokenRefreshView,
)urlpatterns = [path('admin/', admin.site.urls),path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),path('v1/', include('zlblog.urls')), #包含其它页面的路由地址
]if settings.DEBUG:urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
最后,我们可以开始使用postman测试了。通过POST方法发送登录请求到http://127.0.0.1:8000/token/, 请求数据包括username和password。如果登录成功,你将得到两个长字符串,一个是access token(访问令牌),还有一个是refresh token(刷新令牌),如下所示:
但是,这里引发了跨域问题。安装跨越库文件:
pip install django-cors-headers
修改setting.py文件,有两处,如下所示:
INSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','rest_framework','corsheaders', # 注册跨域app'zlblog','rest_framework.authtoken'
]MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','corsheaders.middleware.CorsMiddleware', # 跨域中间件'django.middleware.locale.LocaleMiddleware', #支持中文语言'django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]
然后再用postman仿真就可以得到结果:
修改上文有一个受保护的视图(比如这里的/articles/),权限(permission_classes)是IsAuthenticated,只有验证用户才可访问。如果未授权,返回如下结果:
访问这个保护视图时你只需要在请求头的Authorization选项里输入你刚才获取的access token即可,如下所示:
DRF接口会自定验证token的有效性。
不给这个access token默认只有5分钟有效。5分钟过后,当你再次访问保护视图时,你将得到如下token已失效或过期的提示。
那么问题来了,Simple JWT中的access token默认有效期是5分钟,那么refresh token默认有效期是多长呢? 答案是24小时。
3.4.更改Simple JWT的默认设置
Simple JWT的默认设置如下所示:
# JWT配置
SIMPLE_JWT = {'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5), # Access Token的有效期'REFRESH_TOKEN_LIFETIME': timedelta(days=7), # Refresh Token的有效期# 对于大部分情况,设置以上两项就可以了,以下为默认配置项目,可根据需要进行调整# 是否自动刷新Refresh Token'ROTATE_REFRESH_TOKENS': False, # 刷新Refresh Token时是否将旧Token加入黑名单,如果设置为False,则旧的刷新令牌仍然可以用于获取新的访问令牌。需要将'rest_framework_simplejwt.token_blacklist'加入到'INSTALLED_APPS'的配置中'BLACKLIST_AFTER_ROTATION': False, 'ALGORITHM': 'HS256', # 加密算法'SIGNING_KEY': settings.SECRET_KEY, # 签名密匙,这里使用Django的SECRET_KEY
# 如为True,则在每次使用访问令牌进行身份验证时,更新用户最后登录时间"UPDATE_LAST_LOGIN": False, # 用于验证JWT签名的密钥返回的内容。可以是字符串形式的密钥,也可以是一个字典。"VERIFYING_KEY": "","AUDIENCE": None,# JWT中的"Audience"声明,用于指定该JWT的预期接收者。"ISSUER": None, # JWT中的"Issuer"声明,用于指定该JWT的发行者。"JSON_ENCODER": None, # 用于序列化JWT负载的JSON编码器。默认为Django的JSON编码器。"JWK_URL": None, # 包含公钥的URL,用于验证JWT签名。"LEEWAY": 0, # 允许的时钟偏差量,以秒为单位。用于在验证JWT的过期时间和生效时间时考虑时钟偏差。
# 用于指定JWT在HTTP请求头中使用的身份验证方案。默认为"Bearer""AUTH_HEADER_TYPES": ("Bearer",), # 包含JWT的HTTP请求头的名称。默认为"HTTP_AUTHORIZATION""AUTH_HEADER_NAME": "HTTP_AUTHORIZATION", # 用户模型中用作用户ID的字段。默认为"id"。"USER_ID_FIELD": "id",# JWT负载中包含用户ID的声明。默认为"user_id"。"USER_ID_CLAIM": "user_id",# 用于指定用户身份验证规则的函数或方法。默认使用Django的默认身份验证方法进行身份验证。"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
# 用于指定可以使用的令牌类。默认为"rest_framework_simplejwt.tokens.AccessToken"。"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),# JWT负载中包含令牌类型的声明。默认为"token_type"。"TOKEN_TYPE_CLAIM": "token_type",# 用于指定可以使用的用户模型类。默认为"rest_framework_simplejwt.models.TokenUser"。"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
# JWT负载中包含JWT ID的声明。默认为"jti"。"JTI_CLAIM": "jti",
# 在使用滑动令牌时,JWT负载中包含刷新令牌过期时间的声明。默认为"refresh_exp"。"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",# 滑动令牌的生命周期。默认为5分钟。"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),# 滑动令牌可以用于刷新的时间段。默认为1天。"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),# 用于生成访问令牌和刷新令牌的序列化器。"TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainPairSerializer",# 用于刷新访问令牌的序列化器。默认"TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSerializer",# 用于验证令牌的序列化器。"TOKEN_VERIFY_SERIALIZER": "rest_framework_simplejwt.serializers.TokenVerifySerializer",# 用于列出或撤销已失效JWT的序列化器。"TOKEN_BLACKLIST_SERIALIZER": "rest_framework_simplejwt.serializers.TokenBlacklistSerializer",# 用于生成滑动令牌的序列化器。"SLIDING_TOKEN_OBTAIN_SERIALIZER": "rest_framework_simplejwt.serializers.TokenObtainSlidingSerializer",# 用于刷新滑动令牌的序列化器。"SLIDING_TOKEN_REFRESH_SERIALIZER": "rest_framework_simplejwt.serializers.TokenRefreshSlidingSerializer",
}
如果要覆盖Simple JWT的默认设置,可以修改settings.py, 如下所示。下例将refresh token的有效期改为了15天。
from datetime import timedeltaSIMPLE_JWT = {'REFRESH_TOKEN_LIFETIME': timedelta(days=15),'ROTATE_REFRESH_TOKENS': True,
}
3.5.自定义令牌(token)
如果你对Simple JWT返回的access token进行解码,你会发现这个token的payload数据部分包括token类型,token失效时间,jti(一个类似随机字符串)和user_id。如果你希望在payload部分提供更多信息,比如用户的username,这时你就要自定义令牌(token)了。
首先,编写你的zlblog/seralizers.py,添加如下代码。该序列化器继承了TokenObtainPairSerializer类。
from rest_framework_simplejwt.serializers import TokenObtainPairSerializerclass MyTokenObtainPairSerializer(TokenObtainPairSerializer):@classmethoddef get_token(cls, user):token = super(MyTokenObtainPairSerializer, cls).get_token(user)# Add custom claimstoken['username'] = user.usernamereturn token
其次,不使用Simple JWT提供的默认视图,使用自定义视图。修改zlblog/views.py, 添加如下代码:
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.permissions import AllowAny
from .serializers import MyTokenObtainPairSerializerclass MyObtainTokenPairView(TokenObtainPairView):permission_classes = (AllowAny,)serializer_class = MyTokenObtainPairSerializer
最后,修改zlblog/urls.py, 添加如下代码,将/token/指向新的自定义的视图。注意:本例中的app名为zlblog,所以是从zlblog.views导入的MyObtainTokenPairView。
# coding=utf-8
from django.contrib import admin
from django.urls import path, include
from zlblog.views import MyObtainTokenPairView
from rest_framework.routers import DefaultRouter
from django.conf import settings
from django.conf.urls.static import static
from rest_framework_simplejwt.views import TokenRefreshViewurlpatterns = [path('admin/', admin.site.urls),path('token/', MyObtainTokenPairView.as_view(), name='token_obtain_pair'),#自定义tokenpath('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),path('v1/', include('zlblog.urls')), #包含其它页面的路由地址
]if settings.DEBUG:urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
重新发送POST请求到/token/,你将获得新的access token和refresh token。采用 https://jwt.io/ 解码,在负载部分将得到新的字段名:
对重新获取的access token进行解码,你将看到payload部分多了username的内容,是不是很酷? 在实际API开发过程中,通过Json Web Token传递更多数据非常有用。
3.6.自定义认证后台(Backend)
上面的演示案例是通过用户名和密码登录的,如果我们希望后台同时支持邮箱/密码,手机/密码组合登录怎么办? 这时我们还需要自定义认证后台(Backend)。
首先,修改zlblog/views.py, 添加如下代码:
# coding=utf-8
from django.contrib.auth.backends import ModelBackend
#django的Q对象将SQL表达式封装在Python对象中,该对象可用于与数据库相关的操作。使用Q对象,我们可以使用更少和更简单的代码进行复杂查询。
from django.db.models import Q
from django.contrib.auth import get_user_modelUser = get_user_model()class MyCustomBackend(ModelBackend):def authenticate(self, request, username=None, password=None, **kwargs):try:user = User.objects.get(Q(username=username) | Q(email=username) )if user.check_password(password):return userexcept Exception as e:return None
其次,修改zlblog/settings.py, 把你自定义的验证方式添加到AUTHENTICATION_BACKENDS里去。
AUTHENTICATION_BACKENDS = ('zlblog.views.MyCustomBackend',
)
修改好后,你使用postman发送邮箱/密码组合到/token/,将同样可以获得access token和refresh token。是不是又学到了一招?
相关文章:

Django REST Framework完整教程-认证与权限-JWT的使用
文章目录 1.认证(Authentication)与权限(Permission)1.1.视图添加权限1.2.登录验证1.3.常用DRF自带权限类1.4.自定义权限类1.5.全局权限1.6.函数视图权限 2.认证详解2.1.认证方案2.2.如何使用TokenAuthentication? 3.JSON Web Token(JWT)认证3.1.工作原理3.2.安装3.…...

领域内容第18名
恭喜入榜...

[1024]程序员节 一晃6年过去了
加入开发者大军,一晃已是6年有余,从最初的Andoird开发如火如荼,到现在的秋风萧瑟,宛如被秋风吹得只剩躯干的树木,等待来年的焕发新芽。 我本不是一个科班出身的开发者,但是为了生活,说白了为了钱…...

数据结构 | 构造哈夫曼树
template<class T> void Heap<T>::PercolateUp() //为了向上调整为堆,我们需要比较当前节点和其父节点的值,如果父节点的值比当前节点大,则交换它们的值。 { int p size - 1, c (p - 1) / 2;//c表示当前节点的父节点࿰…...

实验室烧杯可以用超声波清洗机吗
实验室烧杯可以用超声波清洗机吗?答案是可以的!超声波清洗机不仅可以清洗实验烧杯,还可以用于清洗实验室中的试管、培养皿、移液管、载玻片、容量瓶、锥形瓶等各类实验器皿。在实验中,如果烧杯清洁不到位,会使得实验数…...

Unity之ShaderGraph如何实现UV抖动
前言 今天我们通过噪波图来实现一个UV抖动的效果。 如下图所示: 关键节点 Time:提供对着色器中各种时间参数的访问 UV:提供对网格顶点或片段的UV坐标的访问。可以使用通道下拉参数选择输出值的坐标通道。 SimpleNoise:根据…...

#力扣:771. 宝石与石头@FDDLC
771. 宝石与石头 - 力扣(LeetCode) 一、Java class Solution {public int numJewelsInStones(String jewels, String stones) {int[] isJewel new int[z 1];for (int i jewels.length() - 1; i > 0; i--) isJewel[jewels.charAt(i)] 1;int cnt …...

【网络协议】聊聊拓扑网络结构与原理
拓扑结构 上一篇我们简单讲述了一种交换机的情况,但是实际的场景是比较复杂的,在一个楼层可能有几十或者上百个接口,那么当知道对方的IP地址,求对方的MAC地址,其实是通过ARP协议进行处理的。 上图是一个两个交换机的…...

uview表单 hooks
在UViewUI库中,使用hooks封装表单二次可以让我们以更灵活的方式使用表单组件。下面是一个示例,展示如何将表单封装成hooks,并以JSON形式传递参数: 首先,我们可以创建一个自定义的Hook来处理表单逻辑。在这个例子中&…...

车载视频如何转换视频格式
当你收集了多种视频想在车内进行播放,它们可能不会自动播放。你有可能会在屏幕上看到一条消息,显示“文件格式不受支持”,这是因为这些视频可能采用了你的汽车无法识别的格式。 那我们如何才可以转换为车载播放器上运行的最重要且最广泛使用…...

虚拟音频设备软件 Loopback mac中文版软件介绍
创建虚拟音频设备以从应用程序和音频输入设备获取声音,然后将其发送到音频处理应用程序,它就是—Loopback for Mac,Loopback mac为您提供高端工作室混音板的强大功能,有了它在Mac上传递音频会变得很容易。 Loopback for mac中文版…...

Android SurfaceControlViewHost介绍及使用
概要介绍 SurfaceControlViewHost是一个工具类, 用于帮助在其他进程中显示本进程的view。 SurfaceControlViewHost 为绘制进程持有,其中的SurfacePackage 交给另外的显示进程,在显示进程中的SurfaceView中通过SurfaceView.setChildSurface…...

微信小程序开发(一)
目录 开发者界面 app.json配置(举例) 组件 样式 像素 flex布局 微信小程序是一种基于微信平台的应用程序开发模式,它可以让开发者使用前端开发技术(如HTML、CSS和JavaScript)开发应用程序,并在微信客户端中运行。以下是微信…...

MySQL数据库操作(创建、修改、删除、查询)
MySQL查看或显示数据库(SHOW DATABASES语句) 在 MySQL 中,可使用 SHOW DATABASES 语句来查看或显示当前用户权限范围以内的数据库。查看数据库的语法格式为: SHOW DATABASES [LIKE ‘数据库名’]; 语法说明如下: 语法…...

【合宙Air700E/780E短信转发】短信转发移动联通 不要钉钉不要微信,转发自建服务器-傻瓜式搭建
官方提供的教程介绍了通过钉钉、微信等工具接收短信验证码的方法,但最终实现的目的是获取验证码,而不是通过工具间接获得。 因此,我们可以直接调用API接口来获取验证码,从而达到更快、更便捷地获得验证码的目的。 所以做了一个服…...

TStor CSP文件存储在大模型训练中的实践
业务背景 大模型作为人工智能领域的重要发展趋势,正在逐渐改变人们的生活和工作方式。随着近年来大模型领域技术的突破,各类语言模型、图像模型、视频模型快速演进,国内外市场也不断涌现出优秀的大模型研究及商业化平台,预期通过…...

最用的几个git命令
1、git init 用于初始化一个新的Git仓库。 执行这个命令后,Git会在当前目录下创建一个名为".git"的子目录,其中存储着仓库的所有元数据。 2、git clone 用于克隆一个已存在的仓库。 执行这个命令后,将在本地创建仓库的一个副…...

邮件网关CAC2.0防御并行:提升高校师生邮箱账号的全面安全
客户背景 解民生之多艰,育天下之英才。中国农业大学(以下简称“中国农大”)作为教育部直属高校,先后进入国家“211工程”和“985工程”重点建设的高水平研究型大学,首批入选一流大学建设高校(A类ÿ…...

潮玩IP助力环境保护,泡泡玛特发布行业首款碳中和产品
在今年的2023上海PTS国际潮流玩具展上,泡泡玛特正式发布了首款“碳中和”潮玩产品DIMOO X蒙新河狸手办(下简称DIMOO河狸),通过环保主题与流行文化的联合,让年轻人知道野生动物保护有多种方式,同时以创新的设…...

pytorch分布式数据训练结合学习率周期及混合精度
文章目录 1、SPAWN方式2、torchrun 方式 正如标题所写,我们正常的普通训练都是单机单卡或单机多卡。而往往一个高精度的模型需要训练时间很长,所以DDP分布式数据并行和混合精度可以加速模型训练。混精可以增大batch size. 如下提供示例代码,经…...

Looper分析
Looper分析 在 Handler 机制中,Looper 的作用是提供了一个消息循环 ( message loop ) 的机制,用于处理和分发消息。 Looper 是一个线程局部的对象,每个线程只能有一个 Looper 对象。它通过一个无限循环来不断地从消息队列中取出消息&#x…...

LoongArch单机Ceph Bcache加速4K随机写性能测试
LoongArch单机Ceph Bcache加速4K随机写性能测试 两块HDD做OSD [rootceph01 ~]# fio -direct1 -iodepth128 -thread -rwrandwrite -ioenginelibaio -bs4k -size100G -numjobs1 -runtime600 -group_reporting -namemytest -filename/dev/rbd0 mytest: (g0): rwrandwrite, bs(R)…...

景联文科技语音数据标注:AUTO-AVSR模型和数据助力视听语音识别
ASR、VSR和AV-ASR的性能提高很大程度上归功于更大的模型和训练数据集的使用。 更大的模型具有更多的参数和更强大的表示能力,能够捕获到更多的语言特征和上下文信息,从而提高识别准确性;更大的训练集也能带来更好的性能,更多的数据…...

【R】数据相关性的可视化
一千零一技|相关性分析及其可视化:copy&paste,搞定 .libPaths(c("/bioinfo/home/software/miniconda3/envs/R4.0/lib/R/library")) #data("mtcars") library("PerformanceAnalytics") # pdf("test.pdf") #…...

Spring Security 6.x 系列【68】 授权篇之基于注解 缓存的访问控制方案
有道无术,术尚可求,有术无道,止于术。 本系列Spring Boot 版本 3.1.0 本系列Spring Security 版本 6.1.0 源码地址:https://gitee.com/pearl-organization/study-spring-security-demo 文章目录 1. 前言2. 改造思路3. 实现3.1 基础工程3.2 数据库存储用户3.3 自定义3.4 测…...

QML(11)——qml界面之间通信方式详解
目录 一、属性绑定1、直接绑定 property01: property02实例代码 2、条件绑定 Qt.binding实例代码 二、信号传递1、on<Property>Changed实例代码 2、on<Signal>实例代码 3、条件信号传递 connect实例代码 4、Connections 一、属性绑定 属性绑定具有持续性 1、直接…...

图像检索算法 计算机竞赛
文章目录 1 前言2 图像检索介绍(1) 无监督图像检索(2) 有监督图像检索 3 图像检索步骤4 应用实例5 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 图像检索算法 该项目较为新颖,适合作为竞赛课题方向,学长非常推荐ÿ…...

科学清理Windows系统垃圾,让你的电脑性能快如火箭
文章目录 1. 使用磁盘清理工具2. 清理临时文件2.1 清理用户临时文件夹2.2 清理系统临时文件夹2.3 清理系统临时文件 3.卸载不需要的程序4. 删除不必要的下载文件5. 清理回收站6. 压缩磁盘7. 删除旧的系统还原点8. 禁用休眠功能9. 定期进行磁盘碎片整理10. 禁用不必要的启动项11…...

docker图形胡界面管理工具--Portainer可视化面板安装
1.安装运行Portainer docker run -d -p 8088:9000 \ > --restartalways -v /var/run/docker.sock:/var/run/docker.sock --privilegedtrue portainer/portainer--restartalways:Docker启动后容器自动启动 -p:端口映射 -v:路径映射2.通过…...

环形链表的约瑟夫问题
前言: 据说著名犹太历史学家Josephus有过如下故事: 在罗马人占领乔塔帕特后,39个犹太人和Josephus及他的朋友躲进一个洞里,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个…...