5 - Authentification via WebSockets
Passer le jeton avec les requêtes (Angular)
Du côté client, vous devrez passer le jeton stocké dans le localstorage à chaque requête de WebSocket. Pour ce faire, vous devez simplement modifier votre configuration de Socket.io dans app.module de la façon suivante:
// Récupère le jeton du localstorage
const token = localStorage.getItem('access_token');
const config: SocketIoConfig = {
url: 'http://localhost', options: {
transportOptions: {
polling: {
// Ajoute dans l'en-tête des requêtes le jeton
extraHeaders: {
Authorization: `Bearer ${token}`
}
}
}
}
};
@NgModule({
//...
Récupérer et traiter le jeton côté serveur
Dans le module d'authentification, on peut ajouter un guard spécialisé pour les websocket. Ce guard récupère le jeton de l'en-tête, le décode et récupère l'utilisateur associé pour l'associer à la variable client disponible dans les gateway.
- Dans votre module associé aux messages (ex.:
messages.module.ts), importezAuthModuleet la configuration pour JWT.
@Module({
imports: [
/...
AuthModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
secret: configService.get('JWT_SECRET'),
signOptions: { expiresIn: configService.get('JWT_EXPIRES_IN') },
}),
}),
],
/...
- Ajouter un guard dans le module
auth(ex.:ws-jwt-auth-guard.ts)src/auth/ws-jwt-auth-guard.ts@Injectable()
export class WsJwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const client = context.switchToWs().getClient();
const authHeader = client.handshake.headers.authorization;
if (!authHeader) throw new UnauthorizedException('En-tête d\'authentification manquante');
const [bearer, token] = authHeader.split(' ');
if (bearer !== 'Bearer' || !token) throw new UnauthorizedException('Format de jeton invalide');
try {
const payload = this.jwtService.verify(token);
client.user = await Utilisateur.findOne({
where: {
id: payload.sub,
}
});
if(client.user)
return true;
else
return false;
} catch (e) {
throw new UnauthorizedException('Jeton invalide ou expiré');
}
}
} - Dans le gateway, ajouter la référence au guard via un décorateur
@WebSocketGateway(80, { cors: true })
@UseGuards(WsJwtAuthGuard)
export class PixelsEventsGateway implements OnGatewayConnection, OnGatewayDisconnect { - Ensuite, dans les fonctions du type
handleMessage, qui reçoivent en paramètreclient, il est possible d'accéder à l'utilisateur si vous en avez besoin. Par exemple, pour associer un message à son auteur!@SubscribeMessage('pixel')
async handleMessage(client: any, data: PixelDataDto) {
//highglight-next-line
console.log("Gestion de l'événement pour le client: ", client.user);
// ...