【问题标题】:Drf: authenticating without the USERNAME_FIELDDrf:在没有 USERNAME_FIELD 的情况下进行身份验证
【发布时间】:2021-12-31 08:12:45
【问题描述】:

扩展自:Drf how to: simple-jwt authenticating without the USERNAME_FIELD

我试图弄清楚如何使用未设置为 USERNAME_FIELD 的字段对用户进行身份验证并遇到一些问题,它让我可以输入正确的数据字段,但它从不进行身份验证

我正在使用之前问题答案中的这个 sn-p:

class MyTokenStudentSerializer(TokenObtainPairSerializer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['student_id'] = serializers.CharField(required=False)
        # self.fields['password'] = serializers.CharField(write_only=True, required=True)
        self.fields['password'] = PasswordField(trim_whitespace=False)

    username_field = 'student_id'
    auth_fields = ['student_id']


#login view extended from TokenObtainPairView
    class LoginStudentView(TokenObtainPairView):
        permission_classes = (AllowAny,)
        serializer_class = MyTokenStudentSerializer

生产

 {
        "detail": "No active account found with the given credentials"
 }

任何修改将不胜感激。

【问题讨论】:

    标签: django django-rest-framework django-authentication django-rest-framework-simplejwt


    【解决方案1】:

    如果您使用默认的ModelBackend,则应指定USERNAME_FIELD

    class User(AbstractUser):
        USERNAME_FIELD = 'student_id'
        student_id = models.TextField(default="", unique=True) # Should be unique
    

    输出

    ~ $ curl -X POST "http://127.0.0.1:8000/api/auth/login-student/" -d "password=admin&student_id=stdnt"
    {"refresh":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTY0MzcxMTgzMCwiaWF0IjoxNjQxMTE5ODMwLCJqdGkiOiJkY2MyNTEwZGRiNWE0ZTJmODllMDI2OWRkYWI5ZGVjNSIsInVzZXJfaWQiOjF9.c0QTdBhiPUf4yvPP0l3a-XQ0iD6kycECAdb6MAROY8g","access":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNjQxMTIzNDMwLCJpYXQiOjE2NDExMTk4MzAsImp0aSI6ImM0NjA0ZTlhMDBhNjQ5YjdhMTkxOGQ3OTJmOTMyYTJiIiwidXNlcl9pZCI6MX0.XoZXTJICE_PyZFXIIvsm3bci-e-O67AsYvIvY1ijNAo"}
    

    另外,您可以编写自己的身份验证后端并将其包含在 settings.py 中。

    AUTHENTICATION_BACKENDS = [
        'django.contrib.auth.backends.ModelBackend',
        'project.apps.auth.backends.MyCustomModelBackend',
    ]
    

    后端示例

    class MyCustomModelBackend(ModelBackend):
        def authenticate(self, request, username=None, password=None, **kwargs):
            student_id = kwargs.get("student_id")
            if student_id is None or password is None:
                return
            try:
                user = User.objects.get(student_id=student_id)
            except User.DoesNotExist:
                # Run the default password hasher once to reduce the timing
                # difference between an existing and a nonexistent user (#20760).
                User().set_password(password)
            else:
                if user.check_password(password) and self.user_can_authenticate(user):
                    return user
    

    使用这种方法,您可以通过username 字段保留登录信息。此外,您不应在 User 模型中指定 USERNAME_FIELD = 'student_id'

    【讨论】:

    • 当我删除 and self.user_can_authenticate(user) 时它起作用了你能告诉我它是做什么的吗?
    • @redietyosef 我认为你的用户有is_active = False,所以self.user_can_authenticate(user) 等于False。这里是the source code
    猜你喜欢
    • 2022-01-20
    • 1970-01-01
    • 2016-08-02
    • 2020-01-12
    • 2022-01-03
    • 2021-06-25
    • 2020-05-12
    • 2013-06-25
    • 1970-01-01
    相关资源
    最近更新 更多