如何使 Vue.js 将散列密码发布到 Django REST API AbstractBaseUser 自定义模型?
Posted
技术标签:
【中文标题】如何使 Vue.js 将散列密码发布到 Django REST API AbstractBaseUser 自定义模型?【英文标题】:How to make Vue.js post hashed password to Django REST API AbstractBaseUser custom model? 【发布时间】:2019-04-12 18:19:25 【问题描述】:我正在努力通过将数据从 Vue.js 发送到 Django REST 框架来创建用户。
首先,我使用AbstractBaseUser
制作了自己的自定义用户模型。
和迁移成功的地方,它也可以与 mysql、vue.js 通信。
python manage.py createsuperuser
也很好用。
因此,每当我尝试使用 createsupersuser
和 ~/admin 域时,password
字段都会自动创建为哈希字符串。
但是,当我尝试将 Vue.js 中的 POST
方法发送到用户模型时,
它只是将原始(非散列)密码放入其中,而不是遵循我设置的 Django 默认模型,例如 is_admin = False、is_active = True。
这些布尔字段将通过 Vue axios 方法始终设置为“False”
这是我的用户模型。 ./Users/models.py
# Abstracted User fields with options
class User(AbstractBaseUser, PermissionsMixin):
username = models.CharField(
max_length=20,
null=False,
blank=False,
unique=True,
error_messages='unique': _('이미 존재하는 아이디 입니다. (The account is already existed.)'),
)
full_name = models.CharField(
_('first_name' + 'last_name'),
max_length=30,
default='',
)
email = models.EmailField(
_('email address'),
)
organization = models.CharField(
max_length=50,
null=True,
blank=True,
)
phone = models.CharField(
max_length=16,
null=True,
blank=True,
)
is_staff = models.BooleanField(
_('is_staff'),
default=False,
)
is_active = models.BooleanField(
_('is_active'),
default=True,
)
created_date = models.DateTimeField(
_('date joined'),
auto_now_add=True,
)
updated_date = models.DateTimeField(
auto_now=True,
)
# User Management object
objects = UserManager()
# This field will be the 'username'
USERNAME_FIELD = 'username'
# Required for create user (without username, password)
REQUIRED_FIELDS = ['full_name', 'email', 'organization', 'phone']
class Meta:
db_table = 'Users'
verbose_name = _('user')
verbose_name_plural = _('users')
def __str__(self):
return self.username
def get_full_name(self):
"""
This method is required by Django for things like handling emails.
Typically this would be the user's first and last name. Since we do
not store the user's real name, we return their username instead.
"""
if self.full_name:
return self.full_name
return self.email
def get_short_name(self):
"""
This method is required by Django for things like handling emails.
Typically, this would be the user's first name. Since we do not store
the user's real name, we return their username instead.
"""
if self.full_name:
return self.full_name
return self.email
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
@property
def token(self):
return self._generate_jwt_token()
def _generate_jwt_token(self):
dt = datetime.now() + timedelta(days=1)
token = jwt.encode(
'id': self.pk,
'exp': int(dt.strftime('%s'))
, settings.SECRET_KEY, algorithm='HS256')
return token.decode('utf-8')
它是我的用户管理器。在同一个存储库中。
# Abstracted User manager.
class UserManager(BaseUserManager):
def create_user(self, username, password=None, full_name=None, organization=None,
email=None, phone=None, admin=False, staff=False, active=True):
if not username:
raise ValueError('아이디는 필수 항목입니다. (Account is required field.)')
if not password:
raise ValueError('비밀번호는 필수 항목입니다. (Password is required field.)')
if not full_name:
raise ValueError('사용자 이름은 필수 항목입니다. (Name is required field.)')
if not email:
raise ValueError('이메일은 필수 항목입니다. (E-mail is required field.)')
user_obj = self.model(
username=username,
full_name=full_name,
organization=organization,
phone=phone,
)
# Filled area from user
# user_obj.full_name = full_name
# user_obj.organization = organization
# user_obj.phone = phone
user_obj.username = username
user_obj.email = self.normalize_email(email)
user_obj.set_password(password)
# Invisible fields
user_obj.is_superuser = admin
user_obj.is_staff = staff
user_obj.is_active = active
user_obj.save(using=self._db)
return user_obj
def create_staffuser(self, username, password=None, full_name=None, organization=None, email=None, phone=None):
user = self.create_user(
username=username,
password=password,
full_name=full_name,
email=email,
organization=organization,
phone=phone,
staff=True,
)
user.save(using=self._db)
return user
def create_superuser(self, username, password=None, full_name=None, organization=None, email=None, phone=None):
user = self.create_user(
username=username,
password=password,
full_name=full_name,
email=email,
organization=organization,
phone=phone,
staff=True,
admin=True,
)
user.save(using=self._db)
return user
还有我的表单 python 文件。 ./Users/form.py
class RegisterForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput)
password2 = forms.CharField(label='Confirm password', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'full_name', 'email', 'organization', 'phone',)
def clean_email(self):
email = self.cleaned_data.get('email')
qs = User.objects.filter(email=email)
if qs.exists():
raise forms.ValidationError("email is taken")
return email
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
class UserAdminCreationForm(forms.ModelForm):
"""A form for creating new users. Includes all the required
fields, plus a repeated password."""
password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)
class Meta:
model = User
fields = ('username', 'full_name', 'email', 'organization', 'phone',)
def clean_password2(self):
# Check that the two password entries match
password1 = self.cleaned_data.get("password1")
password2 = self.cleaned_data.get("password2")
if password1 and password2 and password1 != password2:
raise forms.ValidationError("Passwords don't match")
return password2
def save(self, commit=True):
# Save the provided password in hashed format
user = super(UserAdminCreationForm, self).save(commit=False)
user.set_password(self.cleaned_data["password1"])
if commit:
user.save()
return user
class UserAdminChangeForm(forms.ModelForm):
"""A form for updating users. Includes all the fields on
the user, but replaces the password field with admin's
password hash display field.
"""
password = ReadOnlyPasswordHashField()
class Meta:
model = User
fields = ('username', 'password', 'email', 'organization', 'phone', 'is_active', 'is_superuser',)
def clean_password(self):
# Regardless of what the user provides, return the initial value.
# This is done here, rather than on the field, because the
# field does not have access to the initial value
return self.initial["password"]
老实说,我不知道你会看到什么...... 也许我也必须向您展示我的 admin.py 吗?总之,
这是我的 vue.js 注册 axios。
data: () => (
username: '',
password: '',
re_pass: '',
full_name: '',
email: '',
organization: '',
phone: ''
),
sign_up ()
this.$validator.validateAll()
if (this.password !== this.re_pass)
alert('check the password')
document.getElementById('re_password').focus()
else
let axios = this.$axios
let formData = new FormData()
formData.append('username', this.username)
formData.append('password', this.password)
formData.append('full_name', this.full_name)
formData.append('email', this.email)
formData.append('organization', this.organization)
formData.append('phone', this.phone)
const baseURI = 'http://127.0.0.1:8000' //my localhost api
const config =
headers:
'Content-Type': 'application/json'
/* Do axios post */
axios.post(`$baseURI/users/`, formData, config)
.then((response) =>
alert('회원가입 되었습니다. (You Signed Up.)')
this.$router.push(
name: 'sign_in'
)
)
.catch((e) =>
console.error(e)
alert('전송 중 문제가 발생하였습니다. 다시시도 해주세요. (The error accurred. Please try to do again.)')
)
实际上它可以工作,但我希望它可以更自然地工作 自动散列密码,默认设置为 Django 模型。
很抱歉这个复杂的问题。 老实说,我是第一次在这个网站上发帖,而且我也不会说英语。 我真的很难找到一些带有 Vue.js 和自定义用户模型的 Django 示例......
感谢您阅读所有内容,不要犹豫告诉我。
祝你有美好的一天!
++ 也添加我的 serializers.py ./Users/serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
# Model set
model = User
# Field set
fields = ('id', 'username', 'email', 'organization', 'full_name', 'phone', 'password',
'is_superuser', 'is_active', 'is_staff', 'last_login', 'created_date', 'updated_date')
还有我的看法。 ./Users/views.py
from rest_framework import viewsets
from .serializers import UserSerializer
from .models import User
class UsersViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
项目网址。 ./Project_name/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token
from rest_framework import routers
from Users.views import UsersViewSet
router = routers.DefaultRouter()
router.register('users', UsersViewSet)
urlpatterns = [
# Normal urls
path('admin/', admin.site.urls),
path('', include(router.urls)),
# JWT auth
path('api-token-auth/', obtain_jwt_token),
path('api-token-refresh/', refresh_jwt_token),
]
再次感谢。
【问题讨论】:
你为什么使用表单而不是序列化程序? @some_code 我正在使用序列化程序,但找不到适合我环境的示例。我也会在这篇文章中添加我的序列化程序! 这似乎是问题所在,您的表单使用user.set_password(self.cleaned_data["password1"])
但您的 API 端点使用序列化程序来保存对象,该对象没有那段代码。
@dethos 那么我必须在表单和序列化程序之间进行选择吗?并且序列化器会更明智?
你的viewset
使用的不是表单而是序列化器,所以你也应该重写序列化器的save()
方法。
【参考方案1】:
@dethos 他给了我一个线索。
所以最后我在这里找到了解决方案
Why isn't my Django User Model's Password Hashed?
我将分享我编辑的 serializers.py
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
# Model set
model = User
# Field set
fields = ('id', 'username', 'email', 'organization', 'full_name', 'phone', 'password',
'is_superuser', 'is_active', 'is_staff', 'last_login', 'created_date', 'updated_date')
def create(self, validated_data):
password = validated_data.pop('password', None)
is_active = validated_data.pop('is_active', True)
instance = self.Meta.model(**validated_data)
if password is not None:
instance.set_password(password)
instance.save()
return instance
def update(self, instance, validated_data):
for attr, value in validated_data.items():
if attr == 'password':
instance.set_password(value)
else:
setattr(instance, attr, value)
instance.save()
return instance
我添加了“set_password”和“is_active”的默认值。
【讨论】:
以上是关于如何使 Vue.js 将散列密码发布到 Django REST API AbstractBaseUser 自定义模型?的主要内容,如果未能解决你的问题,请参考以下文章