위스타그램 (회원가입, 로그인, 인증 & 인가)

박준영·2021년 6월 3일
0
post-thumbnail

위스타그램을 통해서 처음으로 여러 기능들을 구현해보고 프론트분들과 테스트도 해보는 좋은 경험이었던 것 같습니다. 여러 기능들을 해보다보니 모르는 부분들을 많이 알게 되어서 그 부분을 정리하여 많이 응용할 수 있도록 가져가겠습니다. 기초세팅은 중요한부분은 제외하고 작성하겠습니다.

회원가입, 로그인

models.py

from django.db import models

class User(models.Model):
    email        = models.emailField(max_lengh=50, unique=True)
    password     = models.charField(max_lengh=50)
    phone_number = models.charField(max_lengh=50, null=True, unique=True)
    nickname     = models.charField(max_lengh=50, null=True, unique=True)
    
    class Meta:
    	db_table = 'uers'

우선 모델링을 통해 models.py를 작성해주었습니다.
회원가입을 위해서는 email, password, phone_number, nickname이 필요하지만 phone_number와 nikname은 작성을 안해줘도 되기 때문에 null=True를 주고 다른 사람과 겹치면 안되는내용이기 때문에 유니크 설정을 해주었습니다.

views.py

import re, json, bcrypt, jwt

from json.encoder import JSONEncoder

from django.views import View
from django.http  import JsonResponse
from django.db.models  import Q

from .models      import User
from my_settings import SECRET_KEY, ALGORITHM

