SOPT:6回ワークショップ-restaPI、jwt

30499 ワード

追加材料-Neity 16 Velug

jwt


authentication


APIリクエストが使用可能なユーザーであることを確認するプロセス

HTTP特性

  • 非接続性:サーバとサーバが接続を確立すると、サーバ応答が完了し、接続が終了する
  • ステータスなし(ステータスなし)非接続性により、サーバがクライアント
  • を認識できなくなる.

    HTTPでステータスを覚える方法


    cookie


    key-valueペアからなる小さなレコード情報ファイルで、コンピュータに格納されます.

    セッション


    1つの技術は、同じユーザの一連の需要を一定期間にわたって1つの状態と見なし、一致させることができる.

    Cookieセッションの問題


    Cookieはクライアントにローカルに格納されているため、情報が変質したり交換されたりする可能性があります.
    セッションはサーバ上でセッションストレージを使用するため、追加のストレージスペースが必要です.セッション・リポジトリに障害が発生した場合、検証に問題が発生します.

    JWT


    Json Web Token
    クレームトークンに基づく認証方法.
    クライアントのセッションステータスを保存するのではなく、トークンボディに必要な情報を保存して、クライアントが認証として使用できるようにします.

    JWT構成


    Header.Payload.Verify_Signature
    Header:署名で使用されるアルゴリズムについて
    Payload:クレームとして表示されるタグ情報を作成します.クライアントに関する情報が含まれます.
    署名:トークンが変更されていないことを確認します.ヘッダーに指定されたアルゴリズムと秘密鍵には、ヘッダーとペイロードが含まれています.npm install jsonwebtoken
  • config/secretKey.js
  • module.exports = {
        secretKey: 'SecretKeySoptSeRvER',
        options: {
            algorithm: "HS256",
            expiresIn: "1h",
            issuer: "kgy",
        },
        refreshOptions: {
            algorithm: "HS256",
            expiresIn: "7d",
            issuer: "kgy",
        },
    
    }
  • module/jwt.js
  • const jwt = require('jsonwebtoken');
    const { secretKey, options, refreshOptions } = require('../config/secretKey');
    const TOKEN_EXPIRED = -3;
    const TOKEN_INVALID = -2;
    
    module.exports = {
      // jwt 생성
      sign: async (user) => {
        const payload = {
          id: user.id,
          name: user.userName
        };
        const result = {
          accessToken: jwt.sign(payload, secretKey, options),
          refreshToken: jwt.sign(payload, secretKey, refreshOptions),
        };
        return result;
      },
      // jwt 식별
      verify: async (token) => {
        let decoded;
        try {
          decoded = jwt.verify(token, secretKey);
        } catch (err) {
          if (err.message === 'jwt expired') {
            console.log('expired token');
            return TOKEN_EXPIRED;
          } else if (err.message === 'invalid token') {
            console.log('invalid token');
            console.log(TOKEN_INVALID);
            return TOKEN_INVALID;
          } else {
            console.log("invalid token");
            return TOKEN_INVALID;
          }
        }
        return decoded;
      }
    }
  • userController.js
  • signin : async (req, res) => {
            const { email, password } = req.body; // 1. req.body에서 데이터 가져오기
            //2. request data 확인하기, email, password, userName data가 없다면 NullValue 반환
            if (!email || !password) {
                console.log('필요한 값이 없습니다!');
                return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.BAD_REQUEST, responseMessage.NULL_VALUE));
            }
            try{
                //3. 존재하는 아이디인지 확인하기. 존재하지 않는 아이디면 NO USER 반환
                const user = await User.findOne({
                    where : {
                        email : email
                    },
                });
                //4. 비밀번호 확인하기 - 로그인할 email의 salt를 DB에서 가져와서 사용자가 request로 보낸 password와 암호화를 한후 디비에 저장되어있는 password와 일치하면 true
                // 일치하지 않으면 Miss Match password 반환
                const {id, userName, salt, password : hashedPassword} = user;
                const inputPassword = crypto.pbkdf2Sync(password, salt, 10000, 64, 'sha512').toString('base64');
                
                if (inputPassword != hashedPassword) {
                    console.log('비밀번호가 일치하지 않습니다.');
                    return res.status(statusCode.BAD_REQUEST).send(util.fail(statusCode.OK, responseMessage.MISS_MATCH_PW));
                }
                const {accessToken, refreshToken} = await jwt.sign(user);
    
                //5. status: 200 ,message: SIGN_IN_SUCCESS, data: id, email, userName 반환
                return res.status(statusCode.OK).send(util.success(statusCode.OK, responseMessage.SIGN_IN_SUCCESS, {accessToken, refreshToken}));
            } catch (error) {
                console.error(error);
                return res.status(statusCode.INTERNAL_SERVER_ERROR).send(util.fail(statusCode.INTERNAL_SERVER_ERROR, responseMessage.SIGN_IN_FAIL));
            }
        },

    middle ware

    
    const express = require('express');
    const router = express.Router();
    const ut = require('../modules/util');
    const sc = require('../modules/statusCode');
    const rm = require('../modules/responseMessage');
    const jwt = require('../modules/jwt');
    const TOKEN_EXPIRED = -3
    const TOKEN_INVALID = -2
    
    const authUtil = {
        checkToken : async (req, res, next) => {
            const token = req.headers.jwt;
            if (!token) {
              return res.json(ut.fail(sc.BAD_REQUEST, rm.EMPTY_TOKEN));
            }
            const user = await jwt.verify(token);
            console.log('hello', user);
            if (user === TOKEN_EXPIRED) {
              return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.EXPIRED_TOKEN));
            }
            if (user === TOKEN_INVALID) {
              return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.INVALID_TOKEN));
            }
            if (user.id === undefined) {
              return res.status(sc.UNAUTHORIZED).send(ut.fail(sc.UNAUTHORIZED, rm.INVALID_TOKEN));
            }
            req.decoded = user;
            next();
          },
    }
    
    
    module.exports = authUtil;

    REST API

  • URI:Uniform Resource Identifierインターネット上の唯一のアドレス
  • URL:Uniform Resource Locatorネットワーク上のリソースの場所規則
    uriはurlの概念
  • を含む

    REST API


    : REpresentational State Transfer API

    構成


    リソースRESOURCE-URI
    動作:-TTP METHOD
    ひょうじほう

    REST API設計ガイドライン


    1.URIは情報のリソースを表す必要があります。


    リソース名は動詞ではなく名詞ですGET/members/show xGET/hahaha xGET/members o

    2.資源の行為はHTTP方法(GET、POST、PUT、DELETE)を採用する


    REST API注意事項


    1./(スラッシュ)階層関係を表す


    2.URIの最後の文字にスラッシュは含まれません。


    3-(ハイフン)URIによる毒性向上


    4.(下線)URIに使用しない


    5.URIパスの小文字有効


    6.ファイル拡張子はURIに含まれません。

    GET/sopt/server.png xGET/sopt/server/png o

    7.コレクションは複数、装飾は単数

    document는 하나의 객체(문서), collection은 그 객체들의 집합
    
    http://sopt.org/parts/server/users/2

    APIリスト


    API: Application Programming Interface
    クライアントを使用してサーバ上に作成されたAPIのユーザーズガイド.

    APIインベントリコンポーネント

  • API名
  • HTTP METHOD
  • Content-Type
  • 要求ヘッダ/ボディ
  • 応答本体
  • CORS

  • Cross Origin Response Sharing

    schema、host、portの3つは同じ-originであり、1つの違いはcross-origin
  • である.
    Web、サーバのサーバが異なる場合はエラーnpm install cors-app.jsで
    const cors = require('cors');
    app.use(cors());