> 웹 프론트엔드 > JS 튜토리얼 > mongodb 데이터베이스를 사용하는 nodejs의 보안 인증입니다.

mongodb 데이터베이스를 사용하는 nodejs의 보안 인증입니다.

DDD
풀어 주다: 2024-11-05 11:19:02
원래의
647명이 탐색했습니다.

A secure authentication in nodejs with mongodb database.

Node.js 패키지 참조 가이드

핵심 종속성

웹 프레임워크 및 서버

  • 표현 (^4.18.2)
    • 웹 애플리케이션 프레임워크
    • 라우팅, 미들웨어, HTTP 요청/응답 처리
    • API 및 웹 애플리케이션 구축을 위한 핵심 기반

데이터 베이스

  • 몽구스 (^7.0.0)
    • MongoDB 객체 모델링 도구
    • 모델링 애플리케이션 데이터에 대한 스키마 기반 솔루션 제공
    • 데이터베이스 운영 및 관계 처리

보안 패키지

  • jsonwebtoken (^9.0.0)

    • JWT(JSON 웹 토큰) 생성 및 확인
    • 사용자 인증 및 안전한 정보 교환을 위해 사용
  • bcryptjs (^2.4.3)

    • 비밀번호를 안전하게 해시하고 비교합니다
    • 데이터베이스에서 사용자 비밀번호를 보호합니다
  • 헬멧 (^6.0.1)

    • HTTP 응답에 보안 헤더를 추가합니다
    • 일반적인 웹 취약점으로부터 보호
    • 보안을 위한 다양한 HTTP 헤더 설정
  • 코르 (^2.8.5)

    • 교차 출처 리소스 공유 활성화
    • API에 액세스할 수 있는 도메인 제어
    • 프런트엔드/백엔드가 분리된 웹 애플리케이션에 필수

검증 및 구성

  • 조이 (^17.9.0)

    • 데이터 검증 라이브러리
    • 요청 본문, 쿼리 매개변수 및 기타 입력을 검증합니다
    • 데이터 무결성 및 형식 보장
  • 도텐브 (^16.0.3)

    • .env 파일에서 환경 변수 로드
    • 구성 설정 관리
    • 민감한 데이터를 안전하게 보호

개발 종속성

개발 도구

  • 노데몬 (^2.0.22)
    • 개발 중 파일 변경 모니터링
    • 서버 자동 재시작
    • 개발 워크플로 개선

사용예

// Express server setup
const express = require('express');
const app = express();

// Security middleware
const helmet = require('helmet');
const cors = require('cors');
app.use(helmet());
app.use(cors());

// Environment variables
require('dotenv').config();

// Database connection
const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI);

// Validation example
const Joi = require('joi');
const schema = Joi.object({
    email: Joi.string().email().required()
});

// Password hashing
const bcrypt = require('bcryptjs');
const hashedPassword = await bcrypt.hash('password', 10);

// JWT authentication
const jwt = require('jsonwebtoken');
const token = jwt.sign({userId: 123}, process.env.JWT_SECRET);
로그인 후 복사

완전한 Node.js 및 Mongoose 프로젝트 구조 가이드

프로젝트 구조

project-root/
├── src/
│   ├── config/
│   │   ├── database.js
│   │   └── config.js
│   ├── models/
│   │   ├── user.model.js
│   │   └── product.model.js
│   ├── controllers/
│   │   ├── user.controller.js
│   │   └── product.controller.js
│   ├── routes/
│   │   ├── user.routes.js
│   │   └── product.routes.js
│   ├── middleware/
│   │   ├── auth.middleware.js
│   │   └── error.middleware.js
│   ├── utils/
│   │   ├── logger.js
│   │   └── validators.js
│   └── app.js
├── .env
├── .gitignore
└── package.json
로그인 후 복사

1. 초기 설정

패키지.json

{
  "name": "node-mongoose-project",
  "version": "1.0.0",
  "main": "src/app.js",
  "scripts": {
    "start": "node src/app.js",
    "dev": "nodemon src/app.js"
  },
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.0.0",
    "dotenv": "^16.0.3",
    "joi": "^17.9.0",
    "jsonwebtoken": "^9.0.0",
    "bcryptjs": "^2.4.3",
    "cors": "^2.8.5",
    "helmet": "^6.0.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.22"
  }
}
로그인 후 복사

.env

PORT=3000
MONGODB_URI=mongodb://localhost:27017/your-database
JWT_SECRET=your-secret-key
NODE_ENV=development
로그인 후 복사

