4-3. JWT 처리 미들웨어 만들기

쿠키가 한번 설정이 되고 나면, 요청이 들어올때마다 쿠키에 access_token 이 함께 전달됩니다. 이번 섹션에서는 해당 쿠키가 존재한다면, 토큰을 해석해서 요청의 user 값으로 설정하는 미들웨어를 만들어보도록 하겠습니다.

먼저, JWT 디코딩 하는 방법을 알아봅시다.

JWT 디코딩은 다음과 같이 합니다:

jwt.verify(token, jwtSecret, (error, decoded) => {
    if(error) {
        console.error(error);
        return;
    }
    console.log(decoded);
});

이제 이 함수를 사용하여 프로미스 기반으로 토큰을 해석하는 함수를 새로 생성해보겠습니다. 다음 함수를 src/lib/token.js 파일에 만드세요.

src/lib/token.js

(...)
function decodeToken(token) {
    return new Promise(
        (resolve, reject) => {
            jwt.verify(token, jwtSecret, (error, decoded) => {
                if(error) reject(error);
                resolve(decoded);
            });
        }
    );
}

디코딩 하는 함수도 만들었으니, 미들웨어를 만들어보도록 하겠습니다. 주석과 함께 코드를 읽어보세요.

src/lib/token.js

exports.jwtMiddleware = async (ctx, next) => {
    const token = ctx.cookies.get('access_token'); // ctx 에서 access_token 을 읽어옵니다
    if(!token) return next(); // 토큰이 없으면 바로 다음 작업을 진행합니다.

    try {
        const decoded = await decodeToken(token); // 토큰을 디코딩 합니다

        // 토큰 만료일이 하루밖에 안남으면 토큰을 재발급합니다
        if(Date.now() / 1000 - decoded.iat > 60 * 60 * 24) {
            // 하루가 지나면 갱신해준다.
            const { _id, profile } = decoded;
            const freshToken = await generateToken({ _id, profile }, 'account');
            ctx.cookies.set('access_token', freshToken, {
                maxAge: 1000 * 60 * 60 * 24 * 7, // 7days
                httpOnly: true
            });
        }

        // ctx.request.user 에 디코딩된 값을 넣어줍니다
        ctx.request.user = decoded;
    } catch (e) {
        // token validate 실패
        ctx.request.user = null;
    }

    return next();
};

이 미들웨어를 적용하고 나면, 라우트 핸들러에서 ctx.request.user 를 조회하면 유저정보가 반환됩니다.

이제, 이 미들웨어를 적용해줍시다. 방금 만든 미들웨어를 불러온다음에, api 라우트가 적용되기 전에 미들웨어를 적용해줍니다.

src/index.js

const { jwtMiddleware } = require('lib/token');

(...)

app.use(bodyParser()); // 바디파서 적용, 라우터 적용코드보다 상단에 있어야합니다.
app.use(jwtMiddleware);
router.use('/api', api.routes()); // api 라우트를 /api 경로 하위 라우트로 설정
app.use(router.routes()).use(router.allowedMethods());


app.listen(port, () => {
    console.log('heurm server is listening to port ' + port);
});

check API 만들기

이제, 만약에 쿠키에 access_token 이 있다면, 현재 로그인된 유저의 정보를 알려주는 API 를 만들어보겠습니다.

src/api/auth/auth.controller.js - check

exports.check = (ctx) => {
    const { user } = ctx.request;

    if(!user) {
        ctx.status = 403; // Forbidden
        return;
    }

    ctx.body = user.profile;
};

이렇게, ctx.request.user 에 접근하면 토큰에 설정했던 객체값을 얻을 수 있습니다. 이제 라우트를 설정을 하겠습니다.

src/api/auth/index.js

const Router = require('koa-router');
const auth = new Router();
const authCtrl = require('./auth.controller');

auth.post('/register/local', authCtrl.localRegister);
auth.post('/login/local', authCtrl.localLogin);
auth.get('/exists/:key(email|username)/:value', authCtrl.exists);
auth.post('/logout', authCtrl.logout);
auth.get('/check', authCtrl.check);

module.exports = auth;

여기까지 구현을 하고 나서, 로그인 API 를 통해 토큰을 쿠키에 설정받은 다음에, http://localhost:4000/api/auth/check 에 GET 요청을 하면 해당 토큰이 가지고 있는 회원정보를 반환 하게 됩니다.

GET http://localhost:4000/api/auth/check

{
    "thumbnail": "/static/images/default_thumbnail.png",
    "username": "velopert"
}

이제 회원인증을 위한 API 준비를 어느정도 마쳤습니다. 다음 5장 부터 프론트엔드 작업을 시작해보도록 하겠습니다.

results matching ""

    No results matching ""