이제 사용자가 입력할 데이터에 맞춰서 제시할 그래프의 근거자료가 될 통계자료를 모을 차례이다.

이를 토대로 DB 모델에 테이블을 추가해야한다. 

1. 육각형 남자의 조건과 통계자료 찾기

육각형 남자의 기초 통계를 주로 통계청 자료를 이용한다. 자료의 공신력도 중요하지만 저작권이 문제도 중요하기 때문이다.

 

별거아닌 웹페이지라도 괜히 문제거리가 되면 안되니 말이다.

 

나이

연예대상이 될 사람의 나이도 역시 중요하다.

행정동별 연령별 인구현황 (mois.go.kr)

 

행정동별 연령별 인구현황

행정동별 연령별 인구현황 행정동별 연령별 인구현황 해당 연도와 월의 행정기관별로 세대의 인구수를 확인 할 수 있는 연령별 인구현황 (월간) 행정기관코드 행정기관 2024년 02월 계 남 여 총

jumin.mois.go.kr

아마 아래의 데이터들 중에서 가장 정확한 데이터일것이다.

지역

고려 못한 데이터지만 무척 중요하다. 서울 사는 남자가 부산 사는 여자를 만날 확률은 상대적으로 낮기 때문에

 

역시 데이터에 포함되어야 한다고 생각한다.

 

위에 나이 데이터에 같이 포함되어 있다.

 

조금 고민해야 할 사항이 아래에 다른 데이터가 지역별로 분류 되어 있는데 중복 계산되지 않도록 주의할 필요가 있겠다.

 

시도별 연령별 성별 평균 신장 분포 현황 : 일반 (kosis.kr)

 

KOSIS

 

kosis.kr

KOSIS에서 쉽게 찾을 수 있었다.

2012~2022년 까지 남녀 키이다.

생각해보니 2022년 자료만 있어도 충분하지 않은가 하는 의문이 생긴다. 일단 저장.

병역판정검사 현황 - 신장 분포별, 청별 (kosis.kr)

 

KOSIS

 

kosis.kr

남자의 경우 병역판정검사 현황이 정확할것이다. 다만 측정년도를 의미하지 측정대상자의 나이는 오차가 있을 수 있다.

혼인률

2. 연령별/성별/혼인상태별 인구(15세이상,내국인)-시군구 (kosis.kr)

 

KOSIS

 

kosis.kr

이미 혼인을 했다면 대상에서 제외 시켜야 한다. 혼인한 상대로 가리지 않는 무차별 식성이라면 다른 문제겠지만.

체격

연령별 체질량 분포 현황 (kosis.kr)

 

KOSIS

 

kosis.kr

체격의 경우 BMI 수치를 이용하면 될거라 판단했다.

 

외모

외모는 매우 주관적인 요소이기 때문에 직접 수치를 입력하는 것으로 결정했다.

 

예를 들면, 한국 남자 {특정 연령대}의 호감형 외모는 몇 % 라고 생각하십니까?

 

이런 식으로 질문을 만드는 편이 나을듯하다.

 

성격

성격 역시 주관적인 요소이므로 외모와 똑같이 처리할 생각이다.

 

학력

학력의 경우 아쉽게도 학교별 졸업자 통계를 찾기 어려웠다. 그래서 학교별 입학 정원을 먼저 사용하기로 하였다.

 

입학 정원만 실제 입학하는 것도 아니고 더욱이 졸업하는 것은 아니기 때문에 정확한 데이터라고 말할수 없다.

 

더 나은 통계 데이터를 찾을 필요성이 있다.

 

종교

성별/연령별/종교별 인구-시군구 (kosis.kr)

 

KOSIS

 

kosis.kr

2015 조사라서 자료가 좀 오래됐지만 종교가 쉽게 바뀌진 않았을거라 생각하고 이용하기로 했다.

흡연

국가지표체계 | 지표상세정보 (index.go.kr)

 

국가지표체계 | 지표상세정보

 

www.index.go.kr

19년~20년 남녀 흡연 비율이다.

 

연령별 성별이 동시에 표시되지 않은 표라서 아쉽다. 

음주

월간음주율(성/연령별) (kwdi.re.kr)

 

KOSIS

 

gsis.kwdi.re.kr