.gitignore

node_modules/
.env
logs/
*.log
로그인 후 복사

2. 구성 설정

src/config/config.js

require('dotenv').config();

module.exports = {
    port: process.env.PORT || 3000,
    mongoUri: process.env.MONGODB_URI,
    jwtSecret: process.env.JWT_SECRET,
    nodeEnv: process.env.NODE_ENV || 'development',
    jwtExpiresIn: '1d'
};
로그인 후 복사

src/config/database.js

const mongoose = require('mongoose');
const config = require('./config');
const logger = require('../utils/logger');

const connectDB = async () => {
    try {
        await mongoose.connect(config.mongoUri, {
            useNewUrlParser: true,
            useUnifiedTopology: true
        });
        logger.info('MongoDB connected successfully');
    } catch (error) {
        logger.error('MongoDB connection error:', error);
        process.exit(1);
    }
};

module.exports = connectDB;
로그인 후 복사

3. 모델 정의

src/모델/user.model.js

const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const config = require('../config/config');

const userSchema = new mongoose.Schema({
    name: {
        type: String,
        required: [true, 'Name is required'],
        trim: true,
        minlength: 3,
        maxlength: 50
    },
    email: {
        type: String,
        required: [true, 'Email is required'],
        unique: true,
        lowercase: true,
        trim: true
    },
    password: {
        type: String,
        required: [true, 'Password is required'],
        minlength: 6,
        select: false
    },
    role: {
        type: String,
        enum: ['user', 'admin'],
        default: 'user'
    }
}, {
    timestamps: true
});

// Pre-save middleware to hash password
userSchema.pre('save', async function(next) {
    if (!this.isModified('password')) return next();
    this.password = await bcrypt.hash(this.password, 12);
    next();
});

// Instance methods
userSchema.methods.generateAuthToken = function() {
    return jwt.sign(
        { id: this._id, role: this.role },
        config.jwtSecret,
        { expiresIn: config.jwtExpiresIn }
    );
};

userSchema.methods.comparePassword = async function(candidatePassword) {
    return await bcrypt.compare(candidatePassword, this.password);
};

const User = mongoose.model('User', userSchema);
module.exports = User;
로그인 후 복사

src/모델/product.model.js

const mongoose = require('mongoose');

const productSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true,
        trim: true
    },
    price: {
        type: Number,
        required: true,
        min: 0
    },
    description: String,
    category: {
        type: String,
        required: true
    },
    createdBy: {
        type: mongoose.Schema.Types.ObjectId,
        ref: 'User',
        required: true
    }
}, {
    timestamps: true
});

const Product = mongoose.model('Product', productSchema);
module.exports = Product;
로그인 후 복사

4. 컨트롤러

src/controllers/user.controller.js

const User = require('../models/user.model');
const { validateUser } = require('../utils/validators');
const logger = require('../utils/logger');

exports.register = async (req, res) => {
    try {
        const { error } = validateUser(req.body);
        if (error) return res.status(400).json({ error: error.details[0].message });

        const user = await User.create(req.body);
        const token = user.generateAuthToken();

        res.status(201).json({
            status: 'success',
            token,
            data: { user }
        });
    } catch (error) {
        logger.error('Registration error:', error);
        res.status(400).json({
            status: 'fail',
            message: error.message
        });
    }
};

exports.login = async (req, res) => {
    try {
        const { email, password } = req.body;

        const user = await User.findOne({ email }).select('+password');
        if (!user || !(await user.comparePassword(password))) {
            return res.status(401).json({
                status: 'fail',
                message: 'Invalid email or password'
            });
        }

        const token = user.generateAuthToken();
        res.json({
            status: 'success',
            token
        });
    } catch (error) {
        logger.error('Login error:', error);
        res.status(400).json({
            status: 'fail',
            message: error.message
        });
    }
};
로그인 후 복사

5. 노선

소스/경로/user.routes.js

const express = require('express');
const router = express.Router();
const userController = require('../controllers/user.controller');
const auth = require('../middleware/auth.middleware');

router.post('/register', userController.register);
router.post('/login', userController.login);
router.get('/profile', auth, userController.getProfile);

module.exports = router;
로그인 후 복사

6. 미들웨어

src/미들웨어/auth.middleware.js

const jwt = require('jsonwebtoken');
const config = require('../config/config');
const User = require('../models/user.model');

