OAuth 기반 인증 Sprint

const_yang·2022년 2월 2일
0

인증/보안

목록 보기
1/2

Github를 활용하여 OAuth 인증

1) Github > Settings > Developer Settings에서 Client Id와 Client secret key를 생성한다. Authorization callback URL은 나의 웹 앱 URL을 적으면 된다.
2) 생성한 두 정보를 서버의 .env 파일에 저장한다.

Client

App.js

1) Login.js (생략 예정)에서 Github API에 따라
https://github.com/login/oauth/authorize?client_id={내 Client Id}에서 본인 인증 이후에 callback URL로 리디렉션되면서 autorization code를 받게된다. (이후 서버 callback 요청에 req.body로 확인할 수 있다.

class App extends Component {
  constructor() {
    super();
    this.state = {
      isLogin: false,
      accessToken: "",
    };
    this.getAccessToken = this.getAccessToken.bind(this);
  }
  // accessToken을 클라이언트 App.js내 state로 관리하고,
  // getAcceessToken 메소드로 Github에서 넘겨받은 authorization code로 accessToken을 획득한다.
  async getAccessToken(authorizationCode) {
    await axios
    .post('http://localhost:8080/callback', 
    {
      authorizationCode
    })
    .then((data) => {
      this.setState({
        isLogin: true, 
        accessToken: data.data.accessToken
      })
    })
  }

  // componentDidMount는 랜더링 이후 즉시 호출되는 함수이다. 
  // 함수형 컴포넌트의 useEffect Hook과 비슷하다.
  // 시점은 Login 랜더링 후, Mypage 랜더링 후가 되겠다.
  componentDidMount() {
    const url = new URL(window.location.href)
    const authorizationCode = url.searchParams.get('code')
    if (authorizationCode) {
      this.getAccessToken(authorizationCode)
    }
  }
  render() {} // ...생략

Mypage.js

1) https://api.github.com/user 에서 사용자 정보를 받아올 것이다.
2) authorization 헤더에는 Login.js에서 받아온 authorization code를 사용해 획득한 accessToken을 넣어준다.
3) 여러 사용자 정보를 얻을 수 있다.

class Mypage extends Component {

  constructor(props) {
    super(props);
    this.state = {
      images: [],
      name: "", 
      login: "", 
      html_url: "", 
      public_repos: null,
    }
  }

  async getGitHubUserInfo() {
    await axios
    .get("https://api.github.com/user", 
    {
      headers: {authorization: `token ${this.props.accessToken}`}
    })
    .then(data => {
      const { name, login, html_url, public_repos } = data.data;
      this.setState({
        name,
        login,
        html_url,
        public_repos
      })
    })
  }

  async getImages() {
    await axios
    .get(`http://localhost:8080/images`, 
    { 
      headers: {authorization: `token ${this.props.accessToken}`}
    })
    .then((data) => {
      const { images } = data.data
      this.setState({images})
    })
  }

Server

callback.js

1) https://github.com/login/oauth/access_token의 Body에 client id, client secret, authorization code를 전달한다.
2) 전달받은 내용을 data.data에 접근하여 accessToken을 획득하여, 전달한다.

module.exports = async (req, res) => {
  await axios
  .post('https://github.com/login/oauth/access_token', 
  {
    client_id: clientID,
    client_secret: clientSecret,
    code: req.body.authorizationCode
  }, 
  { 
    deaders: {Accept: 'application/json'}
  })
  .then((data) => {
    const accessToken = data.data.access_token;
    res.status(200).json({accessToken})
  })
}

images.js

module.exports = async (req, res) => {
  if (!req.headers.authorization) {
    res.status(403).json({ message: "no permission to access resources" });
  } else {
    res.status(200).json({ images });
  }
};

0개의 댓글