티스토리 뷰

오늘 사용자 정보에 대한 나머지 이야기보다 먼저 코딩에서 흔히 이야기 하는 "함수"에 대해서 이야기하는 시간을 갖으려고 한다. 

 

함수란 무엇인가요?

함수라는게 사실 우리가 중학교 시절 배웠던 내용과 다를게 없다.

 

예를 들어 위의 함수처럼 f(x) = 2x 라는 함수가 있다고 보자 f(x)에서의 x를 우리는 매개변수, 파라미터, Argument라고 부른다. 그리고 이 매개변수는 2x 부분의 x와 같은 값이라는 것을 우리는 중학교때 다 배웠다는 것을 기억해야한다.

아참, 아직 중학교 교육과정을 거치지 않은 사람들을 위해 아래와 같이 설명 해주겠다.

 

f(x) = 2x 라는 함수를 그림으로 그려서 표현하면 위의 왼쪽 이미지, f(2) = 2 * 2 = 4 라는 것이 오른쪽 이미지라고 생각해보면 함수라는 것이 사실 수학이나 코딩이나 다를게 없는거다. 예를 들어 UserManager 클래스에 create_user라는 함수를 보자.

def create_user(self, email, password=None, **extra_fields):
    extra_fields['is_active'] = False
    extra_fields['is_staff'] = False
    extra_fields['is_super'] = False
    
    return self._create_user(email, password, **extra_fields)

※ 참고 : Python에서는 함수를 만들 때 앞에 "def" 라고 먼저 써준다. 그리고 함수의 파라미터에는 자동으로 맨 앞에 self 라는 파라미터가 붙는데 이와 관련한 내용은 또 "인스턴스"라고 부르는 개념하고 붙어서 설명을 해야하는데 이건 너무 어려우니까 지금은 패스. 그리고 파라미터 부분 맨 뒤에 "**extra_fields"는 email과 password 외에 다른 별개의 데이터를 추가해서 보낼때 사용하는 파라미터라고 생각하면 된다.

 

자 그러면 위의 코딩으로 만든 함수를 잘 보면 수학에서 쓰는 "f"가 함수의 이름이라고 치자. 그게 create_user가 되는 것이고 괄호 안에 있는 것들이 파라미터라는 거다. 뭐, 물론 코딩하는 언어마다 문법이 서로 달라서 차이가 조금씩 있지만 결국 동작하는 개념 자체는 수학이나 코딩이나 별반 다를게 없다. 

 

그저 복잡한 행동을 미리 정의해두고 나중에 내가 필요할 때 실행하면 알아서 처리해주는 그런 도구같은 것을 만들어 두는 거라고 생각하면 되겠다.

 

그러면 이제 UserManager 클래스에 대해서 알아보는 시간을 갖자.

 

UserManager 클래스

/* 생략 */

# 사용자 정보 관리 클래스
class UserManager(BaseUserManager):
    def _create_user(self, email, password, **extra_fields):
        
        if not email : # 이메일이 없다면
            raise ValueError('이메일은 필수 요소입니다.')

        if not password : # 패스워드가 없다면
            raise ValueError('패스워드는 필수 요소입니다.')
        
        # 이메일 주소를 소문자로 변환하는 과정을 거친 뒤에 저장한다.
        email = self.normalize_email(email) 
        
        # 사용자 모델 객체를 생성한다.
        user = self.model(
            email           = email
            , is_active     = extra_fields.get('is_active')
        )

        # 사용자 패스워드는 Django에서 제공해주는 해시화 과정(SHA 256)을 거쳐서 저장한다.
        user.set_password(password)

        # 실제로 DB에 사용자 정보를 저장한다.
        user.save(using=self._db)

        # 기본적으로 모든 사용자는 일반사용자 권한을 갖게된다.
        self.create_auth(user, ROLES.get('ROLE_NORMAL', 'NORMAL'))

        # 스탭 권한을 부여할지 확인 후 MANAGER 권한을 부여한다.
        if extra_fields.get('is_staff') is True :
            self.create_auth(user, ROLES.get('ROLE_MANAGER', 'MANAGER'))

        # 슈퍼 관리자 권한을 부여할지 확인 후 SUPER 권한을 부여한다.
        if extra_fields.get('is_superuser') is True :
            self.create_auth(user, ROLES.get('ROLE_SUPER', 'SUPER')) 

        return user
    

    # 일반 사용자 생성
    def create_user(self, email, password=None, **extra_fields): 
        extra_fields['is_active'] = False
        extra_fields['is_staff'] = False
        extra_fields['is_superuser'] = False
        
        return self._create_user(email, password, **extra_fields)

    # 스탭 사용자 생성
    def create_staff(self, email, password=None, **extra_fields):
        extra_fields['is_active'] = True
        extra_fields['is_staff'] = True
        extra_fields['is_superuser'] = False
        
        return self._create_user(email, password, **extra_fields)

    # 슈퍼 관리자 생성
    def create_superuser(self, email, password=None, **extra_fields):
        extra_fields['is_active'] = True
        extra_fields['is_staff'] = True
        extra_fields['is_superuser'] = True

        return self._create_user(email, password, **extra_fields)

    # 권한 정보 등록
    def create_auth( self, user, role=ROLES.get('ROLE_NORMAL', 'NORMAL')):
        role_obj = Auth(
            user = user,
            role = role
        )

        role_obj.save(using=self.db)

        return role_obj