class SignupView(View):

    def post(self, request):

        email_regex    = '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
        password_regex = '^[a-zA-Z0-9!@#$%^&*()-_+={}\|\\\/].{7,}$'

        try:
            data = json.loads(request.body)

            hased_pw = bcrypt.hashpw(data['password'].encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

            nickname     = data.get('nickname')
            email        = data['email']
            password     = data['password']
            phone_number = data.get('phone_number')

            if not re.search(email_regex, email):
                return JsonResponse({'message': '이메일 형식이 아닙니다.'}, status= 400)
            
            if not re.search(password_regex, password):
                return JsonResponse({'message': '패스워드 형식이 아닙니다.'}, status= 400)
              
            if User.objects.filter(
                Q(nickname = nickname) | Q(phone_number = phone_number) | Q(email = email)):
                
                return JsonResponse({'message': '입력값이 중복되었습니다.'}, status= 409)
            
            User.objects.create(
                nickname     = nickname,
                email        = email,
                password     = hased_pw,
                phone_number = phone_number
            )
            
            return JsonResponse({'message': 'SUCCESS'}, status= 201)

        except KeyError:
            return JsonResponse({'message': 'KEY_ERROR'}, status= 400)

class LoginView(View):
    
    def post(self, request):
        try:
            data = json.loads(request.body)

            account  = data['email']
            password = data['password']

            if not User.objects.filter(email = account).exists():
                return JsonResponse({'message': 'INVALID_USER'}, status= 401)

            user_id = User.objects.get(email=account)

            if not bcrypt.checkpw(password.encode('utf-8'), user_id.password.encode('utf-8')):
                return JsonResponse({'message': 'INVALID_USER'}, status= 401)

            token = jwt.encode({'account': account}, SECRET_KEY, algorithm=ALGORITHM)
            return JsonResponse({'message': 'SUCCESS', "token": token}, status = 200)
        except KeyError:
            return JsonResponse({'message': 'KEY_ERROR'}, status= 400)
    

먼저 들여쓰기랑 =기준 정렬을 중요시했고 줄은 한칸을 띄우며 사용했습니다.

설명

이번에 처음으로 정규표현식을 이용했습니다. 정규표현식을 처음부터 짜는 부분은 너무 어려워서 다른 곳에서 사용하는 표현식을 가져와서 제가 원하는 조건의 정규표현식으로 수정하여 사용했습니다.

정규표현식에 맞지 않는 값이 들어가며 오류값을 줘야했기에 리턴값으로 형식이 아니다는 메세지를 줬고 400- error코드였기에 status 400을 주었습니다. 그리고 밑에 보면 if User.objects.filter( 을 처음으로 q객체를 이용해봤습니다.
처음에는 같은 조건의 if문을 3개주었지만 filter문에서 or을 이용할때는 q객체로 변경이 가능하다는 조언을 통해 수정을 해봤습니다. 처음에는 정확히 어느 부분의 값이 중복되었는지 알지 못하는데 왜 사용했지? 이런 생각을 했지만 확실히 간소화할 수 있다는 장점이 컸기에 이용을 하게 되었습니다. 그리고 post의 try except문을 통해 keyerror을 꼭 넣어 주어 key값이 들어오지 않으면 Keyerror을 주게 되었습니다.


로그인부분은 처음에는 get을 이용하나 했지만 생각해보니 body에 값을 만들어줘야겠다는 생각을해서 Post를 이용하게 되었습니다. 로그인 부분은 email부분과 password를 이용하게 되었습니다. login 부분은 bcrypt와 jwt토큰을 통해 비밀번호 암호활를 통해 새로운 토큰이 발행되게 하였습니다. 로그인 부분도 에러처리를 다 해줬고 데이터상으로 토큰값을 확인 할 수 있었습니다.

인증, 인가

models.py

from django.db import models

from user.models import User
# Create your models here.

class Posting(models.Model):
    time    = models.TimeField(auto_now_add=True)
    img_url = models.URLField()
    user    = models.ForeignKey(User, on_delete=models.CASCADE)

    class Meta:
        db_table = 'postings'

게시글 등록을 위해 새로운 앱을 만들었고 새로운 models.py를 작성하였습니다. 현재시간, img_url 유저정보가 필요했기에 위 코드처럼 작성하게 되었습니다. time은 처음으로 timefield를 이용했고 그 안에 auto_now_add=True를 사용했습니다. 이부분이 자동으로 내용이입력할 수 있도록 해주었고, user의 정보가 필요했기에 포린키를 통해 참조를 해주었습니다.

views.py

import json, jwt

from django.views import View
from django.http  import JsonResponse

from .models import Posting
from user.models import User
from my_settings import SECRET_KEY, ALGORITHM

class PostingView(View):
    
    def post(self, request):

        try:
            data = json.loads(request.body)
            token      = request.headers['token']

            Posting.objects.create(
            img_url  = data['img_url'],
            user     = User.objects.get(email=jwt.decode(token, SECRET_KEY, algorithms=ALGORITHM)['account'])
            )

            return JsonResponse({'message': 'SUCCESS'}, status= 201)

        except KeyError:
            return JsonResponse({'message': 'KEY_ERROR'}, status= 400)

class Post_updateView(View):

    def get(self, request):

        posting_data = Posting.objects.values()
        return JsonResponse({'posting_data': list(posting_data)}, status = 200)
       

설명

게시글 등록을 위해 클래스 게시물등록을 위한postingview, 게시물표출을 위한 post_updateview를 작성했습니다.

posttingview는 게시글 등록을 위해서 post를 이용하였고, 게시글 등록위해서는 토큰값을 받아야했습니다. 암호화를 한 토큰을 딕셔너리접근을 위해 복호화를 해야 했기에 decode를 이용하게 되었습니다.img_url을 통해 게시글 등록을 하였고, 여기서 시간은 키값을 아무것도 넣어주지 않으면 생성된다는 점도 테스트를 통해 알게되었습니다.

게시물표출을 위해 posting.objects.values()를 이용했는데 .values가 딕셔너리로 저장된 포스팅 정보를 다 가져오는 쿼리셋이었습니다. 이 쿼리셋도 처음 써봤는데 많이 응용할 수 있을 것 같습니다.


후기
많은 기능을 구현한건 아니지만 그 기능들을 구현함으로써 많은 것을 배우고 다른사람들은 어떤식으로 진행했나 비교도 해보고 좋은 경험이 되었던것 같습니다. 처음에는 다른분들이 작성한 글만 보고 정보를 찾았는데 django 공식문서에서 진짜 많은 정보를 얻을 수 있다는것도 경험을 통해 느끼게 되어 더 소중함을 가지게 되었습니다. 아직 개발자로써 많이 부족하지만 천천히 기초를 다져가는 개발자가 되고 싶고, 지금처럼 모르는 부분은 혼자서 이해도 해보고 동료들과 소통을 통해 이해도 해보는 여러 경험과 소통능력을 가진 개발자로 지향해 나가겠습니다.

0개의 댓글