여러가지 자료가 있어서 하나를 고르기 애매했다.

 

안정적인 직업

 

부모재산

 

노후대비가 된 재산

 

현재 3가지 자료가 빠졌다. 어떤 통계자료를 찾아야할지 막막했다. 자료를 찾는데 너무 시간을 허비하고 있는것 같아서 먼저 프로그래밍을 진행하고 나중에 부족한 자료를 보충하기로 한다.

1. 해싱 알고리즘 적용하기

# db 폴더 - hasing.py

from passlib.context import CryptContext

pwd_cxt = CryptContext(schemes=['bcrypt'], deprecated='auto')

class Hash():
    def bcrypt(password: str):
        return pwd_cxt.hash(password)

    def verify(hashed_password, plain_password):
        return pwd_cxt.verify(plain_password, hashed_password)
    

db 폴더에 hashing 파일을 하나 생성한다.

from passlib.context import CryptContext

암호관련 패키지를 가져온다.

pwd_cxt = CryptContext(schemes=['bcrypt'], deprecated='auto')

해싱 스키마를 bcrypt 로 설정하고 암호화 해시 알고리즘에서 자동으로 추천되는 버전을 사용하도록 설정한다.

 

Hash 클래스에서

class Hash():
    def bcrypt(password: str):
        return pwd_cxt.hash(password)

문자열로 들어온 평서문 암호를 해시화해서 반환하고 (반환한 해시화된 암호는 데이터베이스에 저장된다)

def verify(hashed_password, plain_password):
    return pwd_cxt.verify(plain_password, hashed_password)

암호 확인 작업이다. 사용자가 입력한 평서문 암호와 해시화 된 암호를 비교해서 일치하면 True, 불일치하면 False를 반환한다.

 

# db-db_user_crud.py
from routers.schemas import UserBase
from sqlalchemy.orm.session import Session
from db.models import DbUser
from db.hashing import Hash

def create_user(db:Session, request: UserBase):
    new_user = DbUser(
        username = request.username,
        password = Hash.bcrypt(request.password)
    )
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    return new_user

유저 생성 기능에서 입력 받은 암호를 hash.bcrypt의 매개변수로 보내서 해시화된 암호로 받아와 데이터베이스에 저장한다.

 

이 과정에서 관리자도 직접 암호를 볼수 없다.

 

스웨거 UI를 통해서 hasingtest/test 로 유저를 생성했다.

 

tableplus에서 바로 확인 할수 있듯이 암호가 test가 아니라 해싱된 암호로 데이터베이스에 저장되었다

 

(test/1234와 차이를 바로 확인가능하다.) 

1. 스키마 작성

유저 가입 기능을 구현하기 이전에 데이터 검증모델을 pydantic을 이용해서 스키마 작성을 한다.

 

파일들이 여러개로 늘어나는 문제로 폴더명를 조금 변경하고 파일을 이동시켰다.

 

몇가지 파일을 밑에서 생성할 파일들이다.

 

hexagonMan(루트폴더)

     ---db---database.py, db_user_crud.py, models.py

    db폴더. 데이터베이스 관련 파일

     ---migrations---

    alembic 관련 폴더

    ---routers--- schemas.py, user.py

    라우터 폴더. API관련 실행이 담겨있는 파일들이다.

- main.py

- haxagonMan.db

- alembic.ini

- requirements.txt

 

# routers 폴더 - schemas.py
from pydantic import BaseModel
from datetime import datetime

class UserBase(BaseModel):
   username: str
   password: str

# todo 암호관련 작업 필요하다.

class UserDisplay(BaseModel):
   username: str
   class Config():
       from_attributes = True

class PostBase(BaseModel):
   age: str
   height: str
   education: str
   occupation: str
   residence_location: str
   religion: str
   timestamp: datetime

class CommentBase(BaseModel):
   text: str
   username: str
   timestamp: datetime

routers 폴더에 schemas 파일을 생성하고 코드를 작성하였다.

 

db - models 의 Colunms를 참고하여 작성하였다.

 

암호 관련 작업은 빠져있다.

 

orm_mode 가 from_attribute 로 리네임 됐다는 알람을 띄우기 때문에 변경하였다.

 

스키마는 프론트엔드와 백엔드 사이에서 주고 받을 데이터를 검증하는 거름망이다. 