/* 생략 */

일단 이 UserManager 클래스의 역할은 사용자를 등록하는 역할인데 등록하는 과정에서 일반 사용자인 경우엔 어떻게 상태를 어떻게 정의하고 등록할 것인지, 관리자인 경우엔 어떻게 등록할지 그 동작하는 것들을 미리 정의해두고 수행할 수 있도록 만든 클래스다.  User 클래스를 보면 objects라는 변수에 UserManager() 라고 하는 값을 넣어주는데 이 때 UserManager가 이 UserManager 클래스다. 물론 인스턴스객체와 Static 객체에 대해서 설명을 해야 더 정확한데 어려우니까 나중에 공부하도록 하고 그냥 "아, 사용자를 저장하는 방법들을 미리 정의한 클래스구나"라고 생각하면 된다.

 

이때 중요한 점은 그냥 등록할 때 사용하는 함수에 따라서 권한 정보가 다르게 등록된다는 점을 이해해야하는데 그럼 점들은 내가 주석으로 다 설명해 놓았으니 잘 읽어보길 바란다.

 

일단 이렇게 코딩에 대해서 설명을 했고, 이걸 읽는 독자들도 코딩을 제대로 했다면 cmd 화면에서 이렇게 명령을 입력해보도록 하자.

 

명령 프롬프트(cmd)

$ .env\Scripts\activate

(.env) $ python funny_picture\manager.py makemigrations
(.env) $ python funny_picture\manager.py migrate

(.env) $ python funny_picture\manager.py createsuperuser

명령을 구체적으로 설명하자면 아래와 같다.

  1. 가상환경에 진입(.env\Scripts\activate)
  2. 새로 만든 모델들을 DB에 적용할 수 있도록 처리(python funny_pictures\manage.py makemigrations)
  3. 모델 정보를 실제 DB에 적용하기(python funny_pictures\manage.py migrate)
  4. 슈퍼 관리자 생성(python funny_picture\manage.py createsuperuser)

모델들을 실제 DB에 적용했으니 사용자를 등록할 공간을 만들었다는 이야기고 맨 마지막엔 관리자 한명을 생성해 저장하기까지 한거다. 이 내용을 DB에서 확인해보면 아래와 같다.

DB에 Django에서 제공하는 기본적인 테이블들 외에 테이블 account_auth와 account_user가 생긴 것을 확인할 수 있다. "앱이름_모델명"으로 테이블 이름이 생기게 된다. (참고로 auth에서 제공하는 user 테이블은 생성되지 않았다.)

 

account_user 에 마우스 커서를 대고 오른쪽 버튼을 클릭하면 컨텍스트 메뉴 맨 위에 "Select Rows - Limit 1000" 이라고 뜬다. 이 메뉴를 클릭해보자.

 

방금 우리가 createsuperuser로 등록한 계정이 저장되어있는 것을 확인 할 수 있다. 이때 password 필드를 보면 우리가 입력한대로가 아니라 이상한 문자열이 저장되어 있는 것을 볼 수 있는데 이 것은 sha256이라는 방법으로 패스워드를 해시화(정상데이터로 돌이킬수 없이 수학적으로 변경된 형태) 시킨 값이다. 이 데이터는 원래의 데이터로 돌이킬 수 없으나 같은 문자열이 전달되면 위와 같은 텍스트로 변조되어 비교가 가능한 상태가 된다.

 

한마디로 "관리자라고 해도 DB를 열어서 사용자 패스워드를 확인 할 수 없는" 상태가 되어 보안을 유지할 수 있게 해준다.

 

account_auth 테이블을 한번 보자.

 

이렇게 등록되어있는 권하는 총 3개인데 이는 user_id가 1인 사람의 권한이 NORMAL, MANAGER, SUPER 이렇게 3개의 데이터를 갖는 다는 것을 의미한다. id 필드는 내가 궂이 만들지는 않았지만 Django에서 자동으로 만들어 준다.

 

이렇게 정상적으로 값들이 저장되었다면 슈퍼 관리자 등록까지 완성된거다.

 

아, 그리고 명령어 중 createsuperuser 명령을 실행하면 UserManager의 create_superuser 함수가 실행되어 사용자를 등록시켜준다. 이것은 상속받은 BaseUserManager에 있는 기능이다.

 

이렇게 사용자 계정 정보를 저장할 수 있는 테이블을 만들고 계정 정보와 권한을 저장하는 것까지 만들었다.

중간중간 이해를 돕는다고 써놓은 설명들 전부 이해 못해도 괜찮다.

한번에 이해할 수 있는 내용도 아닐 뿐더러 한번에 이해를 한다쳐도 Django에 대해서 잘 모른다면, Python에 대해서 처음이라면 당연히 바로 이해하긴 힘들거다. 다만 중간에 포기하지 않고 그저 묵묵히 따라온다면 언젠가 이런 코드들을 이해하는 자신의 모습을 확인 할 수 있을거다.

 

다음 시간에는 사용자 계정 정보가 저장되었으니 이제 로그인을 만들어볼 차례가 되었다. 다음 시간에는 JWT를 활용한 사용자 로그인을 만들어보는 시간을 갖도록 하겠다.

 

오늘은 이만!

안녕!!

댓글
댓글쓰기 폼