首次使用需要安装django-rest-framework及jwt相关包
pip install djangorestframework
pip install djangorestframework-simplejwt
INSTALLED_APPS =[
...
...
'rest_framework'
'app01'
]
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated',),
# 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
# 'PAGE_SIZE': 10,
# 用户登陆认证方式
# SessionAuthentication, BasicAuthentication,为了兼容drf自带的页面认证方式
# 若使用drf默认登录认证,不能使用自定义表的用户信息,只可以用默认User表用户登录,通过python manage.py createsuperuser创建
# 'DEFAULT_AUTHENTICATION_CLASSES': (
# 'rest_framework.authentication.SessionAuthentication',
# 'rest_framework.authentication.BasicAuthentication',
# )
}
# jwt
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=1),
}
由于jwt默认使用django自带的User表,若使用自定义User表需要改造获取token的视图,继承官方文档提供的视图TokenObtainPairSerializer,TokenObtainPairView
自定义的User表,增加is_authenticated方法
class User(models.Model):
code = models.CharField(max_length=64, unique=True, verbose_name='用户编码')
name = models.CharField(max_length=128, verbose_name='用户中文名')
password = models.CharField(max_length=256, verbose_name='密码')
email = models.EmailField(unique=True, verbose_name='邮箱')
enabled = models.IntegerField(default=1, verbose_name='是否启用', choices=((1, '启用'), (0, '停用')))
@property
def is_authenticated(self):
"""
Always return True. This is a way to tell if the user has been
authenticated in templates.
"""
return True
创建app01/utils/Authentication.py
from rest_framework_simplejwt.authentication import JWTAuthentication
from rest_framework_simplejwt.exceptions import InvalidToken, AuthenticationFailed
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework import exceptions
from django.utils.translation import gettext_lazy as _
from app01.models import User
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
"""
自定义登录认证,使用自有用户表
"""
username_field = 'username'
def validate(self, attrs):
authenticate_kwargs = {
self.username_field: attrs[self.username_field], 'password': attrs['password']}
print(authenticate_kwargs)
try:
user = User.objects.get(**authenticate_kwargs)
except Exception as e:
raise exceptions.NotFound(e.args[0])
refresh = self.get_token(user)
data = {
"userId": user.id, "token": str(refresh.access_token), "refresh": str(refresh)}
return data
class MyTokenObtainPairView(TokenObtainPairView):
serializer_class = MyTokenObtainPairSerializer
class MyJWTAuthentication(JWTAuthentication):
'''
修改JWT认证类,返回自定义User表对象
'''
def get_user(self, validated_token):
try:
user_id = validated_token['user_id']
except KeyError:
raise InvalidToken(_('Token contained no recognizable user identification'))
try:
user = User.objects.get(**{
'id': user_id})
except User.DoesNotExist:
raise AuthenticationFailed(_('User not found'), code='user_not_found')
return user
修改viewset的authentication_classes,增加调用MyJWTAuthentication即可
class UserViewSet(ModelViewSet):
queryset = User.objects.all().order_by('id')
serializer_class = UserSerializer
permission_classes = permission
authentication_classes = [MyJWTAuthentication, SessionAuthentication, BasicAuthentication]
app01/views.py
class TestView(views.APIView):
# permission_classes = [permissions.AllowAny]
# authentication_classes = [JWTAuthentication, SessionAuthentication, BasicAuthentication]
def get(self, request, *args, **kwargs):
# print('authenticate: ', request.successful_authenticator.authenticate(request))
# print('authenticate_header: ', request.successful_authenticator.authenticate_header(request))
# print('get_header: ', request.successful_authenticator.get_header(request))
# print('get_raw_token: ',
# request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request)))
# print('get_validated_token: ', request.successful_authenticator.get_validated_token(
# request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request))))
# print('get_user: ', request.successful_authenticator.get_user(
# request.successful_authenticator.get_validated_token(
# request.successful_authenticator.get_raw_token(request.successful_authenticator.get_header(request)))))
# print('www_authenticate_realm: ', request.successful_authenticator.www_authenticate_realm)
return Response('OK')
def post(self, request, *args, **kwargs):
return Response('OK')
修改app01/urls.py
urlpatterns = [
path('', include(routers.urls)),
# jwt
path('login/', MyTokenObtainPairView.as_view(), name='login'),
path('test/', views.TestView.as_view(), name='test'),
# jwt
path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
]
浏览器打开 http://127.0.0.1:8000/test/ 返回ok,代表drf框架已经正常了
下面打开postman登录获取token令牌
没有意外情况就可以成功返回token
普通的Model表的api很简单,参考django-rest-framework官方文档即可,下面记录下关于多对多ManyToMany关系的编写
class Role(models.Model):
role_name = models.CharField(max_length=128, unique=True, verbose_name="组名")
permission = models.ManyToManyField('Permission', blank=True, verbose_name="关联权限")
server_group = models.ManyToManyField('ServerGroup', blank=True, verbose_name="关联服务器组")
memo = models.TextField(blank=True, null=True, verbose_name="备注")
c_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
直接使用默认的ModelSerializer会报错,查找官方文档找到一个SlugRelatedField字段可以通过关联查询方式序列化,
slug_field对应的是关联表的显示字段
class RoleSerializer(serializers.HyperlinkedModelSerializer):
permission = serializers.SlugRelatedField(slug_field='title', many=True, queryset=Permission.objects.all())
server_group = serializers.SlugRelatedField(slug_field='name', many=True, queryset=ServerGroup.objects.all())
class Meta:
model = Role
fields = ['url', 'role_name', 'permission', 'server_group', 'memo', 'c_time']
有其他问题后续研究后继续更新