본문 바로가기
JavaScript/Node.js

Node) 사용자 인증 정보 확인 후 다음 미들웨어에게 해당 정보 넘겨주기

by 박채니 2023. 2. 3.
안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.

 

사용자 인증 정보 확인 후 다음 미들웨어에게 해당 정보 넘겨주기

 

API에서 사용자 정보를 확인하고 정보가 없다면 오류를 던져주는 식으로 구현을 했었지만 코드가 중복되어 이를 미들웨어로 분리시켰습니다.

해당 미들웨어에서는 사용자 정보 확인 → 정보가 없다면 상황에 따라 null | Error / 정보가 있다면 userId를 넘겨줍니다.

 

Auth.ts - getUserFromToken

/**
 * jwt 토큰 검증
 */
const getUserFromToken = async (req: Request) => {
    const token = req.headers.authorization;

    if (!token) {
        return null;
    }

    return jwt.verify(token.replace(/^Bearer\s/i, ""), process.env.JWT_SECRET_KEY!, {
        ignoreExpiration: true,
    }) as JwtPayload;
};

 

AuthCheck.ts

import { NextFunction, Request, Response } from "express";
import User from "../models/User";
import { getUserFromToken } from "../utils/Auth";

/**
 * 로그인이 반드시 필요한 기능을 사용할 때
 * loginUser가 존재하는지 확인하는 미들웨어
 */
const loginUserChecker = async (req: Request, _: Response, next: NextFunction) => {
    const user = await getUserFromToken(req);

    if (!user || !user.id) {
        throw new Error("Not Found LoginUser");
    }
    req.userId = user.id;
    next();
};

/**
 * 로그인이 필요하지 않은 기능을 사용할 때
 * loginUser 혹은 anonymousUser가 존재하는지 확인하는 미들웨어
 */
const anonOrLoginUserChecker = async (req: Request, _: Response, next: NextFunction) => {
    const user = await getUserFromToken(req);

    if (user) {
        req.userId = user.id;
        return next();
    }

    // 비로그인 사용자일 때 QueryString | body에서 넘어오는 user_id 체크 -> 둘 다 없다면 undefined
    let requestedUserId = req.query.user_id ?? req.body.user_id;
    if (requestedUserId) {
        const anonymousUser = await User.findOne({ where: { email: requestedUserId } });
        if (anonymousUser) {
            req.userId = anonymousUser?.dataValues.id;
            return next();
        }
    }
    req.userId = req.userId ?? null;
    next();
};

export { loginUserChecker, anonOrLoginUserChecker };

로그인이 반드시 필요한 기능은 token이 존재하지 않다면, Error

로그인이 반드시 필요하진 않은 기능은 token이 존재하지 않는다면, Querystring에서 넘어오는 user_id를 체크해주고 이를 넘겨주거나 null를 넘겨줍니다.

(비로그인 사용자는 GUID 형태로 query에 붙여 보내줌)

 

이 때, 해당 userId를 API에서도 사용할 수 있어야 하기 때문에 Request 객체에 담아준 후 다음 미들웨어를 호출해주었습니다.

 

여기서 Request 객체에 userId 이라는 속성은 존재하지 않으니 오류가 발생하게 됩니다.

(Property 'userId' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs, Record<string, any>>'.)

 

따라서 해당 객체에 userId라는 속성을 부여해주어야 합니다.

src/@types/express.d.ts

declare namespace Express {
    export interface Request {
        userId?: number | null;
    }
}

 

여기까지만 하면 컴파일 시 동일한 오류가 또 발생하게 됩니다.

여기서 굉장히 헤맸는데..^^ 아래 게시글들을 보고 해결!

https://velog.io/@sinf/error-TS2339-Property-user-does-not-exist-on-type-Reqeust

 

error TS2339: Property 'user' does not exist on type 'Reqeust'.

error TS2339: Property 'user' does not exist on type 'Reqeust'.

velog.io

https://techbless.github.io/2020/03/12/ts-node%EC%97%90%EC%84%9C-typeRoots-%EC%84%A4%EC%A0%95%EC%9D%B4-%EC%9E%91%EB%8F%99%EB%90%98%EC%A7%80-%EC%95%8A%EB%8A%94-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0%ED%95%98%EA%B8%B0/

 

ts-node에서 typeRoots 설정이 작동되지 않는 문제 해결하기

TypeScript, Node.js, 알고리즘, 자료구조, 데이터베이스, 개발 팁, 각종 문제 해결 방법 등을 공유합니다.

techbless.github.io

https://github.com/DefinitelyTyped/DefinitelyTyped/issues/46861

 

TS2339: Property 'user' does not exist on type 'Request<ParamsDictionary, any, any, ParsedQs>' · Issue #46861 · DefinitelyType

When trying to extend the Request interface from the package express to add some custom properties, I'm getting the following typescript error on my routers: ..\node_modules\ts-node\src\index.t...

github.com

 

간력하게 요약해보자면,

 

현재 프로젝트에서는 ts-node-dev 라이브러리(ts-node와 node-dev를 합친 라이브러리)를 사용하고 있는데,

ts-node는 기본적으로 includes, excludes, files를 로드하지 않아 실행 시 --files 옵션을 통해서 포함시켜줘야 한다고 합니다.

 

따라서 아래와 같이 해결!

tsconfig.json

{
    "compilerOptions": {
        ...
        
        "typeRoots": ["src/@types/*", "node_modules/@types"]
    }
}

typeRoots가 없어도 잘 실행되긴 하지만, 혹시 몰라서 정의해놨습니다.

 

package.json

    "scripts": {
        "dev": "ts-node-dev --respawn --files ./src/app.ts",
    },