IP를 활용한 로그인 고도화

·2022년 6월 12일
0

팀 프로젝트

목록 보기
34/34
post-thumbnail

왜 IP?

웹사이트를 사용하다보면 IP를 체크해서 해당 유저가 맞는지 아닌지 체크하는 사이트가 있다.

평소에 로그인하던 IP가 아니라면 로그인이 안되며 해당 사용자에게 연락을 보내서 체크를 하고
접속한 IP와 국가를 확인할 수 있는 정보를 볼 수 있는 페이지가 존재한다.

네이버의 로그인 IP 조회 페이지

그래서 이러한 것을 구현해보고 싶어서 정보를 찾아봤다.

클라이언트의 IP를 수집하자.

일단 이것을 구현하기 위해서는 접속하는 클라이언트의 IP를 가져와야만 한다.

그럴 때 Node에서는 사용하는 라이브러리가 있는데 바로 request-ip 이다.

https://www.npmjs.com/package/request-ip

이것을 활용하면 request 속에 clientIp에 Ip 정보가 들어있는 것을 확인할 수 있다.

하지만 이것을 그냥 활용을 하면 IPv6의 형태로 되어있어서 ::ffff:0.0.0.0
같은 형식으로 되어있는 것을 확인할 수 있다.

그냥 이것 자체를 활용하는 것도 방법이지만, 다소 불편함이 있다고 생각이 들어서 IPv4의 형태로 바꾸는 것이 좋다고 생각했다.

방법은 main.ts의 app.listen에 이러한 식으로 설정값을 넣어주면 IPv4의 형식으로 사용할 수 있다.

이렇게 수집한 클라이언트 IP를 활용해서 로직을 이렇게 구현했다.

회원 검증 로직

일단 기준점이 존재해야 하기 때문에 첫 번째 로그인을 할 경우에 클라이언트의 IP회원의 DB저장한다.

  1. 로그인을 할 경우 회원 DB에 해당하는 IP가 존재하는지 확인한다.
  2. 해당 IP가 존재하지 않을 경우 허용되지 않은 IP라며 에러메세지를 리턴한다.
  3. Redis에 uuid를 key로 userId와 IP를 values로 5분간 저장한다.
  4. userId 속에 들어있는 핸드폰 번호로 허용되지 않은 IP에서 접속되는 메세지를 발송한다.
  5. 메세지의 본문 속에는 3번에서 생성한 uuid가 포함되어있는 restAPI를 호출 할 수 있는 URL을 함께 보낸다.
  6. 해당하는 회원은 restAPI를 호출할 수 있는 URL을 클릭할 경우 해당하는 IP가 회원의 DB에 추가된다.
  7. 다시 로그인을 시도할 경우 로그인이 가능해진다.

이런 로직으로 구성을 했는데, 생각보다 신경을 써야할 것들이 많았다.


형태가 비슷한 정보를 분리하기

3번 로직의 경우 userId와 IP를 구분을 두지 않고 저장을 했었다.
하지만 userId는 uuid의 옵션을 가지고있다보니 숫자가 맨 마지막에 있을 경우 ip와 구분하는 것이 어려웠다.

그래서 사이에 /를 사이에 추가하여 split("/")로 분리하여 저장했다.

쿼리를 발동시키는 URL 생성하기 with RestAPI & Redis

어플같은 것이 있었다면 구글처럼 버튼을 생성하는 것을 구현해봤을텐데
아직 네이티브를 활용한 어플화 작업이 진행되지 않았고 반응형 작업으로 프론트가 바빠서
혼자서 처리할 수 있는 구조를 만들었어야했다.

그래서 생각을 한 것이 RestAPI를 활용하여 링크를 생성하고
그 링크를 클릭할 경우 API가 호출이 되어 로직이 돌아가는 것을 생각했다.

하지만 그저 URL을 클릭하는 것으로 모든 것을 해결해야하기 때문에
GET이 아닌 메소드는 사용이 불가능하다고 판단이 됐다.

고민을 하다보니 Redis를 활용하면 해결할 수 있다고 판단하여 로직을 구성해봤다.

uuid를 key값으로 쿼리에 필요한 다양한 값들을 values에 저장을 한 후
RestAPI의 Path를 uuid로 적용한 후 호출을 하는 식으로 사용해봤다.

Path 뒷부분은 일정치가 않은데? Prefix Path

이러한 구조를 따다보니 uuid가 Path에 들어가야한다는 문제가 있었다.
옵셔널체이닝으로 ?를 붙여보면 될까? 했는데 해결이 안됐다..^^

그래서 찾아보던 중 이러한식으로 사용할 수 있다는 것을 확인하게 되었다.

: 뒤에 뭘 적어도 상관없지만, 구분을 하기 위하여 uuid를 적어놓았다

흔히 맨 앞부분만 같으면 된다고 부르는 Prefix 방식이였다.

이 부분에 대한 자세한 설명은 nestjs의 공식문서에 서술되어있다.
https://docs.nestjs.com/controllers

창이 자동으로 꺼지면 좋겠는데...

유저가 메세지를 눌렀을 경우 인터넷 창으로 넘어가는데, 그 창이 계속 남아서 직접 끄는 것은 정말 아니라고 생각했다.

그래서 window.close() 하면 꺼진다길래 넣어봤더니 바로 에러....

조금 더 찾아봤더니 이러한 형식으로 쓰면 된다고 해서 넣어놨다.

res.send('<script>window.close();</script > ');


이렇게 IP를 활용한 로그인 고도화 작업을 진행했는데

추가적으로 작업을 하고 싶은 것은 IP가 아닌 MacAddress를 활용하여 다른 인터넷으로 접속해도 상관이 없는 것을 구현하고 싶고
express-device를 활용하여 흔히 게임사에서 많이 쓰는 지정피시를 구현해보고 싶다.

끝!

profile
물류 서비스 Backend Software Developer

0개의 댓글