Programing

Django에서 이메일 주소를 사용자 이름으로 수락

lottogame 2020. 9. 25. 08:12
반응형

Django에서 이메일 주소를 사용자 이름으로 수락


내 자신의 인증 시스템을 롤링하지 않고 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& UserCreationFormdjango.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'

다른 대안은 나에게 너무 복잡해 보이므로 사용자 이름, 이메일 또는 둘 다를 사용하여 인증하고 대소 문자 구분을 활성화 또는 비활성화 할 수있는 스 니펫을 작성했습니다. 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


     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()

완벽하게 작동합니다 ... 장고 1.11.4에서


아래 링크에서이 주제에 대한 흥미로운 토론을 찾을 수도 있습니다.

http://groups.google.com/group/django-users/browse_thread/thread/c943ede66e6807c/2fbf2afeade397eb#2fbf2afeade397eb


가장 쉬운 방법은 로그인보기에서 이메일을 기반으로 사용자 이름을 조회하는 것입니다. 이렇게하면 다른 모든 것을 그대로 둘 수 있습니다.

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))

In your template set the next variable accordingly, i.e.

<form method="post" class="form-login" action="{% url 'login' %}?next={{ request.GET.next }}" accept-charset="UTF-8">

And give your username / password inputs the right names, i.e. username, password.

UPDATE:

Alternatively, the if _is_valid_email(email): call can be replaced with if '@' in username. That way you can drop the _is_valid_email function. This really depends on how you define your username. It will not work if you allow the '@' character in your usernames.


I think the most quickly way is to create a form inherit from UserCreateForm, and then override the username field with forms.EmailField. Then for every new registration user, they need to signon with their email address.

For example:

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>
...

Not sure if people are trying to accomplish this, but I found nice (and clean) way to only ask for the email and then set the username as the email in the view before saving.

My UserForm only requires the email and password:

class UserForm(forms.ModelForm):
    password = forms.CharField(widget=forms.PasswordInput())

    class Meta:
        model = User
        fields = ('email', 'password')

Then in my view I add the following logic:

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()

참고URL : https://stackoverflow.com/questions/778382/accepting-email-address-as-username-in-django

반응형