DRF框架之如何实现用户名和密码均可登录

 

  由于我们经常会使用jwt_token保持用户的登录状态,所有Django RESTful Framework框架的扩展包  djangorestframework-jwt 帮我们在其内部实现了用户认证机制,即只需要在我们的路由中如下注册即可:

url(r'^authorizations/$',views.ObtainJSONWebToken.as_view())

   那么这个视图主要帮我们做了哪些事情呢?

  1. 调用序列化器对用户名和密码进行校验,返回生成的 用户对象和 签发的jwt_token
  2. 若校验成功,会签发一个jwt_token返回给前端,用来用户状态保持,返回响应。

一、其内部具体怎么实现呢?

  还是直接看源码吧。

 一、首先看 -- ObtainJSONWebToken 视图

 通过文档介绍: 

  接收带有用户名和密码的post请求,返回一个jwt_token用于用户认证。

  其继承了 JSONWebTokenAPIView 视图,而该视图 又继承了 APIView ,其主要帮我们实现了 POST方法。接下来我们看一下 该视图集的post方法。

 

 二、JSONWebTokenAPIView 视图的post方法

 从该方法中我们可以看到主要做了两个操作:

  1. 其调用了序列化器 对用户名和密码进行了校验并且返回数据(签发的jwt_token 和 user对象),而这个序列化器就是 上面看到的序列化器类 -- JSONWebTokenSerializer
  2. 随后调用了一个函数  jwt_response_payload_handler(token, user, request),生成响应对象。

 接下来我们看一下序列化器是怎样做 用户名和密码的校验的,和返回了什么样的数据?

 

 三、JSONWebTokenSerializer的 validate 方法 

  其 主要实现的是:

  1. 通过其Django认证系统内部的一个 user = authenticate(**credentials) 实现 对 用户名和密码的校验 和 生成user对象 。
  2. 通过 用户对象 生成 jwt的payload部分,并且签发token。
  3. 返回 用户对象 和 token。(返回值会传入validated_data中,可以在视图中通过serializer.validated_data获取到。)

 

二、返回的响应数据

  从上面的源码解析中我们可以了解到,生成响应数据的主要是 在 JSONWebTokenAPIView 中 post 方法中通过调用 jwt_response_payload_handler(token, user, request),来生成响应数据的。

  那么需求来了,如果我想要给前端返回的不仅仅是 token,还有返回用户名、用户ID呢?

  这时候我们就可以重写 jwt_response_payload_handler(token, user, request) 方法 去构建响应数据。

def jwt_response_payload_handler(token, user=None, request=None):
    """
    自定义jwt认证成功返回数据
    """
    return {
        'token': token,
        'user_id': user.id,
        'username': user.username
    }

 

三、允许用户名和手机号均可登陆

  通过上述源码介绍我们可以知道,其只允许使用 用户名 进行登录,其最终进行用户名和密码校验的还是调用Django的用户认证系统的 user = authenticate(**credentials)方法

  那么若我们想要 允许用户名和手机号均可登录 ,只需重写 authenticate(**credentials)方法 即可。例如:

def get_user_by_account(account):
    '''
    根据账号获取user对象
    :param account: 账号,可以是用户名,也可以是手机好
    :return: User对象或者None
    '''
    try:
        if re.match(r'1[3-9]\d{9}$',account):
            # 说明是以手机号登陆
            user = User.objects.get(mobile=account)
        else:
            # 说明是以用户名登陆
            user = User.objects.get(username=account)
    except User.DoesNotExist:
        return None
    else:
        return user

class UsernameMobileAuthBackend(ModelBackend):
    '''
    自定义用户名或者手机号
    由于无论是restframework_jwt提供的认证还是其他均是调用了django中的ModelBackend的authenticate进行认证的,
    故我们可以通过继承重写 -- 使得其既可以通过手机号又可以通过用户名进行登陆
    '''
    def authenticate(self, request, username=None, password=None, **kwargs):
        user = get_user_by_account(username)
        if user and user.check_password(password):
            return user
        else:
            return None  # 没有返回值默认返回None

  

  总结:

  1. 若使用 jwt_token做用户保持,DRF框架的提供了 用户认证视图类 -- ObtainJSONWebToken。
  2. 上述视图 通过序列化器进行 用户校验 并且 用户对象和 token,而其内部主要实现 用户名和密码校验的 还是调用Django的用户认证系统的 user = authenticate(**credentials)方法
  3. 并且上述视图类中介绍post请求,通过调用序列化器做数据校验和数据转换,可以通过serializer.validated_data进行获取返回的数据,并且调用 jwt_response_payload_handler(token, user, request)方法生成响应数据。

 

 

   over~~~,主要还是理解源码实现登录的逻辑~~~~~

 

posted @ 2018-10-24 17:25  Little_five  阅读(1077)  评论(0编辑  收藏  举报