Skip to content

Commit

Permalink
Merge pull request #143 from boostcampwm-2024/feature/be/#42-loginapi
Browse files Browse the repository at this point in the history
[BE][Feat] : #42 : 로그인 api 구현
  • Loading branch information
happyhyep authored Nov 12, 2024
2 parents 6bf7474 + 9be7e01 commit 4f606e5
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 13 deletions.
5 changes: 4 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@
"author": "",
"license": "ISC",
"dependencies": {
"bcrypt": "^5.1.1",
"dotenv": "^16.4.5",
"express": "^4.21.1",
"express-validator": "^7.2.0",
"jsonwebtoken": "^9.0.2",
"pg": "^8.13.1",
"swagger-jsdoc": "^6.2.8",
"swagger-ui-express": "^5.0.1",
"ws": "^8.18.0"
"ws": "^8.11.0"
}
}
File renamed without changes.
16 changes: 16 additions & 0 deletions backend/src/controllers/authController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { loginUser } from '../services/authService.js';

export const login = async (req, res) => {
const { id, password } = req.body;

try {
const token = await loginUser(id, password);
if (!token) {
return res.status(401).json({ message: 'Invalid ID or password' });
}
return res.status(200).json({ token });
} catch (error) {
console.error('Login error:', error);
return res.status(500).json({ message: 'Server error occurred' });
}
};
File renamed without changes.
18 changes: 13 additions & 5 deletions backend/src/index.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import express from 'express';
import swaggerUi from 'swagger-ui-express';
import http from 'http';
import { specs } from '../swaggerConfig';
import { pool } from './db';
import { PORT } from './constants';
import { initializeWebSocketServer } from './websocketServer';
import { specs } from '../swaggerConfig.js';
import { pool } from './db/db.js';
import { PORT } from './constants/constants.js';
import { initializeWebSocketServer } from './websocketServer.js';
import { authRouter } from './routes/authRouter.js';

const app = express();
app.use(express.json());

app.use('/api-docs', swaggerUi.serve, swaggerUi.setup(specs));

app.use('/api/auth', authRouter);

// TODO: 데이터베이스에서 데이터 가져오기 예시
app.get('/guests', async (req, res) => {
try {
Expand All @@ -31,7 +34,12 @@ app.get('/example', (req, res) => {
const server = http.createServer(app);

// WebSocket 서버 초기화
initializeWebSocketServer(server);
try {
initializeWebSocketServer(server);
console.log('WebSocket server initialized successfully.');
} catch (error) {
console.error('Failed to initialize WebSocket server:', error);
}

app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
Expand Down
9 changes: 9 additions & 0 deletions backend/src/middleware/validationMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { validationResult } from 'express-validator';

export const validationMiddleware = (req, res, next) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
next();
};
6 changes: 6 additions & 0 deletions backend/src/repositories/userRepository.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { pool } from '../db/db.js';

export const findUserById = async id => {
const result = await pool.query('SELECT * FROM "main"."user" WHERE id = $1', [id]);
return result.rows[0];
};
18 changes: 18 additions & 0 deletions backend/src/routes/authRouter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import express from 'express';
import { body } from 'express-validator';
import { login } from '../controllers/authController.js';
import { validationMiddleware } from '../middleware/validationMiddleware.js';

export const authRouter = express.Router();

authRouter.post(
'/login',
[
body('id').notEmpty().withMessage('ID is required'),
body('password')
.isLength({ min: 6 })
.withMessage('Password must be at least 6 characters long'),
],
validationMiddleware,
login,
);
19 changes: 19 additions & 0 deletions backend/src/services/authService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { findUserById } from '../repositories/userRepository.js';

export const loginUser = async (id, password) => {
const user = await findUserById(id);
if (!user) {
throw new Error('User not found');
}

const isPasswordValid = await bcrypt.compare(password, user.password);
if (!isPasswordValid) {
throw new Error('Invalid password');
}

// JWT 생성
const token = jwt.sign({ userId: user.id }, process.env.JWT_SECRET, { expiresIn: '1h' });
return { token, userId: user.id };
};
4 changes: 2 additions & 2 deletions backend/src/websocketServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { WebSocketServer } from 'ws';

const activeConnections = {}; // token별로 연결을 관리하기 위한 객체

export function initializeWebSocketServer(server) {
export const initializeWebSocketServer = server => {
const wss = new WebSocketServer({ server });

wss.on('connection', (ws, req) => {
Expand Down Expand Up @@ -38,4 +38,4 @@ export function initializeWebSocketServer(server) {
delete activeConnections[token];
});
});
}
};
8 changes: 5 additions & 3 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ export default [
'no-undef': 'off',
'import/extensions': [
'error',
'ignorePackages',
'always',
{
js: 'never',
jsx: 'never',
js: 'always',
jsx: 'always',
ts: 'never',
tsx: 'never',
},
Expand Down Expand Up @@ -111,6 +111,8 @@ export default [
'import/prefer-default-export': 'off',
'import/no-unresolved': 'warn',
'no-console': 'off',
'consistent-return': 'off',
'import/extensions': 'off',
},
},

Expand Down
Loading

0 comments on commit 4f606e5

Please sign in to comment.