#routers 폴더 - user.py
from sqlalchemy.orm.session import Session
from routers.schemas import UserBase, UserDisplay
from fastapi import APIRouter, Depends
from db.database import get_db
from db import db_user_crud

router = APIRouter(
   prefix='/user',
   tags=['user']
)

@router.post('', response_model=UserDisplay)
def create_user(request:UserBase, db:Session=Depends(get_db)):
   return db_user_crud.create_user(db, request)

 

프론트엔드에서 요청이 오면 API에서 받아서 데이터베이스에 명령을 하고 그 수행 결과를 다시 반환하는 코드이다. 코드를 살펴보면

router = APIRouter(
   prefix='/user',
   tags=['user']
)

prefix가 없다면 아래와 같다.

@router.post('/user')

여러개의 기능을 작성할때마다 매번 작성해야 되는 부분을 prefix로 줄일수 있다. 

response_model=UserDisplay

사용자가 가입하고 난 다음에 비밀번호와 같이 민감한 정보 다시 반환하지 말고 스키마에 UserDisplay로 정의한 내용한 보낸다. 여기서는 유저네임만 해당한다.

def create_user(request:UserBase, db:Session=Depends(get_db)):

의존성 주입을 통해서 매번 데이터베이스를 열고 실행, 닫는 코드를 반복 작성하지 않고. 

db:Session=Depends(get_db)

이 코드로 해결한다.

# db-db_user_crud.py
from routers.schemas import UserBase
from sqlalchemy.orm.session import Session
from db.models import DbUser

def create_user(db:Session, request: UserBase):
    new_user = DbUser(
        username = request.username,
        password = request.password
    )
    db.add(new_user)
    db.commit()
    db.refresh(new_user)
    return new_user

API로부터 받은 데이터를 데이터 베이스가 직접 추가하고 실행, 새로고침 하는 코드이다. 

 

이제 시범을 해볼 차례이다. code 응답이 200이면 성공이다. response body를 살펴보면 비밀번호는 제외하고 유저네임만 반환되는 것을 확인할수 있다.

1. 데이터 베이스 구축에 앞서 생각해보기

이제 데이터 베이스를 구축한다.

데이터 베이스에 들어갈 테이블과 속성들 나열해 본다.

 

  • 유저 - 유저 이름, 암호화된 비번
  • 작성글 - 육각남 찾기 작성한 내용 관련 데이터, 작성자
  • 리플 - 리플 내용, 작성자

 

각각의 테이블에는 유니크한 데이터베이스 ID가 포함된다. 

 

유저-작성글-리플은 서로 참조하여 검색에 활용할수 있도록 기능 구현해본다.

 

다음으로는 통계관련 테이블이다.

 

  • 키 - 나이별
  • 학력 - sky, 인서울, 지방 거점대학
  • 나이 - 연령별, 지역별
  • 직업 - 대기업, 공기업, 공무원, 중견, 그외, 지역별
  • 종교 - 천주교, 기독교, 불교, 무교
  • 거주지 - 지역별

통계 관련 테이블은 실제 통계 내용을 살펴보고 그 속성을 추가하는게 나아 보인다.

 

2. 데이터 베이스 구축 기본

2-02 모델로 데이터베이스 관리하기 - 점프 투 FastAPI (wikidocs.net)

 

2-02 모델로 데이터베이스 관리하기

