kookmin-sw / capstone-2023-08

capstone-2023-08 created by GitHub Classroom
1 stars 4 forks source link

DRF Token authentication 구축 완료 #98

Closed wynter122 closed 1 year ago

wynter122 commented 1 year ago

구현 내용

말씀하신대로 Token 을 발급하여 해당 정보를 서버에 저장, 로그인시 Token 을 반환하도록 구현 완료했습니다.

클라이언트단에서 회원가입, 로그인시 전송해아하는 데이터에 변경은 없고, 회원가입, 로그인 성공시 토큰을 반환하도록 했습니다. (회원가입때는 반환하지 않아도 될 것 같은데, 우선 데이터 확인용으로 반환하고있습니다.)

앞으로 진행해야하는 내용

해당 PR이 리뷰되면 찜 반환 목록에서 token에 따라 user 의 정보를 보내주면 될 것 같습니다. (#90 에서 추가 수정 commit 진행)

다만, 궁금한점이 있습니다. 제가 이해한 내용 토큰 사용방식은 클라이언트 단에서 유저의 id & pw 대신 토큰 값으로 요청 해당 토큰을 받으면 서버에서는 id & pw 검증 단계 없이 토큰만으로 user 파악 가능 이렇게 백단에서의 인증 방식을 간소화 시켜주는 기능을 제공하는것 이라고 이해했습니다.

~~그렇다면 클라이언트 단에서는 "토큰" 을 유지하나, 유저의 "id" 를 유지하나 어쨌든 결국 지금 방법도 값을 유지해야 하는건 필요한건데, 이 부분은 클라이언트 단에서 어떻게 구현하시나요?~~

wynter122 commented 1 year ago

89 코멘트 확인을 못했었네요.

요구사항 확인 되었고, 이슈 트래킹 해서 리프레시 토큰 등 수정사항 있으면 다시 커밋 남기도록 하겠습니다.

wynter122 commented 1 year ago

JWT 사용하여 회원가입, 로그인 구현 완료

restframework의 simple_jwt 사용하여 해당 부분 구현을 완료했습니다. 기본 jwt 는 버그가 많이 발생하여서 요즘은 업데이트가 잘 되는 simple_jwt 를 많이들 사용한다고 하네요.

회원가입

우선, 회원가입시 기존과 동일한 로직으로 작동하되 access token 과 refresh token 을 발급합니다. json response 에 문자열로 출력하며, 응답의 쿠키에도 담아서 반환합니다.

클라이언트에서는 data에 user_id, password, user_name, s3_img_url 을 POST 주시면 됩니다.

요청과 응답의 결과입니다.

image

로그인

클라이언트에서는 동일하게 user_id와 password 로 로그인합니다. 응답으로 access token 과 refresh token 을 같이 반환합니다.

image

Viewset 테스트 결과

아직 찜하기 api가 리뷰되지 않아서, 우선 옷 리스트 api 클래스에 IsAuthenticated를 걸어서 토큰 동작 확인했습니다. image

헤더에 아무값도 넣지 않은 GET 요청의 경우 다음과 같이 에러를 반환합니다.

image

AUTH_HEADER_TYPES 를 Bearer 로 지정해서, 헤더에 Bearer로 토큰을 넣어주셔야합니다. 토큰을 헤더에 포함했을 때 성공적으로 결과가 반환됩니다.

image

그 외 수정사항 및 추가 설명

user-id, user-pw 넣어서 보내는 것은 확실한데, 나머지 정보인 user-name, user-img-url는 같이 보내야하는데, 그걸 token안에 넣어야하는지는 모르겠어요 그냥 요청 보낼 때 body에 넣어서 같이 보내면 되는지, authorization안에 같이 넣어서 보내야하는지 알아보시고 보내주시면 될 것 같아요 정보 자체는 flutter secure storage에 저장해놓고 꺼내서 사용하면 됩니다 / 혹은 상태 관리 플러그인을 사용해서 글로벌 변수로 사용하는 방법도 있어요

위 부분은 회원가입시에만 필요한 data 라서 body 에만 담으면 될 것 같습니다.

리뷰후에 피드백 및 추가요청사항 있으시면 merge 하지 마시고 코멘트 남겨주세요

@lucyya99

lucyya99 commented 1 year ago

저희 마이페이지에 고객이름이 들어가서 추가로 요청하면 보내주는 부분 필요할것같습니다 아니면 accesstoken 요청했을 때 body에 담아서 보내주심 될 것 같아요 토큰 관련 오류는 혹시 따로 처리가 안되는건지 궁금합니다 토큰이 만료되었거나 토큰이 일치하지 않을때 401 에러로 위에서 발생하는 오류랑 다르게 처리가 가능할까요? 지금 클라이언트에 보여주는 오류 메세지는 서버에서 보내주는 대로 화면에 띄우도록 하고 있는데, 토큰 관련은 사용자에게 보여주지 않는게 좋을것같아서요..!

wynter122 commented 1 year ago
  1. 마이페이지 api를 말씀하시는 걸까요? 즉, 마이페이지 클릭시 백에 request 를 보낼 예정이신가요? 아니면, 로그인시에 User 정보를 받아서 저장해두고 사용하실 예정이신가요? 전자라면 따로 이슈 파서 진행하는게 좋아 보이고, 후자라면 이번 PR 에서 진행하려고 합니다.

  2. 토큰 만료부분이 제가 구현한게 아니고, simple-jwt 에서 그냥 알아서 제공해줘서... 가능한 방법이 있는지 알아보겠습니다!

lucyya99 commented 1 year ago
  1. 생각해보니까 로그인시 같이 정보를 보내주면 될 것 같아서 이번 PR에서 해당 부분 같이 진행해주시면 될 것 같아요
  2. 제가 들었던 강의에서는 refresh token을 가지고 새로운 access token을 요청하는 api도 존재했는데, 그 부분이 빠진 것 같아요. 저도 구현하려니까 눈에 보여서 다시 말씀드립니다

access token과 refresh token에 대한 flow는 노션 토큰 관련 참고자료 부분 보면 되는데 혹시 몰라 설명드릴게요..!

access token은 노출이 적게 만들기 위해 일부러 기간 만료 시간을 짧게 만들고, 처음 로그인할 때 access token과 refresh token을 같이 보내주므로 만약 refresh token이 있다면 이전에 로그인했었던 이력이 있었다는 것입니다. 클라이언트 입장에서 [서버에서 401 오류]를 보내줬는데 'http://$ip/account/sign-in'로 새로운 토큰을 요청하려는 것이 아니라 [다른 url로 요청]을 했다면, access token이 만료된 것이므로 클라이언트 입장에서는 로그인한 이력이 있지만 잘못된 토큰을 보낸 것이므로 서버에 새로운 토큰을 요청해야 합니다. 클라이언트에서 refresh token을 이용해 새로운 토큰을 발급해달라 = 아직 로그인 유지 기간(=refresh token 만료 기간)이 남았는데, access token이 만료되어 다시 보내서 로그인한 것으로 만들어달라, 즉 새로운 토큰을 보내달라는 뜻입니다. 로직은 복잡한데 명령어는 간단합니다 Header의 'authorization': 'Bearer $refreshToken'로 요청 보낼때가 이 경우에 해당합니다.

제가 말씀드린 건 이 경우고 이 경우에 대한 처리가 있는지 확인해주시고 없으면 변경해주시면 될 것 같아요!

wynter122 commented 1 year ago

Access Token 및 Refersh Token 관련 피드백

우선, 말씀하신 부분 "Access Token 이 만료되었을 시, Refersh Token을 요청하여 새로운 AT 를 발급하는 처리" 에 관해서 말씀드립니다. 해당 기능들은 simpole-jwt 에서 모두 제공하고 있는것으로 확인되며 AT 만료시간 30초, RT 만료일 7일 로 설정하여 테스트 해 보았을 때 결과입니다.

RT를 통한 AT 재발급 방법입니다

다음 url 에 {"referesh" : RT} 를 body 에 담아 POST 요청을 보냅니다

POST http://35.84.85.252:8000/api/token/refresh/ data : { "refresh" : RT }

image

이 부분도 제가 구현하는게 아니고, 커밋내역에 이미 포함되어있습니다.

AT 가 발급되며 30초간 해당 AT는 유효하여 authentication 이 필요한 부분에 접근 가능합니다. 재발급된 AT 로 request 날린 결과입니다.

image
  1. 토큰 만료 시간은 대개 AT 는 2 ~ 7일 RT 는 7 ~ 30일 정도로 설정하는것으로 보이는데 저희는 보안을 크게 신경쓸만큼 짧게 설정할 필요가 없어보여서 AT=7일, RT=30 일 정도로 해도 충분할 것 같습니다.

  2. 말씀하신 400번대 코드는 api test 를 해보면 자체적으로 포함되어있는 것 같습니다

    image

개발자들이 바보가 아니라면 포함을 했을거에요... 이 부분은 프론트에서 테스트 해보는게 좋을 것 같네요. 결론은 지금 부분에서 추가적으로 건드려야 할 것은 없어보이고, 해당 PR 이 approve 되면 나머지 view 들에 권한 추가 하는 부분 진행하면 될 것 같습니다. status code 테스트가 필요하시면 말씀해 주세요. merge 이전에 저랑 로컬에서 테스트해보면 좋을듯합니다. @lucyya99

제가 예지님의 요구사항을 잘 이해한게 맞는지 모르겠네요. 추가적으로 필요한게 있으면 말씀해주세요.

wynter122 commented 1 year ago

User 정보 추가 반환 완료

serializer 를 추가하여 user_id 와 user_name 을 로그인시에 반환하는 코드 추가했습니다.

결과

image

궁금한게 있는데, 저렇게 반환하면 마이페이지에서 추가 API 를 날리지 않아도 nickname 사용이 가능한게 맞나요? 그게 가능하다면, 토큰을 굳이 사용해서 찜목록에 토큰 기반 api 를 날리는 이유가 무엇인지... 잘 이해가 안가서 물어봅니다. (물론 보안측면으로는 인증방식이 좋지만, 가능성만 놓고 따졌을 때, 토큰이 아니면 불가능한것처럼 보였는데 user name 저장이 가능하다면 user id 도 저장이 가능한거 아닌가 해서요)

lucyya99 commented 1 year ago

마지막 질문에 대한 답변 드리자면, 로그인 방식에 대한 제 이해도가 조금 부족했던 것 같습니다..

일단 로그인은 서버와 통신이 있어야 가능하다고 생각했는데, flutter secure storage가 시스템만이 접근할 수 있는 컨테이너에 저장하고, 정보는 아예 거기에서 꺼내 쓰면 되는 거라서 만약에 로그인을 토큰이 아니라 Flutter Secure Storage만 사용하는 방식으로 구현한다고 하면, 어플 삭제하거나 로그아웃 버튼 누르지 않는 이상 로그인 유지가 됩니다. 이렇게 되는 방식을 생각하지 못하고 서버에서 허용하는 시간 이후에는 계속 로그인 요청을 보내야 한다라고만 생각했어요 로그인 여부를 확인할 때도 마찬가지고요.. 현영님이 질문하셔서 다시 생각해보니 보안적 측면 아니면 딱히 필요가 없는 게 맞는 것 같아요

한가지 클라이언트에서 조금 편해지는 부분은, 로그인 여부가 필요한 부분에서 body에 id/pw를 계속 포함해서 보내야하는데, Header에 공통적으로 토큰을 포함하도록 interceptor를 이용해서 Header 교체하는 부분에 대한 코드가 있어서 body에 id/pw를 보내지 않아도 된다는 점 일 것 같아요 이 부분은 찜하기에서도 필요하니까 내일 소정님께 따로 연락하고 설명드리겠습니다

저희 어플에서는 그렇게까지 보안적 요구사항이 크지 않아서 필수적으로 포함해야 했던 부분은 아니었던 것 같아요. 좀 더 확실한 어플 요구사항을 생각하고 부탁드렸어야 했는데 죄송합니다...!

일단 로그인 여부 확인하는 부분 클라이언트에 포함해서 내일 테스트 전까지 최대한 마무리해보도록 하겠습니다 😥

wynter122 commented 1 year ago

저도 로그인 인증 방식 적용해볼 수 있는 기회라 오히려 좋았어요! 죄송할건 전혀 없는걸여...😅 단지 닉네임 저장이랑 비슷한 문제로 인해 토큰을 적용했는데 그러면 닉네임도 저장을 못하는거 아닌가... 이 점이 궁금했습니다. 이러나 저러나 클라이언트나 백 둘 다 편해진 방식이니 제안하신게 더 좋아보여요.

테스트 하실 때 말씀해주세요!

wynter122 commented 1 year ago

예지님과 토큰 기반 api 호출 테스트 완료하였습니다.

테스트 시나리오와 결과는 다음과 같습니다.

  1. 로그인 (AT : 1분, RT: 7일)
  2. 1분 이내로 발급받은 AT로 authentication 필요한 api 호출 -> 성공
  3. 1분 이후 동일 AT 로 2번 수행 -> 401 반환 -> 클라이언트단에서 exception 핸들링
  4. token refresh api 호출 -> AT 재발급됨
  5. 재발급된 AT 로 2번 수행 -> 성공

테스트 기반으로 클라이언트단에서도 헤더와 핸들링을 적절히 구성하면 되겠습니다.

해당 PR 은 merge 합니다.