module.exports = async (req, res, next) => {
    try {
        const token = req.headers.authorization?.replace('Bearer ', '');

        if (!token) {
            return res.status(401).json({
                status: 'fail',
                message: 'No token provided'
            });
        }

        const decoded = jwt.verify(token, config.jwtSecret);
        const user = await User.findById(decoded.id);

        if (!user) {
            return res.status(401).json({
                status: 'fail',
                message: 'User not found'
            });
        }

        req.user = user;
        next();
    } catch (error) {
        res.status(401).json({
            status: 'fail',
            message: 'Invalid token'
        });
    }
};
로그인 후 복사

src/미들웨어/error.middleware.js

const logger = require('../utils/logger');

module.exports = (err, req, res, next) => {
    logger.error(err.stack);

    if (err.name === 'ValidationError') {
        return res.status(400).json({
            status: 'fail',
            message: err.message
        });
    }

    if (err.code === 11000) {
        return res.status(400).json({
            status: 'fail',
            message: 'Duplicate field value'
        });
    }

    res.status(err.status || 500).json({
        status: 'error',
        message: err.message || 'Internal server error'
    });
};
로그인 후 복사

7. 유틸리티

src/utils/logger.js

const winston = require('winston');
const config = require('../config/config');

const logger = winston.createLogger({
    level: config.nodeEnv === 'development' ? 'debug' : 'info',
    format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json()
    ),
    transports: [
        new winston.transports.File({ filename: 'logs/error.log', level: 'error' }),
        new winston.transports.File({ filename: 'logs/combined.log' })
    ]
});

if (config.nodeEnv === 'development') {
    logger.add(new winston.transports.Console({
        format: winston.format.simple()
    }));
}

module.exports = logger;
로그인 후 복사

src/utils/validators.js

const Joi = require('joi');

exports.validateUser = (user) => {
    const schema = Joi.object({
        name: Joi.string().min(3).max(50).required(),
        email: Joi.string().email().required(),
        password: Joi.string().min(6).required(),
        role: Joi.string().valid('user', 'admin')
    });

    return schema.validate(user);
};

exports.validateProduct = (product) => {
    const schema = Joi.object({
        name: Joi.string().required(),
        price: Joi.number().min(0).required(),
        description: Joi.string(),
        category: Joi.string().required()
    });

    return schema.validate(product);
};
로그인 후 복사

8. 주요 애플리케이션 파일

src/app.js

const express = require('express');
const cors = require('cors');
const helmet = require('helmet');
const config = require('./config/config');
const connectDB = require('./config/database');
const errorMiddleware = require('./middleware/error.middleware');
const userRoutes = require('./routes/user.routes');
const productRoutes = require('./routes/product.routes');
const logger = require('./utils/logger');

// Initialize express app
const app = express();

// Connect to MongoDB
connectDB();

// Middleware
app.use(helmet());
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Routes
app.use('/api/users', userRoutes);
app.use('/api/products', productRoutes);

// Error handling
app.use(errorMiddleware);

// Start server
app.listen(config.port, () => {
    logger.info(`Server running in ${config.nodeEnv} mode on port ${config.port}`);
});

// Handle unhandled promise rejections
process.on('unhandledRejection', (err) => {
    logger.error('UNHANDLED REJECTION! Shutting down...');
    logger.error(err.name, err.message);
    process.exit(1);
});
로그인 후 복사

애플리케이션 실행

  1. 종속성 설치:
npm install
로그인 후 복사
  1. .env에서 환경 변수 설정

  2. 개발 서버 시작:

npm run dev
로그인 후 복사
  1. 제작의 경우:
npm start
로그인 후 복사

API 테스트

Postman 또는 컬과 같은 도구를 사용하여 API 엔드포인트를 테스트하세요.

# Register a new user
curl -X POST http://localhost:3000/api/users/register \
  -H "Content-Type: application/json" \
  -d '{"name": "John Doe", "email": "john@example.com", "password": "password123"}'

# Login
curl -X POST http://localhost:3000/api/users/login \
  -H "Content-Type: application/json" \
  -d '{"email": "john@example.com", "password": "password123"}'
로그인 후 복사

이 구조화된 가이드는 적절한 구성, 오류 처리 및 보안 기능을 갖춘 Node.js 및 Mongoose 애플리케이션의 전체 설정을 제공합니다. 각 파일에는 특정 책임이 있어 코드베이스를 유지 관리하고 확장할 수 있습니다.

위 내용은 mongodb 데이터베이스를 사용하는 nodejs의 보안 인증입니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