ucharles / Comrade

일정 조율 웹 어플리케이션
1 stars 1 forks source link

react-admin의 checkAuth, getPermission에 대해 #24

Closed ucharles closed 2 years ago

ucharles commented 2 years ago

react-admincheckAuthgetPermission을 잘못 이해하고 사용했던 것 같습니다. 이 PR의 수정이 필요합니다. https://github.com/ucharles/Comrade/pull/21 관련 이슈 https://github.com/ucharles/Comrade/issues/11

결론

수정 방법

checkAuth

checkAuth: () => {
  if (!cookies.get("LoggedIn")) {
    return Promise.reject();
  }

  const request = new Request(
    process.env.REACT_APP_BACKEND_URL + "/users/token-check",
    { method: "GET", credentials: "include" }
  );

  return fetch(request)
    .then((response) => {
      return response.status >= 200 && response.status < 300
        ? Promise.resolve()
        : Promise.reject();
    })
    .catch(() => {
      throw new Error("Network error");
    });
},

logout

백엔드 API를 수정했습니다. 로그아웃 호출 시 403 에러를 뱉지 않게 했습니다. 아래의 코드로 로그아웃 처리가 가능합니다.

logout: () => {
  const request = new Request(
    process.env.REACT_APP_BACKEND_URL + "/users/logout",
    { method: "GET", credentials: "include" }
  );

  return fetch(request)
    .then((response) => {
      if (response.ok) {
        return Promise.resolve();
      } else if (response.status < 200 || response.status >= 300) {
        return Promise.reject();
      }
    })
    .catch(() => {
      throw new Error("Network error");
    });
},

getPermission

새롭게 추가된 달력 권한 습득 API를 이용하여 권한을 습득하시면 될 것 같습니다. GET /api/calendar/admin

이와 같은 객체로 리턴됩니다. { calendars: [ {calendarId: "xxx", isAdmin: true}, {...} ] }

관련 이슈: https://github.com/ucharles/Comrade/issues/20

문서 내용

checkError

checkAuth

getPermission

  • a string (e.g. 'admin'),
  • an array of roles (e.g. ['post_editor', 'comment_moderator', 'super_admin'])
  • an object with fine-grained permissions (e.g. { postList: { read: true, write: false, delete: false } })
  • or even a function
yypp1226 commented 2 years ago

설명이 좀 부족했던거 같은데, react-admin에서 getPermissions의 목적은 말씀하신대로가 맞습니다. 하지만 getPermissions를 checkAuth의 대용으로 사용하고자 했던 이유는 페이지 접근 권한 설정때문입니다. 아래 과정을 거쳐서 결정하게 되었는데요..

  1. Authprovider에서 context 사용이 힘듬
  2. 페이지 접근 권한 설정을 context로 컨트롤하기에 어려움
  3. react-admin의 주목적(관리자 페이지 제작)에 맞춘 permission으로 페이지 접근권한을 설정하도록 함(checkAuth도 페이지 랜딩, 이동 등마다 실행되지만 reject가 올바르게 작동하지 않았음. URL로 직접 접근시 접근이 제한되지 않음..)
  4. permission으로 접근권한을 설정하자 각 페이지마다 checkAuth, getPermissions를 둘다 실행하게 되므로, 한가지만 사용자인증으로 사용하는게 낫다고 판단.

애초에 react-admin이 관리자용 페이지를 쉽게 만들기 위함이 목적인듯 하여 저희가 만드는 웹이랑은 거리가 좀 있어보이긴합니다..

정현씨가 말씀하신대로 하려면 아래 두가지 방안이 있을 것 같습니다. 1.Authprovider에서 인증 Context를 사용할 수 있도록 좀 더 연구해서 수정하는 방법 2.react-admin 포기...

ucharles commented 2 years ago

위 수정 코드를 반영하는 것으로 3번은 해결됩니다. 나머지 1, 2, 4번도 이 문서를 참조하시면 해결되지 않을까 싶습니다. 4.0 업데이트에 맞춰 자세한 문서가 추가되었습니다. https://marmelab.com/react-admin/doc/4.0/Permissions.html

yypp1226 commented 2 years ago

서버요청이 없는 페이지의 경우 3번이 일단 해결되지 않습니다.. URL로 접근이 가능합니다. checkAuth를 실행하지만 페이지 로드는 되고요. 그 다음 다른 메뉴로 접속하려고 하면 로그인 페이지로 리다이렉트 됩니다.

현재 각페이지에서 서버 요청이 되지 않고 있기 때문에, URL접속시 페이지 로드가 가능한 것 같고 서버 요청이 있고 서버의 check-auth 미들웨어를 거친다면 로그인 페이지로 리다이렉트 시킬 수 있습니다.

하지만 서버 요청이 없는 페이지(예:캘린더생성(/calendar/new))는 페이지 접근이 가능할 수 밖에 없습니다.

ucharles commented 2 years ago

수정 예의 checkAuth처럼 서버 요청을 넣으면 해결이 될 것 같습니다만, 이곳에서 서버 요청을 하지 않으려는 이유는 무엇인가요? checkAuth에서는 인증 관련 요청만, getPermission에서는 권한 관련 요청만 하게 함으로써 기능적으로 분리를 하는 것이 좋아보입니다. 실제로 의도대로 동작이 되는 것을 확인했습니다.

checkAuth의 정확한 동작방식은 이렇습니다.

  1. 페이지의 탐색, 표시, 생성, 편집때마다 호출됨
  2. resolve인 경우 OK, reject인 경우 logout 호출
  3. logout에서 resolve가 호출되면 로그아웃. 로그인 화면으로 리다이렉트.

때문에 정확히는 페이지에 서버 요청이 없어서 URL으로 접근이 가능한 것이 아니라, checkAuth에서 reject 되어야 할 올바른 조건이 없기 때문에 그렇습니다. 혹은 logout 에서 resolve를 호출하지 않은 경우, 로그아웃 처리 & 로그인 페이지로 리다이렉트가 되지 않습니다. 이 경우엔 reject에 별도로 리다이렉트 설정이 필요할 수도 있습니다.

ucharles commented 2 years ago

좀 더 조사해본 결과는 아래와 같습니다.

  1. <CustomRoutes> 에서는 checkAuth 를 호출하지 않음. checkAuth에서 Promise.reject()를 시켜도 logout을 호출하지 않음.
  2. 컴포넌트의 최상단에 별도로 useAuthenticated를 사용하여 authProvider를 호출할 수 있으나, 아주 잠깐 페이지의 내용이 노출되는 현상 발생. (공식 문서에도 관련된 내용이 기재되어 있음)
  3. 2의 화면 노출 현상을 방지하기 위해 useAuthState를 사용하여 authProvider의 응답이 있기 전까지 페이지 표시를 하지 않을 수 있음. 페이지 접속을 완전 차단하는 형태는 아니라 2번처럼 아주 잠깐 페이지의 내용이 노출됨. (노출 시간은 2번보단 짧음. 화면이 깜빡이는 정도)
  4. 페이지 접속을 화면 깜빡임 없이 완전 차단하기 위해선 getPermission 사용이 불가피한 듯함.
  5. route / (dashboard) 에서 checkAuth가 작동했던 이유는 <CustomRoutes>가 아니었기 때문. (서버 요청과는 관련 없음. 서버 요청은 되지 않고 있었다.)
ucharles commented 2 years ago

getPermission을 사용하는 것으로 결정. Close 하겠습니다.