Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[강성구] Sprint11 #309

Merged

Conversation

L1m3Kun
Copy link
Collaborator

@L1m3Kun L1m3Kun commented Aug 23, 2024

요구사항

기본

  • 회원가입

  • 유효한 정보를 입력하고 스웨거 명세된 “/auth/signUp”으로 POST 요청해서 성공 응답을 받으면 회원가입이 완료됩니다.

  • 회원가입이 완료되면 “/login”로 이동합니다.

  • 회원가입 페이지에 접근시 로컬 스토리지에 accessToken이 있는 경우 ‘/’ 페이지로 이동합니다.

  • 로그인

  • 회원가입을 성공한 정보를 입력하고 스웨거 명세된 “/auth/signIp”으로 POST 요청을 하면 로그인이 완료됩니다.

  • 로그인이 완료되면 로컬 스토리지에 accessToken을 저장하고 “/” 로 이동합니다.

  • 로그인/회원가입 페이지에 접근시 로컬 스토리지에 accessToken이 있는 경우 ‘/’ 페이지로 이동합니다.

  • 메인

  • 로컬 스토리지에 accessToken이 있는 경우 상단바 ‘로그인’ 버튼이 판다 이미지로 바뀝니다.

심화

  • react-hook-form 사용

주요 변경사항

  • react-hook-form 도입
  • fetch API를 이용한 refresh token / access token api 호출 시마다 처리

스크린샷

멘토에게

  • 피드백 부탁드립니다 😄

@L1m3Kun L1m3Kun requested a review from wlgns2223 August 23, 2024 09:40
@L1m3Kun L1m3Kun added the 매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다. label Aug 23, 2024
@L1m3Kun L1m3Kun changed the title React 강성구 [강성구] Sprint11 Aug 26, 2024
Comment on lines +53 to +56
{isLogin ? '판다마켓이 처음이신가요?' : '이미 회원이신가요?'}{' '}
<Link to={isLogin ? '/signUp' : '/login'}>
{isLogin ? '회원가입' : '로그인'}
</Link>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이걸 컴포넌트로 만들어서 isLoginprops로 받으면 깔끔하겠네요 !

Comment on lines +23 to +32
const {
isVisible: passwordVisble,
icon: passwordIcon,
handlePasswordVisibility: handlePasswordView,
} = usePasswordVisibility();
const {
isVisible: passwordConfirmVisible,
icon: passwordConfirmIcon,
handlePasswordVisibility: handlePasswordConfirmView,
} = usePasswordVisibility();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

passwordVisibility를 hook으로 만든게 인상적이네요 !

Comment on lines +3 to +9
export const API_PATH = {
AUTH: {
signIn: 'auth/signIn',
signUp: 'auth/signUp',
refreshToken: 'auth/refresh-token',
},
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체로 path 관리는 항상 좋은 것 같습니다 ! 타강의에서도 이렇게 많이 하더라구요.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API 핸들러 클래스에 statusCode별로 처리하는 로직을 추가 하셨네요.

refreshToken을 이용해서 access token을 새로 받아서 요청을 보내는 부분은 잘 동작하던가요?
저는 이 부분을 middleware를 이용해서 똑같은 로직을 구현 했습니다 !
아직 완성은 안되서 아마 에러가 날꺼에요.

export const enum HttpStatusCode {
 OK = 200,
 UNAUTHORIZED = 401,
}

export const handleToken = async (request: NextRequest) => {
 try {
   const res = await verifyToken();
   if (res.statusCode === HttpStatusCode.OK) {
     return true;
   }
 } catch (e) {
   return match(e)
     .when((e): e is HTTPError => e instanceof HTTPError, handleVerifyFail)
     .otherwise((e) => {
       console.error("default error");
       console.error(e);
       return false;
     });
 }
 return false;
};

const handleVerifyFail = (httpError: HTTPError) => {
 return match(httpError.statusCode)
   .with(HttpStatusCode.UNAUTHORIZED, () => handleUnauthorizeError(httpError))
   .otherwise(() => {
     console.error("다른 에러");
     return false;
   });
};

const handleUnauthorizeError = (httpError: HTTPError) => {
 return match(httpError.headers)
   .when(
     (headers) =>
       headers instanceof Headers && headers.has("www-authenticate"),
     handleErrorByRealm
   )
   .otherwise(() => false);
};

const handleErrorByRealm = (headers: Headers) => {
 const { realm, error } = extractRealmAndStatus(headers);

 return match([realm, error])
   .with(
     [AuthTokenType.ACCESS_TOKEN, AuthTokenStatus.EXPIRED],
     handleRenewToken
   )
   .otherwise(() => {
     console.log("모든 쿠키 삭제");
     return false;
   });
};

const handleRenewToken = async () => {
 try {
   // const result = await renewToken();
   console.log("cookie delete");
   const result = await deleteAuthCookie();
   return true;
 } catch (e) {
   console.log("모든 쿠키 삭제");
   return false;
 }
};
const extractRealmAndStatus = (header: Headers) => {
 const authHeader = header.get("www-authenticate")!;
 const realm = getTokenInfo<AuthTokenType>(authHeader, "realm");
 const error = getTokenInfo<AuthTokenStatus>(authHeader, "error");
 return {
   realm,
   error,
 };
};
const getTokenInfo = <T>(authHeader: string, type: string) => {
 const regex = new RegExp(`${type}=([^,]+)`);
 const matched = authHeader.match(regex);
 if (!matched) {
   return null;
 }
 return matched[1] as unknown as T;
};

https://nextjs.org/docs/pages/building-your-application/routing/middleware

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 header 의 쿠키에 JWT 토큰을 넣고 HTTP문서를 막 찾아보니까 www-authenticate 라는 헤더가 있는 걸 찾았어요
인증시에 쓰인다길래, 사실 실무에서 쓰는지는 모르겠지만 한번 헤더와 쿠키를 이용해서 해보는 중입니다.

https://m.blog.naver.com/asd7005201/222446348947

@wlgns2223 wlgns2223 merged commit debdf58 into codeit-bootcamp-frontend:React-강성구 Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
매운맛🔥 뒤는 없습니다. 그냥 필터 없이 말해주세요. 책임은 제가 집니다.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants