[]
        
(Showing Draft Content)

사용자 인증 및 권한

이 가이드는 js-collaboration에서 사용자 인증메시지 권한 검증을 구현하는 방법을 설명합니다. 미들웨어를 사용하여 사용자 신원을 검증하고, 메시지를 수신할 때 권한을 확인하여 작업 허용 여부를 판단합니다.

요약

js-collaboration은 토큰 검증을 통해 안전한 인증을 수행하고, 메시지 수준의 권한 제어를 구현합니다. 이를 통해 다음을 보장합니다.

  • 인증된 클라이언트만 서버 연결을 설정할 수 있음

  • 정책을 통해 메시지 처리 권한이 강제됨

핵심 포인트:

  • 인증(Authentication): 토큰을 통해 사용자 신원을 검증하여 클라이언트가 합법적인 사용자인지 확인

  • 권한 검증(Permission Validation): 사용자 정보를 저장하고 조회하여 메시지 권한 제어 수행

이 예제의 토큰 검증 및 권한 검증은 데모용입니다. 실제 애플리케이션에서는 비즈니스 요구사항에 따라 더 안전하고 복잡한 검증 메커니즘을 구현해야 합니다.

워크플로우

클라이언트

  1. 사용자가 로그인하여 토큰을 획득

  2. 클라이언트가 client.connect()를 통해 auth 파라미터로 토큰을 서버에 전달

  3. 서버가 토큰을 수신하여 검증 수행

    인증 성공 시 서버와의 연결이 설정되고, 실패 시 인증 실패 메시지가 반환됨

서버

  1. 서버는 server.use() 미들웨어를 통해 클라이언트가 전달한 토큰을 조회하고 검증

  2. 인증 성공 시 사용자 정보를 connection.tags에 저장하고, 이후 작업(예: 메시지 전송)을 허용

  3. 인증 실패 시 서버는 오류 메시지를 반환하며, 클라이언트는 이를 수신할 수 있음

클라이언트 측: 인증 정보 전송

프런트엔드에서는 연결을 설정할 때 토큰을 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
    }
});

코드 설명

  • 클라이언트는 userTokenauth 파라미터로 서버에 전달하여 인증을 요청

  • 서버는 미들웨어를 통해 토큰을 검증하고, 결과에 따라 연결을 허용하거나 거부

서버 측: 인증 및 메시지 권한

서버 측에서는 미들웨어를 사용하여 클라이언트가 전달한 토큰을 검증하고, 검증된 사용자 정보를 기반으로 권한을 처리합니다.

  • 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')로 저장된 사용자 정보를 조회하고, 사용자 역할에 따라 메시지 권한을 검증합니다.