* `[완성 소스]` : [https://github.com/pahkey/fastapi-book/tree/v2.02](https://github.com/pahkey/fastapi…

wikidocs.net

참고하였다.

pip3 install sqlalchey

설치하고 요구사항.txt 파일에 추가한다.

#database.py
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

SQLALCHEMY_DATABASE_URL = "sqlite:///./haxagonMan.db"

engine = create_engine(
    SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

Base = declarative_base()

 

database.py를 생성하고 위의 코드를 추가한다.

SessionLocal은 데이터베이스에 접속하기 위해 필요한 클래스
create_engine, sessionmaker 등을 사용하는것은 SQLAlchemy 데이터베이스를 사용하기 위해 따라야 할 규칙이다.

autocommit=False 일종의 자동저장 옵션으로 False는 commit 실행이 있어야 저장된다. True로 해버리면 데이터를 잘못 저장했을때 rollback을 할수 없다는 점을 주의한다.

create_engine은 데이터 베이스에 접속하는 세션수를 제어하고, 또 세션 접속에 소요되는 시간을 줄이고자 하는 용도로 사용한다.

declarative_base 함수에 의해 반환된 Base 클래스는 데이터베이스 모델을 구성할 때 사용되는 클래스이다.

 

3. 데이터베이스 모델링

models.py 파일을 생성하고 코드를 추가한다.

# models.py
from database import Base
from sqlalchemy import Column, Integer, String, DateTime, ARRAY, ForeignKey
from sqlalchemy.orm import relationship

class DbUser(Base):
   __tablename__= 'user'
   id = Column(Integer, primary_key=True, index=True)
   username = Column(String)
   password = Column(String)
   items = relationship('DbPost', back_populates='user')

# todo 암호 관련 작업이 필요하다.

class DbPost(Base):
   __tablename__ = 'post'
   id = Column(Integer, primary_key=True, index=True)
   age = Column(ARRAY(Integer))
   height = Column(ARRAY(Integer))
   education = Column(ARRAY(String))
   occupation = Column(ARRAY(Integer))
   residence_location = Column(ARRAY(Integer))
   religion = Column(ARRAY(Integer))
   timestamp = Column(DateTime)
   user_id = Column(Integer, ForeignKey('user.id'))
   user = relationship('DbUser', back_populates='items')
   comments = relationship('DbComment', back_populates='post')

class DbComment(Base):
   __tablename__ = 'comment'
   id = Column(Integer, primary_key=True, index=True)
   text = Column(String)
   username = Column(String)
   timestamp = Column(DateTime)
   post_id = Column(Integer, ForeignKey('post.id'))
   post = relationship('DbPost', back_populates='comments')

패스워드는 아직 암호화 되지 않고 그대로 받았기 때문에 추가 작업이 필요하다.

 

Dbuser 클래스는 고우 id, 유저명, 암호가 들어왔다.

중요한 점은 DbPost인데 위에 언급한 속성을 리스트로 받을 있게 하였다.

실제로 나이는 20~30대, 키는 175 이상, 학력은 sky~인서울과 같이 복수 응답이 가능해야 하기 때문이다.

 

4. 데이터 베이스 생성

데이터 베이스 생성에는 alembic을 이용한다. 요구사항.txt에 추가한다.

터미널에서 실행한다.

pip install alembic

alembic init migrations
초기화

alenbic.ini 파일에
(... 생략 ...)
sqlalchemy.url = sqlite:///./hexagonMan.db
(... 생략 ...)

migrations-vsrsions-env.py 파일에
import models
추가하고
target_metadata = mymodel.Base.metadata
수정한다.

alembic revision --autogenerate
리비전 파일을 생성하고

alembic upgrade head
업데이트하면 데이터베이스 파일이 생성된다.

 

앞으로 모델 파일이 업데이트가 있을때마다 리비전 파일을 생성하고 업데이트를 하면 내용이 반영된다.

 

# models.py
from database import Base
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey
from sqlalchemy.orm import relationship

class DbUser(Base):
   __tablename__= 'user'
   id = Column(Integer, primary_key=True, index=True)
   username = Column(String)
   password = Column(String)
   items = relationship('DbPost', back_populates='user')

# todo 암호 관련 작업이 필요하다.

class DbPost(Base):
   __tablename__ = 'post'
   id = Column(Integer, primary_key=True, index=True)
   age = Column(String)
   height = Column(String)
   education = Column(String)
   occupation = Column(String)
   residence_location = Column(String)
   religion = Column(String)
   timestamp = Column(DateTime)
   user_id = Column(Integer, ForeignKey('user.id'))
   user = relationship('DbUser', back_populates='items')
   comments = relationship('DbComment', back_populates='post')

class DbComment(Base):
   __tablename__ = 'comment'
   id = Column(Integer, primary_key=True, index=True)
   text = Column(String)
   username = Column(String)
   timestamp = Column(DateTime)
   post_id = Column(Integer, ForeignKey('post.id'))
   post = relationship('DbPost', back_populates='comments')

 

문제가 발생했다.

 

sqlite는 ARRAY형식으로 데이터를 저장하지 못하기 때문에 Column(String)으로 변경할수 밖에 없었다.

 

문자열을 파싱하는 방법으로 처리할수 밖에 없을 듯하다.

tableplus를 통해서 생성된 db 파일을 살펴보면 문제없이 데이터베이스가 생성된 것을 확인할수 있다.

1. CORs 문제 해결

코딩을 시작하기 앞서 CORs문제를 해결한다.

 

리액트를 사용해서 하나의 PC로 작업할 경우 CORs 문제가 생기기 때문에 미리 해결해두고 간다.

 

교차 출처 리소스 공유 - FastAPI (tiangolo.com)

 

교차 출처 리소스 공유 - FastAPI

FastAPI framework, high performance, easy to learn, fast to code, ready for production

fastapi.tiangolo.com

관련 내용을 참고하였다.

 

FastAPI는 8000 포트를 사용하고 React. JS 쪽은 3000포트를 사용한다. 이 포트가 서로 다를 경우 포트 허용목록에 포트를 추가시켜서 데이터가 교신이 가능하도록 설정하여야 한다. 글쓴이가 이해한 수준이 이 정도에 그쳐서 더 자세한 설명을 하지 못한다.

# main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware


app = FastAPI()

origins = [
    "http://localhost:3000",
    "http://localhost:8000",
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_methods=["*"],
    allow_headers=["*"],
)

@app.get('/')
def main():
    return "hello world"

1. 가상환경

 

새로운 프로젝트에 맞게 새 가상환경을 설치하였다.

 

육각남 찾기 프로젝트라서 가상환경명을 hexagonMan으로 정했다.

 

프론트엔드와 백엔드 어디를 먼저할것인지 고민을 했다.

 

웹페이지는 리액트와 HTML, CSS, JS 를 이용해야 되는데 제대로 배우지 않아 많은 시간이 소요될것 같다는 예감이 들었다.

 

상대적으로 백엔드에 FastAPI를 이용한 필요한 기능 구현을 강의를 통해 배운 상태이기 때문에 학습 내용을 빠르게 적용해보 싶었다.

 

그래서 백엔드부터 시작한다.

 

2. requirements.txt 작성

requirements.txt 작성해서 필요한 패키지를 설치한다. 기본적으로 2가지를 설치한다. 필요하면 그때 그때 추가한다.

 

  • fastapi
  • uvicorn

파이참은 문서를 작성하면  미설치한 패키지를 설치할지 물어본다. 터미널을 이용하지 않아도 되므로 편리한 점이 있다.

 

from fastapi import FastAPI

app = FastAPI()

@app.get('/')
def main():
    return "hello world"

 

프로그래머의 관례에 따라 '헬로 월드'를 출력해본다.

 

터미널에서

uvicorn main:app --reload

 

실행 --reload의 의미는 코드를 변경하면 실시간으로 다시 읽어 적용하겠다는 의미이다. 즉, 코드를 입력을 잘못하면 바로 에러이다.

 

브라우져 주소창으로 아래의 주소로 접속하면

localhost:8000

출력 성공이다.

 

localhost:8000/docs

 

FastAPI의 장점인 자동문서화를 통해서 성공을 확인할수 있다.

화면 설계서에 사용될 일종의 규칙을 정리하였다

육각남 찾기 전체 이미지

피그마를 이용해서 구상한 웹페이지를 구체화 해보았다.

 

디자인적으로 훌륭해 보이지 않지만 어떻게 구상해야될지 감이 잡힌다. 색상 배합을 좀 고민해야 될것 같다.

 

육각남 찾기 헤드

 

상단에는 웹페이지 로고와 로그인, 로그아웃 기능을 배치하고 그 아래에 웹페이지 이름을 배치하였다.

 

로고 자리에 웹페이지 이름을 배치하는 편이 좋을 듯하다.

 

로그인과 가입 버튼을 배치하고

 

로그인 상태가 되면 로그아웃 버튼만 배치하는 것으로 바꾼다.

 

로그인, 가입 버튼을 누르면 새창을 띄워서 정보를 입력할수 있도록 한다.

 

인스타그램처럼 사용자의 사진을 넣을 수 있도록 해본다.

 

육각남 찾기 데이터 입력

 

데이터 입력 부분이다.

 

사용자가 데이터를 입력하면 약간의 딜레이 1초정도 후에 오른쪽에 그 결과를 보여준다.

 

예를 들면 "30대 연령의 남자는 전체 인구의 20%입니다" 라는 문구와 함께 그래프를 보여준다.

 

사용자가 입력하는 박스의 색과 오른쪽 그래프 프임색을 일치시켜 진행단계와 그래프의 연관성을 한눈에 알수 있도록 한다.

 

데이터 입력은 직접 입력, 박스 체크 등 몇가지 형태를 고려하여 가장 적합한 형태를 선택한다. 복수 선택이 가능해야한다.

 

현재 외모 아래는 최종 결과 버튼이 필요할듯 하다.

육각남 찾기 그래프

 

오른쪽에 결과 그래프이다.

 

원형 그래프는 하나의 예시이며 다양한 그래프를 사용하여 효과적으로 나타낼수 있도록 한다.

 

그래프 내에 관련된 범례, 데이터 테이블 등 필수 정보가 누락되지 않도록 한다.

 

육각남 찾기 하단

최하단에는 다른 유저의 최근 데이터를 5~10개 정도 공간을 압축하여 보여준다.

 

다른 사용자가 리플을 추가 할수 있는 기능을 넣는다.

 

피그마로 구현하는데 시간이 걸릴것 같아서 구체화된 이미지는 구현하지 않았다.

 

1. 프로젝트의 목적

인터넷에서 육각형 조건을 갖춘 남자 찾기가 어렵다는 글을 보았다. 사용자가 제시하는 조건을 갖춘 육각남(여)가 목표연령층의 몇 퍼센트에 해당하는지를 실존통계를 기반하여 한눈에 알아 볼수 있는 수치를 제공하는 것이 목표이다.

 

육각남(녀)이란? 외모, 성향, 학력, 자산, 직업, 집안이 특출나지는 않아도 빠지지 않아서 6각형 균형을 이루는 조건을 갖춘 남녀를 의미한다.

 

 

2. 필요한 기능(사용자 관점에서)

사용자가 요구하는 조건을 입력한다. DB에 입력된 통계자료에 근거하여 그래프로 실시간 구현하여 보여준다. 

최신 결과 파일을 최하단에 띄운다.

결과에 대해서 서로 댓글을 통해서 소통할수 있는 공간을 제공한다.

결과를 이미지 파일로 생성하여 인터넷 배포가 쉽도록 만든다. 이미지에는 워터마크로 사이트 주소가 포함되도록 만든다.

 

3. 개발에 사용 될 기술 

Python

처음 배운 언어이며 다른 언어를 모르기 때문에 기본적으로 사용할 프로그래밍 언어로 선택.

 

FastAPI

웹프레임 워크로 성능이 뛰어나고 자동문서화로 빠르게 기능확인을 할수 있다는 점이 장점이라서 선택.  타입힌트, 빠른개발, 비동기 처리 등 을 쉽게 구현할 수 있다.

 

React

웹프론트 엔드 기술. FastAPI 강의가 React를 사용하기 때문에 같이 선택. 책을 한권 살펴봤지만 심도 깊게 배우지 못했기 때문에 일부는 공부하고 일부는 chatGPT를 이용해서 기능을 구현할 계획이다.

단일페이지 애플리케이션에 적합하기 때문에 현재 프로젝트의 이미지와 상당히 궁합이 좋다고 생각한다.

 

HTML/CSS/Javascript

웹페이지와 React를 움직이는 도구라서 사용할 수 밖에 없다. 역시 잘 모르기 때문에 공부+쳇GPT의 도움이 필요하다.

 

DB

REDIS 또는 SQLAlchemy를 이용해서 구현할 계획이다.

 

Uvicorn 서버

여러 강의에서 사용한 서버. 다른 서버는 모르기 때문에 대안이 없다.

 

배포 방식

AWS를 사용할지 개인 서버를 구축을 할지 아직 미정이다.

 

Oauth 보안

보안 관련 도구로 Oauth를 사용할 생각이다. 로그인, 로그아웃, 토큰 발행과 저장, 댓글 기능을 구현하기 위해 사용한다.

보안 문제로 사용자 정보가 유출되는 일이 없도록 사용자 정보 아이디와 비번 정도로 최소한으로 제한한다. 

+ Recent posts