Django | 로그인 기능 구현

Ryan Heo·2022년 5월 23일
0
post-thumbnail

# django 프로젝트를 시작했다고 가정하고 작성할 것이다.

django restframework Authentication API 공식 홈페이지

전반적인 내용은 공식 홈페이지에 기술된 내용을 따라갈 것이다.


기본 세팅

Django restframework 를 이용하여 로그인 기능구현

Django restframework는 다양한 Authentication API를 제공하는데 그 중 Client-server setup에 용이한 TokenAuthentication API를 이용하여 로그인 기능을 구현해보도록 할 것이다.

1. Django Restframework 설치

Django Restframework API를 설치하기 위해선 우선 restframeworok를 설치해야한다.

pip install djangorestframework

위 command를 실행하여 가상환경에 django restframework를 설치하였다.

2. Setting.py 설정

django project를 시작하면 setting.py 파일이 함께 생성된다.
TokenAuthentication 을 이용하기 위해선 setting.py 내에 App을 추가해줘야한다.

INSTALLED_APPS = [
    ...
    
    # Third party API
    'rest_framework.authtoken',
]


User Model 확장

장고에서는 기본적으로 User Model을 제공하고 이를 이용한 다양한 기능을 제공한다. TokenAuthentication 또한 Django가 기본적으로 제공하는 User Model를 기반으로 동작하기 때문에 이 모델을 확장한 Customized User Model를 만들어 보도록 한다.

User Model 확장이후에도 superuser를 만들거나 user 관리가 가능하도록 만들어볼 것이다.

1. User App 설치

py manage.py startapp users

위 command를 이용하여 users라는 이름을 가진 App을 만들어주었다.
model.py, view.py 등 필요한 파일을 자동으로 생성해준다.

2. model.py 수정

# users/models.py

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

필요한 라이브러리를 import 한다. AbstractBaseUser를 이용하여 기본적인 내용만 제공되는 User 모델에서 가져오고, 나머지는 직접

# users/models.py

class UserManager(BaseUserManager):

    use_in_migrations = True
    
    def create_user(self, username, email, password):
        # need username, email, password to create a user
        if not username:
            raise ValueError('must have a username')
        if not email:
            raise ValueError('must have user email')
        if not password:
            raise ValueError('must have user password')

        user = self.model(
            username=username,
            email=self.normalize_email(email)
        )
        
        user.set_password(password)
        user.save(using=self._db)
        
        return user
    
    def create_superuser(self, username, email, password):
        user = self.create_user(
            username=username,
            email=self.normalize_email(email),
            password=password
        )
        
        user.is_admin = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

User 관리를 위한 Manager를 설정한다.
username, email, password만 있다면 user등록이 가능하도록 설정했다.

#users/models.py

class User(AbstractBaseUser, PermissionsMixin):
    
    objects = UserManager()
    
    username = models.CharField(max_length=50,
                                unique=True,)
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField(
        verbose_name='email',
        max_length=255,
        unique=True,
    )
    position = models.CharField(max_length=30)
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    
    USERNAME_FIELD = 'username'
    REQUIRED_FIELDS = ['email']
    
    def __str__(self):
        return self.username
    
    def has_perm(self, perm, obj=None):
        return True
    
    def has_module_perms(self, app_label):
        return True
    
    @property
    def is_staff(self):
        return self.is_admin

User 모델에 사용될 요소를 설정해준다.
username, first_name, last_name, email, position 의 요소를 갖도록 설정했고,
관리자인지 확인하는 property를 추가했다.

이 부분은 나중에 더 자세하게 다루겠지만, 더 자세한 내용은 아래 공식 홈페이지에서 확인할 수 있다.
django 공식 홈페이지 | user customizing

3. Migration

py manage.py makemigrations

py manage.py migrate

위 command를 이용하여 data migration을 해준다.
작성한 models.py와 추가한 restframework 내용을 포함한 데이터베이스를 생성한다.



