View

wecode 24일차

오늘은 드디어 backend와 Fronend 개발자가 협업하여 각자 구현한 westagram 기능을

합쳐 정상적인 로그인과 회원가입의 기능을 구현해보는 날이다...!!

다음주부터 시작하는 프로젝트시에도 매우 중요한 과정이기에

다른 포스팅보다 나름 애정을 갖고 포스팅을 해본다.


Session의 공통 학습목표

  1. 로그인 과정에서 일어나는 프론트엔드, 백엔드 간 통신 흐름을 설명할 수 있다.
  2. Access Token 과 JWT의 개념을 이해하고 설명할 수 있다.
  3. (프론트) 백엔드에서 전달 받은 Access Token을 프론트 단에서 어떻게 관리하는지 설명할 수 있다.
  4. (프론트) fetch 함수의 구조를 이해하고, 이를 이용하여 서버에 HTTP 요청을 보낼 수 있다.
  5. (백엔드) 코드를 직접 치기 전에 Postman 을 사용해서 백앤드 API 호출 테스트를 해볼 수 있다
  6. 브라우저에서 로그인 관리를 할 수 있다.
  7. 코드를 직접 치기 전에, POSTMAN을 사용해서 백엔드 api호출 테스트를 해볼 수 있다.
  8. Access token과 JWT의 개념을 이해하고 말로 설명할 수 있다.
  9. Access token을 왜 사용해야하는지 알고, 프론트에서 어떻게 관리하는지 설명할 수 있다.

 

회원가입의 흐름

 

  1. 프론트엔드에게 api와 연결되어있는 엔드포인트와 서버의 ip주소를 알려줍니다.
  2. 해당 엔드포인트로 클라이언트에서 필요한 값(이메일, 비밀번호 등)을 body에 담아 request를 보냅니다.
  3. 받은 이메일의 중복 여부를 database 조회를 통해 확인합니다.
  4. 존재하는 이메일일 경우 Response로 에러메세지와 에러코드를 반환합니다.
  5. 입력 받은 이메일과 비밀번호의 형식이 사이트의 기준과 부합 하는지 확인합니다.
  6. 부합하지 않을 경우 Response로 에러메세지와 에러코드를 반환합니다.
  7. 부합할 경우 database에 해당 회원의 정보를 저장하고 SUCCESS 메세지와 상태코드 201을 Response로 반환합니다.

프론트 : 제이슨형태로 요청을 백앤드에게 전달 => 백앤드 : json.loads로 딕셔너리형태로  변경

* endopoint : 요청을 보내는 주소를 의미 *


로그인의 흐름

  1. 프론트엔드에게 api와 연결되어있는 엔드포인트와 서버의 ip주소를 알려줍니다.
  2. 해당 엔드포인트로 클라이언트에서 필요한 값(이메일, 비밀번호)을 body에 담아 request를 보냅니다.
  3. 받은 이메일이 유효한 회원인지, database 조회를 통해 검증합니다.
  4. 존재하지 않는 이메일일 경우 Response로 에러메세지와 에러코드를 반환합니다.
  5. 존재하는 이메일일경우, 회원의 비밀번호와 입력 받은 비밀번호가 일치하는지 확인합니다.
  6. 일치하지 않을 경우 Response로 에러메세지와 에러코드를 반환합니다.
  7. 일치할 경우 해당 회원을 식별할 수 있는 값을 담아 token을 생성해 Response로 반환합니다.

‼️설정 주의‼️    프론트서버 -> 백앤드 서버로 들어올수있게 허용
corsheaders,    allowed_host, runserver 0:8000

  • corsheaders : 내 로컬 서버에서 외부접속 허용
  • Allowed_Host : 특정IP만 허용할 수있게 하는 기능이나, 여기서는 '*'로 저장하여 모든 아이피의 접속을 허용해주어야함
  • python manage.py runserver 0:8000 으로 서버를 켜주어야함.
    : 본래 서버 실행시 0:8000가 생략되어있다.(원본: 0.0.0.0:8000)   0.0.0.0 => 모든아이피 허용한다는 뜻

내 아이피주소(백엔드)  : 10.58.7.215:8000

아래 url을 프론트의 fetch에 넣어줘야함.
(이때, 프론트와 백앤드는 같은 local network를 사용하여야함.!!! )

회원가입 : 10.58.7.215:8000/users/signup

로그인 : 10.58.7.215:8000/users/signin

 


FRONTEND 구현

< 회원가입 >

이메일 중복 / Key값 불일치/ 패스워드 형식 오류(PASSWORD FORM ERROR)/ 회원가입 성공(CREATE)

  goToMain = () => {
    fetch("http://10.58.7.215:8000/users/signup", {
      method: "POST",
      body: JSON.stringify({
        name: "강남11",
        email: this.state.id,
        password: this.state.pw,
        cell_number: "010-2344-2423",
        address: "서울시 강남구 서초동 124",
        birthday: "2020-03-02",
        sex: "여",
      }),
    })
      .then(response => response.json())
      .then(result => console.log("결과: ", result));
  };

