扩写auth的user表
-1 前端(postman,web,app,小程序)---》发送http请求,携带用户的用户名密码---》到后端
-2 后端request.data 取出前端传入的数据--》字典---》取出用户名,密码
-3 拿着用户名密码去数据库查询,有没有这个人
-4 如果有,说明 登录成功
-5 签发token:1 通过当前用户得到payload(自己生成荷载) 2 通过荷载得到token
-6 返回给前端{code,msg,token,username,icon...}
-7 如果查不到,就返回用户名密码错误
-1 扩写auth的user表
-自己写一个表,继承AbstractUser:username,password,is_superuser
-password:加密的---》如何加密的
-同样的明文---》加密得到的密文是不一样的
-AuthUser.objects.create_user(username=xx,password=123)
-AuthUser.objects.create_superuser(username=xx,password=123)
-pbkdf2_sha256$260000$e3ZRrKYrR0kSEMNAKPOJl4$2dzB06dDZEe4ZSTy7DtWGqvCwY
加密方式 有效时间 盐 加密后的结果
-自定义密码加密---》同样的密码,加密结果不一样
-项目一开始,就要处理完,再迁移,如果先迁移,就会出问题
-配置文件中配置
-2 多方式登录
-前端接收 用户名,手机号,邮箱的这个字段是同一个
{username:用户名/手机号/邮箱,password:密码}
-正则匹配---》如果是手机号,就查 手机号+密码,如果是邮箱 邮箱+密码
-check_password
-签发token
------所有逻辑都写在视图类中了-----
-逻辑写到序列化类中
-如果继承了ModelSerializer,必须重写username
-重写了全局钩子:在全局钩子中完成校验,如果校验不过,抛异常
-写了获取用户方法
-写了签发token方法
-把token和用户名放到了self.context中了
1 基于自定义表编写认证类
from django.utils.translation import gettext_lazy as _
msg = _('Signature has expired.')
1.1 认证类
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from rest_framework_jwt.settings import api_settings
from .models import User
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
from django.utils.translation import ugettext as _
class JWTLoginAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
try:
payload = jwt_decode_handler(token)
user = User.objects.get(pk=payload.get('user_id'))
except jwt.ExpiredSignature as e:
msg = '签名过期'
raise AuthenticationFailed(msg)
except jwt.DecodeError:
msg = 'token错误'
raise AuthenticationFailed(msg)
except jwt.InvalidTokenError:
raise AuthenticationFailed('不合法的token')
except Exception:
raise AuthenticationFailed('未知错误,请联系系统管理员')
return (user, token)
'''
每次访问需要登录的接口,都会去查数据库
所以咱们可以做优化
1 自己生成一个user对象
2 直接返回user_id,以后用的时候,再查数据库
'''
1.2 登录接口
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
from rest_framework.viewsets import ViewSet
from rest_framework.decorators import action
class UserView(ViewSet):
@action(methods=['POST'],detail=False)
def login(self, request):
username = request.data.get('username')
password = request.data.get('password')
user = User.objects.filter(username=username, password=password).first()
if user:
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return Response({'code': 101, 'msg': '登录成功', 'token': token, 'username': user.username})
else:
return Response({'code': 101, 'msg': '用户名或密码错误'})
1.3 路由
router.register('user', UserView, 'user')
router.register('books', BooView, 'books')
1.4 视图类
from rest_framework.viewsets import GenericViewSet
from .auth import JWTLoginAuthentication
class BooView(GenericViewSet):
authentication_classes = [JWTLoginAuthentication]
def list(self, request):
return Response("你看到我了")
2 django-jwt源码分析
2.1 签发
-前端post请求,提交了用户名密码,就能签发token
-去ObtainJSONWebToken中找---》post
class ObtainJSONWebToken(JSONWebTokenAPIView):
serializer_class = JSONWebTokenSerializer
class JSONWebTokenAPIView(APIView):
def post(self, request, *args, **kwargs):
serializer =JSONWebTokenSerializer(data=request.data)
if serializer.is_valid():
user = serializer.object.get('user')
token = serializer.object.get('token')
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)
class JSONWebTokenSerializer(Serializer):
def validate(self, attrs):
credentials = {
'username': attrs.get("username"),
'password': attrs.get('password')
}
if all(credentials.values()):
user = authenticate(**credentials)
if user:
if not user.is_active:
msg = _('User account is disabled.')
raise serializers.ValidationError(msg)
payload = jwt_payload_handler(user)
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 前端携带用户名密码到后端---》执行后端你的post方法---》后端生成一个序列化类的对象---》执行校验---》走了全局钩子--》全局钩子中通过用户名密码获取用户(如果获取不到抛异常)---》获取到后签发token---》签发完返回----》在视图类中---》取出来,返回给前端
2.2 认证
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
def get_jwt_value(self, request):
auth = get_authorization_header(request).split()
auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
if not auth:
if api_settings.JWT_AUTH_COOKIE:
return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
return 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)
return auth[1]
def authenticate(self, request):
jwt_value = self.get_jwt_value(request)
if jwt_value is None:
return None
try:
payload = jwt_decode_handler(jwt_value)
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)
return (user, jwt_value)
-获取token复杂一点,有个前端
3 权限介绍
将用户与权限对接(多对多)
张三 [发视频,点赞,评论]
李四 [看视频]
将用户与角色对接,然后角色与对象的权限对接。
django的admin+auth就是使用了这套认证机制
ABAC(Attribute-Based Access Control,基于属性的访问控制),又称为PBAC(Policy-Based Access Control,基于策略的访问控制),CBAC(Claims-Based Access Control,基于声明的访问控制)。
传统的ACL、RBAC的架构是{subject,action,object},
而ABAC的架构是{subject,action,object,contextual}且为他们添加了parameter(参数)。
subject属性:比如用户的年龄、部门、角色、威望、积分等主题属性。
action属性:比如查看、读取、编辑、删除等行为属性。
object属性:比如银行账户、文章、评论等对象或资源属性。
contextual属性:比如时段、IP位置、天气等环境属性
RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。
-用户表---》一堆用户:张三,李四
-角色表(group组)---》用户的角色:后勤部,开发部,总裁办。。。
-权限表-----》放了一堆权限:发电脑,提交代码,删除代码,发工资
-用户和角色多对多:一个用户属于多个角色,一个角色属于多个用户
-角色 和权限多对多:一个角色有多个权限,一个权限属于多个角色
--------rabc----通过5张表可以实现
-django为了更细粒度划分---》多了一张表,用户和权限多对多
4 simpleui的使用
1.安装simpleui
pip install django-simpleui -i https://pypi.tuna.tsinghua.edu.cn/simple
-第三方开源的权限控制 项目
-python界:django-vue-admin 7期学长写的
-java界:若依
-go界:gin-vue-admin
2 修改django后台模块默认的模板
INSTALLED_APPS = [
'simpleui',
]
3 字符集及时区设置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False