Django休息框架JWT和自定义身份验证后端

时间:2017-05-26 20:30:51

标签: django django-rest-framework django-rest-framework-jwt

我有自定义用户模型并创建了自定义身份验证后端。我使用django rest frameworkdjango rest framework JWT进行令牌身份验证。

用户模型:

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(
        unique=True,
        max_length=254,
    )
    first_name = models.CharField(max_length=15)
    last_name = models.CharField(max_length=15)
    mobile = models.IntegerField(unique=True)
    date_joined = models.DateTimeField(default=timezone.now)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    objects = UserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'mobile']

Auth后端:

class EmailOrMobileAuthBackend(object):
    def authenticate(self, username=None, password=None):
        try:
            user = get_user_model().objects.get(email=username)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            if username.isdigit():
                try:
                    user = get_user_model().objects.get(mobile=username)
                    if user.check_password(password):
                        return user
                except User.DoesNotExist:
                    return None
            else:
                return None

    def get_user(self, user_id):
        try:
            return get_user_model().objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

并已在settings.py中添加:

AUTHENTICATION_BACKENDS = ('accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',)

登录django管理站点时,电子邮件和手机号码都可以正常验证用户身份。但是,当我尝试使用django rest framework JWT为用户获取令牌时,出现错误:

curl -X POST -d "email=admin@gmail.com&password=123123" http://localhost/api-token-auth/

"non_field_errors": [
    "Unable to log in with provided credentials."
  ]

我还在Rest身份验证默认身份验证框架中添加了自定义身份验证后端类,但它仍无效:

REST_FRAMEWORK = {
    ...
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
}

我错过了什么?为什么它在登录django管理站点时工作,但在使用django rest framework jwt获取令牌时会出错?

更新

我按照建议制作了另一个身份验证后端并将其添加到DEFAULT_AUTHENTICATION_CLASSES,但即使这样也无效。

class DrfAuthBackend(BaseAuthentication):
    def authenticate(self, username=None, password=None):
        try:
            user = get_user_model().objects.get(email=username)
            if user.check_password(password):
                return user, None
        except User.DoesNotExist:
            if username.isdigit():
                try:
                    user = get_user_model().objects.get(mobile=username)
                    if user.check_password(password):
                        return user, None
                except User.DoesNotExist:
                    return None
            else:
                return None

设定:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAdminUser',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend',
        'accounts.email_mobile_auth_backend.DrfAuthBackend',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
}

更新

将身份验证类中的argsusername更改为email似乎无法获取auth_token,但又无法登录管理网站。

class EmailOrMobileAuthBackend(object):
    def authenticate(self, email=None, password=None):
        try:
            user = get_user_model().objects.get(email=email)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            if email.isdigit():
                try:
                    user = get_user_model().objects.get(mobile=email)
                    if user.check_password(password):
                        return user
                except User.DoesNotExist:
                    return None
            else:
                return None

    def get_user(self, user_id):
        try:
            return get_user_model().objects.get(pk=user_id)
        except User.DoesNotExist:
            return None 

2 个答案:

答案 0 :(得分:0)

您应该检查DRF documentation以获取自定义身份验证后端。

我认为您的自定义身份验证后端正在破坏它,您可以通过从DRF设置中删除它来解决它:

$query = "
        SELECT *
        FROM streamdata_comments t1 
        JOIN streamdata m
        ON";
        if ($last_id!==0) {
        $query .= " t1.comment_id < $last_id GROUP BY t1.comment_streamitem 
        AND";
        }
        $query .= "
        m.streamitem_id=t1.comment_streamitem
        AND t1.comment_poster=34 AND comment_type_id=1
        ORDER BY t1.comment_id DESC LIMIT 2";
        $result = mysqli_query($mysqli, $query) or die('Error: ' . 
        mysqli_error($mysqli));

或者修复你的,这与Django自定义身份验证基本上不一样,因为你应该从REST_FRAMEWORK = { ... 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', ), } 扩展并返回一个元组。

authentication.BaseAuthentication

然后在DRF设置中使用它:

from rest_framework import authentication


class DrfAuthBackend(authentication.BaseAuthentication):
    def authenticate(self, email=None, password=None):
        try:
            user = get_user_model().objects.get(email=email)
            if user.check_password(password):
                return user, None
        except User.DoesNotExist:
            if email.isdigit():
                try:
                    user = get_user_model().objects.get(mobile=email)
                    if user.check_password(password):
                        return user, None
                except User.DoesNotExist:
                    return None
            else:
                return None

对于Django登录:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAdminUser',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'accounts.email_mobile_auth_backend.DrfAuthBackend',
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
    ),
}

然后进行设置:

class EmailOrMobileAuthBackend(object):
    def authenticate(self, username=None, password=None):
        try:
            user = get_user_model().objects.get(email=username)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            if username.isdigit():
                try:
                    user = get_user_model().objects.get(mobile=username)
                    if user.check_password(password):
                        return user
                except User.DoesNotExist:
                    return None
            else:
                return None

    def get_user(self, user_id):
        try:
            return get_user_model().objects.get(pk=user_id)
        except User.DoesNotExist:
            return None 

答案 1 :(得分:0)

在 settings.py 文件中,添加以下内容:

<块引用>

AUTH_USER_MODEL = 'accounts.email_mobile_auth_backend.EmailOrMobileAuthBackend'