react-Hooks,Graphql-CodeGen, Apollo, Refresh-token, Authentication MiddleWare를 사용하여 dev.to 복제 [백엔드 + 프런트엔드](파트-2)

안녕하세요 커뮤니티 여러분, 오늘 저는 최소한의 기능으로 dev.to를 복제하려고 하는 이 기사 시리즈의 두 부분을 작성하고 있습니다. 사용자가 가입/로그인하고 게시물 및 기타 기능을 만들 수 있는 프로토타입이 될 것입니다.

I am doing it for just learning purpose.

If you have not visited the first Part, please understand it first



기술 스택:



NodeJs, ReactJs, Graphql, TypeOrm, TypeGraphql, Typescript, JWT, Apollo-server-express, Jest, Apollo-client, Apollo-link 등..

이 시리즈의 두 번째 부분에서는 Refreshing 토큰, 백엔드 서버용 인증된 미들웨어에 대한 논리를 만들 수 있습니다. 또한 Apollo-Client, React-Bootstrap, Styled-components, Graphql-CodeGen 등을 사용하여 React frontEnd에 대한 설정도 만들었습니다.

쉽게 이해하기 위해 Git 저장소에 2개의 분기를 만들어 더 명확하게 이해했습니다.
*
*

Part-4(GitHub 브랜치)



이 지점에서는 주로 다음과 같은 4가지 작업을 수행했습니다.

토큰 버전 : 이 'tokenVersion'은 기본값 0으로 각 사용자와 함께 저장됩니다. 새로 고침 토큰에 대한 인증, 사용자 로그인 횟수 및 사용자의 모든 세션 종료와 같은 기타 사항을 식별하는 데 도움이 됩니다.

//For authentication, I am changing createRefreshToken method.
export const createRefreshToken = (user: User) => {
  return sign(
    { userId: user.id, tokenVersion: user.tokenVersion },
    process.env.REFRESH_TOKEN_SECRET!,
    {
      expiresIn: "7d"
    }
  );

Refresh Token : 아시다시피 'loginMutation' 쿼리를 누르면 서버가 'Refresh Token'을 쿠키로 다시 보냅니다. 이제 이것을 상상해보십시오. 사용자가 우리의 dev.to에 로그인하여 페이지를 복제하고 새로 고치면 로그인하고 인증된 모든 서비스를 제공하는 메커니즘을 만들어야 합니다. 이를 가능하게 하기 위해 서버에서 새로 고침 토큰에 대한 쿠키를 수락한 다음 이를 확인하는 'POST' API를 만들고 있습니다. 서버 측에서 새로 고침 토큰이 성공적으로 확인되면 최신 '새로 고침 토큰'과 '액세스 토큰'을 사용자에게 다시 보내 사용자가 불필요하게 반복해서 로그인하지 않도록 합니다.

app.use(cookieParser());

  app.post("/refresh_token", async (req, res) => {
    const token = req.cookies.devId;
    if (!token) {
      console.log("token is not valid " + token);
      return res.send({ ok: false, accessToken: "" });
    }

    let payload: any = null;
    try {
      payload = await verify(token, process.env.REFRESH_TOKEN_SECRET!);
    } catch (err) {
      console.log(err);
      return res.send({ ok: false, accessToken: "" });
    }
    console.log("payload :: " + payload.userId);
    //token is valid and we can send him access token now.abnf
    const user = await User.findOne({ id: payload.userId });

    if (!user) {
      console.log("User not found");
      return res.send({ ok: false, accessToken: "" });
    }

    if (user.tokenVersion !== payload.tokenVersion) {
      return res.send({ ok: false, accessToken: "" });
    }

    //Referesh Token
    res.cookie("devId", createRefreshToken(user), {
      httpOnly: true
    });

    return res.send({ ok: true, accessToken: createAccessToken(user) });
  });

따라야 할 단계:
1) 로그인하고 RefreshToken을 받습니다.


