JWT拓展的登录视图中, 在接受到用户名和密码时, 调用的也是Django的认证系统中提供的authenticate()来检查用户名与密码是否正确.
我们可以通过修改Django系统的认证后端来支持登录账号既可以是用户名
也可以是手机号
修改重写思路是:
修改Django认证系统的认证后端需要继承django.contrib.auth.backends.ModelBackends, 并重写authenticate方法
我们需要重写什么位置?
因为我们的需求是多条件登录, 所以我们就应该着手于数据库校验操作, 寻找定位源码中数据库校验username是否存在的操作, 并使用Q查询添加多个条件验证
下面是以from rest_framework_jwt.views import obtain_jwt_token
为入口进行的源码分析(序号为查找流程):
继承JsonWebTokenAPIView视图, 当接受到用户post请求时, 执行get_serializer()
调用get_serializer()方法找到子类中定义的serializer类
当调用is_valid()方法时, 会调用到validate()
这里调用了authenticate方法并传入了用户数据, 返回的对象user
在utils/authenticate.py中:
from django.contrib.auth.backends import ModelBackend, UserModel from django.db.models import Q def get_user_by_account(account): """ 根据帐号信息获取user模型实例对象 :param account: 账号信息,可以是用户名,也可以是手机号,甚至其他的可用于识别用户身份的字段信息 :return: User对象 或者 None """ user = UserModel.objects.filter(Q(mobile=account) | Q(username=account) | Q(email=account)).first() return user class CustomAuthBackend(ModelBackend): """ 自定义用户认证类[实现多条件登录] """ def authenticate(self, request, username=None, password=None, **kwargs): """ 多条件认证方法 :param request: 本次客户端的http请求对象 :param username: 本次客户端提交的用户信息,可以是user,也可以mobile或其他唯一字段 :param password: 本次客户端提交的用户密码 :param kwargs: 额外参数 :return: """ if username is None: username = kwargs.get(UserModel.USERNAME_FIELD) if username is None or password is None: return # 根据用户名信息useranme获取账户信息 user = get_user_by_account(username) if user and user.check_password(password) and self.user_can_authenticate(user): return user
在配置文件settings/dev.py中告知Django使用我们自定义的认证后端,注意不是给drf添加设置。
# django自定义认证 AUTHENTICATION_BACKENDS = ['luffycityapi.utils.authenticate.CustomAuthBackend', ]