HTML과 view.py

서버로 보낼 데이터를 입력할 페이지와 logic을 담당하는 view.py를 작성한다.

1. HTML

공동으로 사용하는 페이지 base.html
서버로부터 message를 받으면 출력하고, 아니라면 Welcome!을 출력한다.
login 버튼을 누르면 login form을,
signup 버튼을 누르면 signup form을 출력한다.

# base.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Home</title>
</head>
<body>
  <h5>{% if not message %} Welcome! {% else %} {{ message }} {% endif %}</h5>

  <button><a href="/login">Log In</a></button>
  <button><a href="/signup">Sign Up</a></button>
  {% block login %}{% endblock %}
  {% block signup %}{% endblock %}
  {% if user.is_authenticated %} <button><a href="/signout">Sign Out</a></button> {% endif %}
</body>
</html>

username과 password를 받아 서버로 POST한다.

# login.html

{% extends 'base.html' %}

{% block login %}
  <form action="/login/" method="POST">
    {% csrf_token %}
    <div>
      <label for="username">Username: </label>
      <input type="text" name="username">
    </div>
    <div>
      <label for="password">Password:</label>
      <input type="password" name="password">
    </div>
    <button type="submit">Log In</button>
  </form>
{% endblock %}

username, email, password를 받아 서버로 POST한다.

# signup.html
{% extends 'base.html' %}

{% block signup %}
  <form action="/signup/" method="POST">
    {% csrf_token %}
    <div>
      <label for="username">Username: </label>
      <input type="text" name="username">
    </div>
    <div>
      <label for="email">Email: </label>
      <input type="email" name="email">
    </div>
    <div>
      <label for="password">Password: </label>
      <input type="password" name="password">
    </div>
    <div>
      <label for="re-password">Password Check: </label>
      <input type="password" name="re-password">
    </div>
    <button type="submit">Sign Up</button>
  </form>
{% endblock %}

2. view.py

index는 홈화면을 출력한다.

# view.py

from django.contrib.auth import authenticate, login, logout
from django.contrib import messages, auth
from django.shortcuts import render, redirect
from .models import User
from rest_framework.authtoken.models import Token


def index(request):
    user_list = User.objects.all()
    context = {'user_list': user_list,
               'user': request.user,}
    return render(request, 'base.html', context)

token을 발행하여 user 파라미터를 통해 해당유저에게 할당한다.

def login(request):
    if request.method == 'POST':
        username = request.POST['username']
        password = request.POST['password']

        user = authenticate(request, username=username, password=password)

        if user is not None:
            # create a token for a user
            token = Token.objects.get_or_create(user=user)
            context = {'token': token,
                       'message': 'You logged in successfully.'}
            return render(request, 'users/login.html', context)
        else:
            messages.error(request, 'ID or Password was incorrect.')
            return redirect('users:login')
    else:
        return render(request, 'users/login.html')


def signup(request):
    if request.method == 'POST':
        username = request.POST['username']
        email = request.POST['email']
        pass1 = request.POST['password']
        pass2 = request.POST['re-password']

        if User.objects.filter(username=username):
            messages.error(request, "Username already exist! Please try some other username.")
            return redirect('users:signup')

        if User.objects.filter(email=email):
            messages.error(request, "Email already registered.")
            return redirect('users:signup')

        if pass1 != pass2:
            messages.error(request, "Passwords do not match.")
            return redirect('users:signup')

        user = User.objects.create_user(username, email, pass1)
        token = Token.objects.create(user=user)
        context = {'token': token}
        user.save()
        messages.success(request, "Your account has been successfully created.")
        return redirect('users:login', context)
    else:
        return render(request, 'users/signup.html')


def signout(request):
    logout(request)
    messages.success(request, "Logged Out Successfully.")
    return redirect('users:home')

위 코드에서 사용한 authentication API는 django 공식 홈페이지 에서 확인 가능하다.

profile
developer

0개의 댓글