[보안/인증] Session Sprint

sunn·2022년 3월 21일
0

보안/인증

목록 보기
2/2

1. 환경 변수 설정

시작하기에 앞서 .env.example 파일이름을 .env로 바꾼 다음 데이터베이스 관련 환경 변수를 설정해야 합니다.

DATABASE_PASSWORD=PASSWORD // 임의의 비밀번호
DATABASE_USERNAME=root
DATABASE_NAME=authentication

2. 데이터베이스 마이그레이션

시퀄라이즈 마이그레이션 및 시드를 적용하거나 직접 데이터베이스를 수정해야 합니다.
참고

// Sequelize CLI 설치
npm install --save-dev sequelize-cli
// 프로젝트 만들기
npx sequelize-cli init
// 모델 만들기
npx sequelize-cli model:generate --name Users --attributes host:string,user:string,password:string
// 마이그레이션 실행
npx sequelize-cli db:migrate

3. 서버 구현

index.js

  1. 발급받은 https 인증서를 해당 스프린트 디렉토리에 복사합니다. 쿠키 설정은 HTTPS를 사용하는 것을 고려하여 설정하세요.
    app.use(
    session({
     secret: '@codestates',
     resave: false,
     saveUninitialized: true,
     cookie: {
       domain: 'localhost',
       path: '/',
       maxAge: 24 * 6 * 60 * 10000,
       sameSite: 'none',
       httpOnly: true,
       secure: true,
     },
    })
    );
  2. index.js에서 CORS 및 세션 옵션을 설정합니다.
    app.use(cors(corsOptions));

controller/login.js (POST /users/login)

  1. request로부터 받은 userId, password와 일치하는 유저가 DB에 존재하는지 확인합니다.
const userInfo = await Users.findOne({
    where: { userId: req.body.userId, password: req.body.password },
    });
    
    console.log(userInfo)
    // Users.dataValues에 유저 정보 존재
  1. 일치하는 유저가 없을 경우:
  • 로그인 요청을 거절합니다.
    if (!userInfo) {
      res.status(400).send({ data: null, message: `not authorized` })
  1. 일치하는 유저가 있을 경우:
  • 세션에 userId를 저장합니다.
else {
      req.session.save(function () {
        req.session.userId = userInfo.userId;
        res.json({ data: userInfo, message: "ok" });
      });    

controller/logout.js (POST /users/logout)

  1. 세션 객체에 저장한 값이 존재하면
  • 세션을 삭제합니다. (자동으로 클라이언트 쿠키는 갱신됩니다)
    if (!req.session.userId) {
      res.status(400).send()
    } 
    else {
      res.status(200).send();
      req.session.destroy()
    }

controller/userinfo.js (GET /users/userinfo)

  1. 세션 객체에 저장한 값이 존재하면
  • 사용자 정보를 데이터베이스에서 조회한 후 응답으로 전달합니다.
    if (!req.session.userId) {
      res.status(400).send({ message: 'not authorized' })
  1. 세션 객체에 저장한 값이 존재하지 않으면
  • 요청을 거절합니다.
const result = await Users.findOne({
      where: { userId: req.session.userId },
      });
      res.status(200).json({ data: result, message: "ok" });
    }

4. 클라이언트 구현

components/Mypage.js

function Mypage(props) {
  const handleLogout = () => {
    // TODO: 서버에 로그아웃 요청을 보낸다음 요청이 성공하면 props.logoutHandler를 호출하여 로그인 상태를 업데이트 해야 합니다.
    axios
      .post("https://localhost:4000/users/logout", {
        withCredentials: true,
      })
      .then(() => {
        props.logoutHandler();
      });
  };

components/Login.js

  loginRequestHandler() {
    // TODO: 로그인 요청을 보내세요.
    //
    // 로그인에 성공하면
    // - props로 전달받은 함수를 호출해, 로그인 상태를 변경하세요.
    // - GET /users/userinfo 를 통해 사용자 정보를 요청하세요
    //
    // 사용자 정보를 받아온 후
    // - props로 전달받은 함수를 호출해, 사용자 정보를 변경하세요.
    axios
      .post(
        'https://localhost:4000/users/login',
        { 
          userId: this.state.username,
          password: this.state.password
        },
        { 'Content-Type' : 'application/json', withCredentials: true }
      )
      .then((res) => {
        this.props.loginHandler(true);
        return axios.get('https://localhost:4000/users/userinfo', {
          withCredentials: true
        })
      })
      .then(res => {
        let { userId, email } = res.data.data;
        this.props.setUserInfo({
          userId, 
          email
        })
      }) 
  }

세션 기반으로 로그인 인증을 수행하는 서버와 클라이언트를 가이드에 따라 얼추 구현해보았다.
삐질삐질🥲

profile
:-)

0개의 댓글