내 자신의 인증 시스템을 롤링하지 않고 django에서 이것을 수행하는 좋은 방법이 있습니까? 사용자 이름을 만드는 대신 사용자 이름을 사용자의 이메일 주소로 사용하고 싶습니다.
조언 부탁드립니다, 감사합니다.
답변:
이 작업을 수행하려는 다른 사람에게는 django-email-as-username 을 살펴볼 것을 권합니다. 이것은 관리자 및 createsuperuser
관리 명령 패치를 포함하는 매우 포괄적 인 솔루션 입니다.
편집 : Django 1.5부터 django-email-as-username 대신 사용자 정의 사용자 모델을 사용하는 것을 고려해야 합니다.
여기에 우리가하는 일이 있습니다. "완전한"솔루션은 아니지만 원하는 기능을 많이 수행합니다.
from django import forms
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
exclude = ('email',)
username = forms.EmailField(max_length=64,
help_text="The person's email address.")
def clean_email(self):
email = self.cleaned_data['username']
return email
class UserAdmin(UserAdmin):
form = UserForm
list_display = ('email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff',)
search_fields = ('email',)
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
다음은 사용자 이름과 이메일이 모두 허용되도록하는 한 가지 방법입니다.
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.forms import ValidationError
class EmailAuthenticationForm(AuthenticationForm):
def clean_username(self):
username = self.data['username']
if '@' in username:
try:
username = User.objects.get(email=username).username
except ObjectDoesNotExist:
raise ValidationError(
self.error_messages['invalid_login'],
code='invalid_login',
params={'username':self.username_field.verbose_name},
)
return username
기본 인증 양식을 설정하는 설정이 있는지 모르겠지만 urls.py에서 URL을 재정의 할 수도 있습니다.
url(r'^accounts/login/$', 'django.contrib.auth.views.login', { 'authentication_form': EmailAuthenticationForm }, name='login'),
ValidationError를 발생 시키면 유효하지 않은 이메일이 제출 될 때 500 오류를 방지 할 수 있습니다. "invalid_login"에 대한 super의 정의를 사용하면 이메일 주소가 귀하의 서비스 계정에 등록되었는지 여부를 유출하는 것을 방지하는 데 필요한 오류 메시지가 모호하게 유지됩니다 (특정 "해당 이메일로 사용자가 없음"과 비교). 해당 정보가 아키텍처에서 안전하지 않은 경우 더 많은 정보를 제공하는 오류 메시지가있는 것이 더 편할 수 있습니다.
Django는 이제 관리자 및 양식이 포함 된 확장 인증 시스템의 전체 예제를 제공합니다. https://docs.djangoproject.com/en/stable/topics/auth/customizing/#a-full-example
기본적으로 복사 / 붙여 넣기 및 적용 할 수 있습니다 ( date_of_birth
제 경우에는 필요하지 않음 ).
실제로 Django 1.5부터 사용할 수 있으며 현재까지도 사용할 수 있습니다 (django 1.7).
사용자 모델을 확장하려는 경우 어쨌든 사용자 지정 사용자 모델을 구현해야합니다.
다음은 Django 1.8의 예입니다. 조금 필요 장고 1.7은 대부분 기본 형태 (단지에서 살펴 변화, 더 많은 작업을 비트 UserChangeForm
& UserCreationForm
에 django.contrib.auth.forms
- 당신은 1.7에서 필요하다고).
user_manager.py :
from django.contrib.auth.models import BaseUserManager
from django.utils import timezone
class SiteUserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
today = timezone.now()
if not email:
raise ValueError('The given email address must be set')
email = SiteUserManager.normalize_email(email)
user = self.model(email=email,
is_staff=False, is_active=True, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, email, password, **extra_fields):
u = self.create_user(email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
models.py :
from mainsite.user_manager import SiteUserManager
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import PermissionsMixin
class SiteUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(unique=True, blank=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
is_staff = models.BooleanField(default=False)
USERNAME_FIELD = 'email'
objects = SiteUserManager()
def get_full_name(self):
return self.email
def get_short_name(self):
return self.email
forms.py :
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from mainsite.models import SiteUser
class MyUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = SiteUser
fields = ("email",)
class MyUserChangeForm(UserChangeForm):
class Meta(UserChangeForm.Meta):
model = SiteUser
class MyUserAdmin(UserAdmin):
form = MyUserChangeForm
add_form = MyUserCreationForm
fieldsets = (
(None, {'fields': ('email', 'password',)}),
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser',)}),
('Groups', {'fields': ('groups', 'user_permissions',)}),
)
add_fieldsets = (
(None, {
'classes': ('wide',),
'fields': ('email', 'password1', 'password2')}
),
)
list_display = ('email', )
list_filter = ('is_active', )
search_fields = ('email',)
ordering = ('email',)
admin.site.register(SiteUser, MyUserAdmin)
settings.py :
AUTH_USER_MODEL = 'mainsite.SiteUser'
username
필드를 추가했습니다 SiteUser
. python manage.py makemigrations ...
명령을 실행하면 다음과 같은 출력이 ERRORS: <class 'accounts.admin.UserAdmin'>: (admin.E033) The value of 'ordering[0]' refers to 'username', which is not an attribute of 'accounts.User'.
username
필드를 추가했습니다 . 이 붙여 넣기 bin 항목에서 구현을 보여주고 싶었습니다. pastebin.com/W1PgLrD9User
null=True
다른 대안은 나에게 너무 복잡해 보이므로 사용자 이름, 이메일 또는 둘 다를 사용하여 인증하고 대소 문자 구분을 활성화 또는 비활성화 할 수있는 스 니펫을 작성했습니다. django-dual-authentication 으로 pip에 업로드했습니다 .
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.conf import settings
###################################
""" DEFAULT SETTINGS + ALIAS """
###################################
try:
am = settings.AUTHENTICATION_METHOD
except:
am = 'both'
try:
cs = settings.AUTHENTICATION_CASE_SENSITIVE
except:
cs = 'both'
#####################
""" EXCEPTIONS """
#####################
VALID_AM = ['username', 'email', 'both']
VALID_CS = ['username', 'email', 'both', 'none']
if (am not in VALID_AM):
raise Exception("Invalid value for AUTHENTICATION_METHOD in project "
"settings. Use 'username','email', or 'both'.")
if (cs not in VALID_CS):
raise Exception("Invalid value for AUTHENTICATION_CASE_SENSITIVE in project "
"settings. Use 'username','email', 'both' or 'none'.")
############################
""" OVERRIDDEN METHODS """
############################
class DualAuthentication(ModelBackend):
"""
This is a ModelBacked that allows authentication
with either a username or an email address.
"""
def authenticate(self, username=None, password=None):
UserModel = get_user_model()
try:
if ((am == 'email') or (am == 'both')):
if ((cs == 'email') or cs == 'both'):
kwargs = {'email': username}
else:
kwargs = {'email__iexact': username}
user = UserModel.objects.get(**kwargs)
else:
raise
except:
if ((am == 'username') or (am == 'both')):
if ((cs == 'username') or cs == 'both'):
kwargs = {'username': username}
else:
kwargs = {'username__iexact': username}
user = UserModel.objects.get(**kwargs)
finally:
try:
if user.check_password(password):
return user
except:
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user.
UserModel().set_password(password)
return None
def get_user(self, username):
UserModel = get_user_model()
try:
return UserModel.objects.get(pk=username)
except UserModel.DoesNotExist:
return None
장고 등록의 최신 버전은 멋진 사용자 정의를 허용하고 일을 할 수 - 문서를 여기 https://bitbucket.org/ubernostrum/django-registration/src/fad7080fe769/docs/backend-api.rst
아래 링크에서이 주제에 대한 흥미로운 토론을 찾을 수도 있습니다.
가장 쉬운 방법은 로그인보기에서 이메일을 기반으로 사용자 이름을 조회하는 것입니다. 이렇게하면 다른 모든 것을 그대로 둘 수 있습니다.
from django.contrib.auth import authenticate, login as auth_login
def _is_valid_email(email):
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
try:
validate_email(email)
return True
except ValidationError:
return False
def login(request):
next = request.GET.get('next', '/')
if request.method == 'POST':
username = request.POST['username'].lower() # case insensitivity
password = request.POST['password']
if _is_valid_email(username):
try:
username = User.objects.filter(email=username).values_list('username', flat=True)
except User.DoesNotExist:
username = None
kwargs = {'username': username, 'password': password}
user = authenticate(**kwargs)
if user is not None:
if user.is_active:
auth_login(request, user)
return redirect(next or '/')
else:
messages.info(request, "<stvrong>Error</strong> User account has not been activated..")
else:
messages.info(request, "<strong>Error</strong> Username or password was incorrect.")
return render_to_response('accounts/login.html', {}, context_instance=RequestContext(request))
템플릿에서 그에 따라 다음 변수를 설정하십시오.
<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">
그리고 사용자 이름 / 암호 입력에 올바른 이름, 즉 사용자 이름, 암호를 제공하십시오.
업데이트 :
또는 if _is_valid_email (email) : 호출은 사용자 이름에서 if '@'로 대체 될 수 있습니다. 이렇게하면 _is_valid_email 함수를 삭제할 수 있습니다. 이것은 실제로 사용자 이름을 정의하는 방법에 따라 다릅니다. 사용자 이름에 '@'문자를 허용하면 작동하지 않습니다.
나는 가장 빠르게 방법에서 양식 상속을 만드는 것입니다 생각 UserCreateForm
하고 무시 username
로 필드를 forms.EmailField
. 그런 다음 모든 신규 등록 사용자에 대해 이메일 주소로 로그인해야합니다.
예를 들면 :
urls.py
...
urlpatterns += url(r'^signon/$', SignonView.as_view(), name="signon")
views.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
class UserSignonForm(UserCreationForm):
username = forms.EmailField()
class SignonView(CreateView):
template_name = "registration/signon.html"
model = User
form_class = UserSignonForm
signon.html
...
<form action="#" method="post">
...
<input type="email" name="username" />
...
</form>
...
UserCreationForm
클래스입니까? 그리고 <input …
확실히 {{form.username}}
더 나은 때를 작성하지 않는 것이 좋습니다 .
사람들이이 작업을 수행하려고하는지 확실하지 않지만 이메일 만 요청한 다음 저장하기 전에보기에서 사용자 이름을 이메일로 설정하는 좋은 방법을 찾았습니다.
내 사용자 양식에는 이메일과 비밀번호 만 필요합니다.
class UserForm(forms.ModelForm):
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
model = User
fields = ('email', 'password')
그런 다음 내 관점에서 다음 논리를 추가합니다.
if user_form.is_valid():
# Save the user's form data to a user object without committing.
user = user_form.save(commit=False)
user.set_password(user.password)
#Set username of user as the email
user.username = user.email
#commit
user.save()