[]
이 가이드는 js-collaboration에서 사용자 인증과 메시지 권한 검증을 구현하는 방법을 설명합니다. 미들웨어를 사용하여 사용자 신원을 검증하고, 메시지를 수신할 때 권한을 확인하여 작업 허용 여부를 판단합니다.
js-collaboration은 토큰 검증을 통해 안전한 인증을 수행하고, 메시지 수준의 권한 제어를 구현합니다. 이를 통해 다음을 보장합니다.
인증된 클라이언트만 서버 연결을 설정할 수 있음
정책을 통해 메시지 처리 권한이 강제됨
핵심 포인트:
인증(Authentication): 토큰을 통해 사용자 신원을 검증하여 클라이언트가 합법적인 사용자인지 확인
권한 검증(Permission Validation): 사용자 정보를 저장하고 조회하여 메시지 권한 제어 수행
이 예제의 토큰 검증 및 권한 검증은 데모용입니다. 실제 애플리케이션에서는 비즈니스 요구사항에 따라 더 안전하고 복잡한 검증 메커니즘을 구현해야 합니다.
클라이언트
사용자가 로그인하여 토큰을 획득
클라이언트가 client.connect()를 통해 auth 파라미터로 토큰을 서버에 전달
서버가 토큰을 수신하여 검증 수행
인증 성공 시 서버와의 연결이 설정되고, 실패 시 인증 실패 메시지가 반환됨
서버
서버는 server.use() 미들웨어를 통해 클라이언트가 전달한 토큰을 조회하고 검증
인증 성공 시 사용자 정보를 connection.tags에 저장하고, 이후 작업(예: 메시지 전송)을 허용
인증 실패 시 서버는 오류 메시지를 반환하며, 클라이언트는 이를 수신할 수 있음
프런트엔드에서는 연결을 설정할 때 토큰을 auth 파라미터로 서버에 전달해야 합니다. 아래는 클라이언트 측에서 인증 정보를 전송하는 예제입니다.
프런트엔드는 client.connect() 메서드를 통해 인증용 토큰을 서버에 전달합니다.
import { Client } from '@mescius/js-collaboration-client';
// 로그인 시뮬레이션
async function login(username, password) {
const response = await fetch('http://localhost:8080/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});
const result = await response.json();
if (result.success) {
return result.token;
} else {
throw new Error(result.message);
}
}
// 토큰 획득
const userToken = await login('reader1', 'read123');
// 클라이언트 인스턴스 생성 및 룸 연결
const client = new Client('ws://localhost:8080');
const connection = client.connect('room123', {
auth: {
token: userToken
}
});코드 설명
클라이언트는 userToken을 auth 파라미터로 서버에 전달하여 인증을 요청
서버는 미들웨어를 통해 토큰을 검증하고, 결과에 따라 연결을 허용하거나 거부
서버 측에서는 미들웨어를 사용하여 클라이언트가 전달한 토큰을 검증하고, 검증된 사용자 정보를 기반으로 권한을 처리합니다.
connect 미들웨어에서 클라이언트가 전달한 토큰을 조회·검증하고, 사용자 정보를 connection.tags에 저장
message 미들웨어에서 connection.tags에 저장된 사용자 정보를 조회하여 권한 검사를 수행
import express from 'express';
import { createServer } from 'http';
import { Server } from '@mescius/js-collaboration';
import jwt from 'jsonwebtoken';
const app = express();
const httpServer = createServer(app);
const server = new Server({ httpServer });
app.use(express.json());
// JWT 비밀 키
const JWT_SECRET = 'your-secret-key-here';
// 사용자 데이터베이스 시뮬레이션
const users = new Map([
['admin1', { username: 'admin1', password: 'admin123', role: 'admin' }],
['reader1', { username: 'reader1', password: 'reader123', role: 'reader' }],
['editor1', { username: 'editor1', password: 'editor123', role: 'editor' }]
]);
// 로그인 라우트
app.post('/login', (req, res) => {
const { username, password } = req.body;
const user = users.get(username);
if (!user || user.password !== password) {
return res.status(401).json({
success: false,
message: '잘못된 사용자 이름 또는 비밀번호'
});
}
const token = jwt.sign(
{ username: user.username, role: user.role },
JWT_SECRET
);
res.json({
success: true,
token,
user: { username: user.username, role: user.role }
});
});
server.use('connect', async (context, next) => {
const token = context.connection.auth?.token;
if (!token) {
await next('토큰이 제공되지 않았습니다');
return;
}
try {
const decoded = jwt.verify(token, JWT_SECRET);
const user = {
username: decoded.username,
role: decoded.role
};
context.connection.tags.set('user', user);
console.log(`사용자 인증 성공: ${user.username} (${user.role})`);
await next();
} catch {
await next('유효하지 않은 토큰');
}
});
server.use('message', async ({ connection }, next) => {
const user = connection.tags.get('user');
if (user.role === 'admin' || user.role === 'editor') {
await next();
} else {
await next('편집 권한 없음');
}
});
// 서버 시작
httpServer.listen(8080);코드 설명
인증 검증: connect 미들웨어에서 context.connection.auth?.token을 통해 전달된 토큰을 조회하고 검증합니다. 검증에 성공하면 사용자 정보를 조회하여 connection.tags에 저장합니다.
권한 검증: message 미들웨어에서 context.connection.tags.get('user')로 저장된 사용자 정보를 조회하고, 사용자 역할에 따라 메시지 권한을 검증합니다.