본문으로 바로가기
 

쉽게 알아보는 서버 인증 1편(세션/쿠키 , JWT)

앱 개발을 처음 배우게 됐을 때, 각종 화면을 디자인해보면서 프론트엔드 개발에 큰 흥미가 생겼습니다. 한때 프론트엔드 개발자를 꿈꾸기도 했었죠(현실은 ...) 그러나 서버와 통신을 처음 배��

tansfil.tistory.com

 

React + Node.js Express: User Authentication with JWT example - BezKoder

Build React + Express Authentication with JWT, React Router, Axios, Sequelize, Login & Registration example (with Authorization)

bezkoder.com

 

 

 

이번 프로젝트를 react + express로 진행했으므로 이들을 기준으로 설명하겠습니다.

리프레쉬 토큰이 없는, 일반 JWT 환경에서는 다음과 같이 작업하면 됩니다.

 

 

회원가입

 

react) 유저가 입력한 정보를 받아 post로 백단에 날린다.

 

back)

 

우선 해당 식별자로 가입한 사람이 없는지 먼저 체크한 후 (빈 비밀번호, 이미 존재하는 닉네임 등등도 처리)

플레인한 비밀번호를 받아 hash + salt 화를 진행한다. (bcrypt를 활용한 해쉬, 솔트)

해쉬화된 비밀번호와 함께 유저 정보를 DB에 저장한다.

res.json으로 결과를 React에게 반환한다.

 

* caustion!

 패스워드는 반드시 PBKDF2 이상의 보안성을 가지는 해시 함수로 해싱해야 한다. 대부분 SHA를 쓴다. 그렇지 않으면 개인정보보호법 29조 위반으로 과태료 폭탄을 맞을 수 있다.

 

 

react) post의 결과를 받아 에러면 에러창을 띄우고 성공이면 자동으로 로그인 처리를 하던 다시 로그인을 하라고 알림을 주던 후속 처리를 해주자.

 

로그인

 

react) 유저가 입력한 정보를 받아 post로 백단에 로그인을 요청한다.

 

back

 

유저가 입력한 식별자(idemai)를 이용해 DB에서 찾는다.

유저가 입력한 플레인한 비밀번호를 bcrypt.compare를 활용해 해쉬화된 비밀번호와 일치하는지 확인

(기존 암호를 복호화하여 비교하는 방식보다 합리적임)

 

비밀번호가 같다면 만료일을 설정한 JWT를 생성한 후 생성한 JWT를 프론트 단의 쿠키에 저장하자 백단에는 아무것도 저장할 필요가 없다. 그냥 검증만 해주면 되니까.

 

=> 세션 방식의 인증이 Redis를 확장해주는 방식으로 관리를 해야하지만 JWT는 DB에 저장할 필요가 없어서 인증을 위한 서버를 관리하지 않아도 된다는 장점이 있다. 꿀!

 

(프론트 단에서 jwt를 어디에 저장해둬야 하는 지에 대한 문제가 있다. 쿠키는 LS나 세션에 비해 안전하다는 평이 있다. 그런데 필자는 요새 그냥 LS에 저장해두고 있다. 왜냐면 편해서...)

 

jwt를 만드는 방식은 다른 포스트에서 다뤘습니다. payload, 비밀번호, conf 순으로 적어준다고만 알아둡시다.

jwt.sign(
  { UserId: user._id, nickname: user.nickname },
  process.env.JWT_SECRET,
  {
     expiresIn: "7d",
  }
);

 

프론트단의 쿠키에 x_auth에 저장해둡니다.

res.cookie("x_auth", user.token, {
  maxAge: 1000 * 60 * 60 * 24 * 7,
  httpOnly: true,
})

 

여기서, 프론트와 백엔드의 주소가 다른 경우 쿠키 전송이 되지 않으니 다음과 같은 세팅을 해주어야 합니다.

https://www.zerocho.com/category/NodeJS/post/5e9bf5b18dcb9c001f36b275

 

 

 

아니면 LS에 저장해둬도 됩니다.

res.json({token: jwt를 넣어 보내자})

 

 

react) 로그인 실패면 실패를 처리하고 성공이면 백단으로 받은 정보(jwt를 비롯한 유저 정보들)를 원하는 곳에 저장해주자. 필자는 LS에 저장했다.

 

🚨 주의! LS에는 객체 형태로 정보를 저장할 수 없습니다. JSON.stringfy를 해줘야 합니다. 나중에 사용할 때는 JSON.parse를 통해 파싱한 다음 사용하면 됩니다.

localStorage.setItem(
  "ZzalZzal",
  JSON.stringify({ token, userId, nickname, email })
);

 

 

 

유저 권한(JWT) 체크

 

react) 특정 권한이 필요한 페이지에 접속하려고 한다. (HOC을 통해 감싸주자)

 

function withAuthHoc(WrappedComponents) {
  const AuthenticationCheck = (props) => {
    const [userData, setuserData] = useState("");
    useEffect(() => {
      axios.post("/auth/jwtauthcheck").then((res) => {
        setuserData(res.data);
        if (!res.data.isAuth)
          return props.history.push("/", {
            data: "로그인한 회원만 업로드할 수 있습니다.",
          });
      });
    }, []);
    return <WrappedComponents user={userData} />;
  };
  return AuthenticationCheck;
}

 

 

back) 권한을 체크하는 미들웨어(위 코드에서는 /auth/jwtauthcheck)를 만들어 통과시키고 접속하려는 유저의 정보를 추출하여 앞단에 res.json으로 전송한다.

 

authRouter.post("/jwtauthcheck", jwtMiddleware, (req, res) => {

  .... 생략 
  
  // 미들웨어에서 유저를 못찾았으니 인증 실패
  if (!req.user) return res.json({ isAuth: false });
  
  // 유저가 있다는 이야기니 인증 처리
  return res.json({
    isAuth: true,
    userId: req.user._id,
    nickname: req.user.nickname,
  });
});
const jwtMiddleware = async (req, res, next) => {
  // 쿠키 내부에 저장된 토큰을 가져온다.

  let token = req.cookies.x_auth;

  jwt.verify(token, process.env.JWT_SECRET, async (err, decoded) => {
    if (err) return res.json({ isAuth: false, message: "token decode 실패" });

    // 토큰을 복호화한 후 유저를 찾는다. (token 생성시 _id값을 주었음)
    const user = await User.findById({ _id: decoded.UserId }, (err) => {
      if (err)
        return res.json({
          isAuth: false,
          message:
            "백단 token 복호화에는 성공했으나 해당 User를 찾는데 실패했습니다. 로그아웃하셨군요",
        });
    });

    // 다음 컨트롤러에서 req를 빼다 쓰기 위해 저장
    req.token = token;
    req.user = user;
    next();
  });
};

 

 

react) 돌려 받은 결과를 HOC에서 판단하여 권한이 있으면 해당 컴포넌트를 렌더하고 없으면 리다이렉트시킨다.

 

 

로그아웃

 

react) 로그아웃 버튼을 누르는 등 이벤트가 발생하면 토큰을 LS에 저장한 경우 그냥 LS만 지워주면 끝. 만약 쿠키에 저장했다면 백단으로 로그아웃 post를 날린다.

 

back) 우선 로그아웃을 요청할 수 있는 유저는 로그인이 되어 있는 상태일 터이므로 jwt 검증 미들웨어를 거친 후에 쿠키를 삭제해주면 됩니다. 

 

 

 

darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체