< 로그인 >

로그인성공(토큰 획득) / 로그인 실패(비밀번호잘못 입력) / 계정잘못입력 / Key 값 불일치 

goToMain = () => {
    fetch("http://10.58.7.215:8000/users/signin", {
      method: "POST",
      body: JSON.stringify({
        name: "강남11",
        email: this.state.id,
        password: this.state.pw,
        cell_number: "010-2344-2423",
        address: "서울시 강남구 서초동 124",
        birthday: "2020-03-02",
        sex: "여",
      }),
    })
      .then(response => response.json())
      .then(result => console.log("결과: ", result));

onclick했을 때 , handleLogin함수 실행, fetch함수에 인자가 2개 들어간다.

URL과 dictionary(method, body 등 포함) => 백엔드에 요청을 보냄.

로그인 성공시 백앤드는 프론트로 토큰을 포함한 응답을 보내고, 프론트에서는 localStorage를 통해 토큰을 저장한다.


BACKEND 구현

모두가 들어올수 있게,, 백엔드가 서버를 킬때,  python manage.py runserver 0:8000으로 킨다.

에러원인 => Network의 header값에서 알 수 있다.

status 에 failed이 있으면 통신 자체가 안된것.

디버깅

백엔드 print(data)를 작성하여 로 받은 값을 확인할 수 있다.

< 회원가입 >

class SignUpView(View):
    
    def post(self,request):
        data = json.loads(request.body)
        
        try:
            check_password     = re.compile("^(?=.*[A-Za-z])(?=.*\d)(?=.*[$@$!%*#?&])[A-Za-z\d$@$!%*#?&]{8,}$")
            password_validator = check_password.match(data['password'])

            if not password_validator:
                return JsonResponse({"MESSAGE" : "PASSWORD FORM ERROR"}, status=404)
            
            if len(User.objects.filter(email=data["email"])) > 0:
                return JsonResponse({"MESSAGE" : "EMAIL DUPLICATION ERROR"}, status=404)
                
            check_email     = re.compile('^[a-zA-Z0-9+-_.]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')
            email_validator = check_email.match(data["email"])

            if not email_validator:
                return JsonResponse({"MESSAGE" : "EMAIL FORM ERROR"}, status=404)

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

            User.objects.create(
            name        = data["name"],
            email       = data["email"],
            password    = decoded_hash_pwd,
            cell_number = data["cell_number"],    
            address     = data["address"],
            birthday    = data["birthday"],
            sex         = data["sex"]
            )  
            return JsonResponse({"MESSAGE" : "CREATE"}, status=201)

        except KeyError as e:
            return JsonResponse({"MESSAGE" : "KEY_ERROR"}, status=400)

 

< 로그인 >

class SignInView(View):
        
    def post (self,request):
        data = json.loads(request.body)
        
        try:
            if not User.objects.filter(email=data["email"]).exists():
                return JsonResponse({"MESSAGE" : "INVALID_USER"}, status=401)
            
            entered_pwd       = data['password']
            encoded_enter_pwd = entered_pwd.encode('utf-8')

            user_pwd         = User.objects.get(email=data["email"]).password
            encoded_user_pwd = user_pwd.encode('utf-8')

            user_id = User.objects.get(email=data["email"]).id           

            if bcrypt.checkpw(encoded_enter_pwd,encoded_user_pwd):

                access_token = jwt.encode({"user_id": user_id}, SECRET_KEY, algorithm='HS256')

                return  JsonResponse({"MESSAGE": "SUCCESS", "TOKEN" : access_token}, status=200)
            else:    
                return  JsonResponse({"MESSAGE": "LOGIN_FAIL"}, status=400)
                


        except KeyError as e:
            return  JsonResponse({"MESSAGE": "KEY_ERROR"}, status=400)

 


추가 에러 발견 후 코드 수정사항 

Error1 : 2021-13-11 로 날짜입력하였을 때 SyntaxError

날짜 형식 불일치 => DATATYPE_ERROR 또는 Value에러로 잡을수 있음.

=> 날짜를 2021-13-11 로 입력하였을 때 에러나도록 SignupView에 아래 코드 추가

from django.core.exceptions import ValidationError

	except ValidationError as e:
            return  JsonResponse({"MESSAGE": "DATA_FORMAT_ERROR"}, status=400)

 

Error2 : 전화번호 형식이  불치해도 입력이 됨.( '-' 가 빠지거나, 총 13자리가 안될 경우)

 

전화번호 형식 불일치

=> 전화번호도 정규표현식으로 아래와 같이 validation 해보았다^ㅡ^

 check_phone_number     = re.compile('\d{3}-\d{3,4}-\d{4}')
 phone_number_validator = check_phone_number.match(data["cell_number"])
 
 if not phone_number_validator:
 	return JsonResponse({"MESSAGE" : "PHONE_NUMBER_FORM ERROR"}, status=400)
Share Link
reply
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31