인프런 커뮤니티 질문&답변

TaeHyeon Kim님의 프로필 이미지

작성한 질문수

따라하며 배우는 노드, 리액트 시리즈 - 기본 강의

[/api/users/logout] 에러 질문: Cannot read property 'x_auth' of undefined

해결된 질문

작성

·

467

0

안녕하세요 logout 기능을 구현했는데 아래 에러가 떠서 너무 힘들어서 질문드립니다.

postman으로 POST 메소드로 login에 성공하였고, 토큰이 생기는것을 확인했습니다.

그 후 바로 postman으로 GET 메소드로 /api/users/logout을 하려 하는데 아래와 같은 에러가 발생하네요 ㅠㅠ 

제 깃헙 주소에서 전체코드를 보실 수 있습니다. https://github.com/kth990303/boiler-plate-prac

어디가 문제인지 잘 모르겠네요. 답변 부탁드립니다 ㅜㅜ 감사합니다.

TypeError: Cannot read property 'x_auth' of undefined
    at auth (C:\Users\User\Desktop\web_workspace\boiler_plate\middleware\auth.js:6:29)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\layer.js:95:5)
    at C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\index.js:335:12)
    at next (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\express\lib\router\index.js:275:10)
    at C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\body-parser\lib\read.js:130:5
    at invokeCallback (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\raw-body\index.js:224:16)
    at done (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\raw-body\index.js:213:7)
    at IncomingMessage.onEnd (C:\Users\User\Desktop\web_workspace\boiler_plate\node_modules\raw-body\index.js:273:7)
    at IncomingMessage.emit (events.js:327:22)
    at endReadableNT (internal/streams/readable.js:1327:12)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)

코드는 아래와 같습니다.

Auth.js (auth.js:6:29는 const token=req.cookies.x_auth 부분입니다.)

const { User } = require("../models/User");

const auth=(req, res, next)=>{
    // 인증처리
    // client cookie에서 토큰 가져오기
    const token=req.cookies.x_auth;
    // token을 jwt로 decoding
    User.findByToken(token, (err, user)=>{
        if(err) throw err;
        if(!user){
            return res.json({
                isAuth: false,
                error: true
            });
        }
        req.token=token;
        req.user=user;
        next();   
    })
}
module.exports={auth};

User.js (Token 생성, findByToken function 부분)

userSchema.methods.generateToken=function(cb){
    const user=this;
    const token=jwt.sign(user._id.toHexString(), 'secretToken');
    user.token=token;
    user.save(function(err, user){
        if(err) return cb(err);
        cb(null, user);
    });
}

userSchema.statics.findByToken=function(token, cb){
    const user=this;
    jwt.verify(token, 'secretToken', function(err, decoded){
        user.findOne({"_id": decoded, "token": token}, function(err, user){
            if(err) return cb(err);
            cb(null, user);
        });
    });
}

const User=mongoose.model('User', userSchema);

// 다른 파일에서도 이 모델을 쓸 수 있도록
module.exports={ User }

Index.js (/api/users/login, /api/users/auth, /api/users/logout)

app.post('/api/users/login', (req, res)=>{
    // 요청된 이메일을 db에서 찾는다.
    User.findOne({email: req.body.email}, (err, user)=>{
        if(!user){
            return res.json({
                loginSuccess: false,
                message: "Unvalid email"
            });
        }
        // 요청된 이메일이 db에 있다면 비밀번호 일치여부 확인
        user.comparePassword(req.body.password, (err, isMatch)=>{
            if(!isMatch)
                return res.json({
                    loginSuccess:false,
                    message:"Wrong password"
                });
            // 일치 시, 토큰 생성
            user.generateToken((err, user)=>{
                if(err) return res.status(400).send(err);
                // 토큰을 쿠키에 저장
                res.cookie("x_auth", user.token)
                .status(200)
                .json({
                    loginSuccess: true,
                    userId: user._id
                });
            });
            
        });
    });
});

// auth라는 미들웨어를 추가
// request를 받으면 call back function 호출 전에 middleware실행
app.get('/api/users/auth', auth, (req, res)=>{
    res.status(200).json({
        _id: req.user._id, 
        isAdmin: req.user.role===0?false:true, 
        isAuth: true,
        email: req.user.email,
        name: req.user.name,
        lastname: req.user.lastname,
        role: req.user.role,
        image: req.user.image
    });
});

app.get('/api/users/logout', auth, (req, res)=>{
    console.log(req.user);
    user.findOneAndUpdate({_id:req.user._id}, {
        token: ""
    }, (err, user)=>{
        if(err) return res.json({
            success: false,
            err
        });
        return res.status(200).send({
            success: true
        })
    })
})

아래는 postman 화면 결과입니다.

+) 전체적으로 수업시간의 코드는 이해가 되는데, 어떤 의식의 흐름으로 이렇게 작성하는지 신기할 때가 많습니다.

예를 들면 쿠키에서 토큰을 가져온다 할 때 let token=req.cookies.x_auth 에서 req에 cookies에서 쿠키 이름인 x_auth로 접근하면 바로 토큰이 나온다는 사실을 몰랐음.

이런 경우는 어떤 부분을 공부해야 할까요? 전체적으로 자바스크립트 실력이 붕 뜬 느낌입니다. (초보자라 질문이 좀 이상한 것 같기도 하네요...)

답변 2

1

깃헙에서 확인해보니 아마도 app에 cookieParser를 추가를 안하셔서 x_auth에 토큰정보가 제대로 안담기고 있는것같아요.

index.js에서 12번째줄 밑에

app.use(cookieParser());

추가해주시면 될거같습니다.

John Ahn님의 프로필 이미지
John Ahn
지식공유자

감사합니다... !! 

TaeHyeon Kim님의 프로필 이미지
TaeHyeon Kim
질문자

덕분에 잘 해결됐습니다. 정말 감사합니다

0

TaeHyeon Kim님의 프로필 이미지
TaeHyeon Kim
질문자

추가로 위 코드에 index.js의 /api/users/logout 라우터에서 user.findOneAndUpdate에서 User.findOneAndUpdate로 해주어 ReferenceError: user is not defined 이 에러도 없앴습니다.