2) REST API를 누르기 위해 Postman을 사용하고 그 안에 refreshToken을 쿠키로 설정하십시오.


3) 새로 고침 토큰을 기반으로 새 AccessToken을 가져옵니다.

인증 미들웨어:



인증된 사용자만 사용할 수 있는 graphql 쿼리가 있다고 가정합니다. 이 작업을 수행하기 위해 'type-graphql'의 미들웨어를 사용하고 있습니다.

 @Query(() => String)
  @UseMiddleware(isAuth) //Below is implementation
  me(@Ctx() { payload }: MyContext) {
    return `${payload!.userId}`;
  }

//isAuth.ts
export const isAuth: MiddlewareFn<MyContext> = ({ context }, next) => {
  const authorization = context.req.headers["authorization"];

  if (!authorization) {
    throw new Error("Not Authenticated");
  }

  try {
    const token = authorization.split(" ")[1];
    const payload = verify(token, process.env.ACCESS_TOKEN_SECRET!);
    context.payload = payload as any;
  } catch (err) {
    console.error(err);
    throw new Error("Not Authenticated");
  }
  return next();
};

새로 고침 토큰 취소:



이것을 상상해보십시오. "새로 고침 토큰"이 만료되지 않았고 "비밀번호를 잊어 버렸습니다", 그러면 누군가가 보호 된 graphql 쿼리에 대해 자신을 인증하거나 단순히 모든 logIn 세션을 제거하는 것을 원하지 않습니다. 그런 다음 특정의 tokenVersion을 업데이트 할 수 있습니다 사용자는 refreshTokens의 tokenVersion으로 자신을 확인해야 합니다.

 @Mutation(() => Boolean)
  async revokeRefreshToken(@Arg("userId", () => Int) userId: number) {
    await getConnection()
      .getRepository(User)
      .increment({ id: userId }, "tokenVersion", 1);

    return true;
  }

파트-5 분기



이 브랜치에서는 명령으로 반응 프런트엔드 앱을 설정했습니다.
"npx create-react-app devto --typescript". 설치 후 다음 모듈을 추가하십시오.

yarn add apollo-boost @apollo/react-hooks graphql
yarn add -D @types/graphql

** app.tsx 파일 업데이트 **

import React from "react";
import ReactDOM from "react-dom";
import ApolloClient from "apollo-boost";
import { ApolloProvider } from "@apollo/react-hooks";
import "bootstrap/dist/css/bootstrap.min.css";
import App from "./App";

const client = new ApolloClient({
  uri: "http://localhost:4000/graphql",
  credentials: "include"
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById("root1")
);

graphql/CodeGen 추가



yarn add -D @graphql-codegen/cli
//then
npx graphql-codegen init

설정 단계:






첫 번째 graphql 쿼리 만들기

query Hello {
  hello
}

app.tsx의 useHelloQuery()

import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import { HeaderComponent } from "./components/Header/header.component";
import { GlobalStyle } from "./ui_components/GlobalStyle";
import { ColStyle, RowStyle } from "./ui_components/RowColStyle";
import { RegisterComponent } from "./components/User/Register.component";
import { useHelloQuery } from "./generated/graphql";
const App: React.FC = () => {
  const { data, loading } = useHelloQuery();

  if (loading || !data) {
    return <div>...</div>;
  }

  return (
    <>
      <GlobalStyle></GlobalStyle>
      <RowStyle>
        <ColStyle md={12}>
          <HeaderComponent />
        </ColStyle>
      </RowStyle>
      <RowStyle>
        <ColStyle md={12}>
          <Router>
            <Switch>
              <Route exact path="/" render={() => <div>{data.hello}</div>} />
              <Route exact path="/register" component={RegisterComponent} />
            </Switch>
          </Router>
        </ColStyle>
      </RowStyle>
    </>
  );
};

export default App;


이 기사가 마음에 드시기를 바랍니다. 곧 더 많은 코드로 돌아오겠습니다 :).

좋은 웹페이지 즐겨찾기