Authentification et admission

La règle

Dès qu'un canal porte des sessions, il appelle session.allowMessage?.(name, payload) avant de publier chaque entrant. false : trame jetée, avertissement. Absente : autorisé. Le composant d'auth, un par canal, la pose au connected de façon synchrone, écrit l'identité dans session.data au login, re-valide au resumed, libère à l'expired.

Pourquoi

Le hook est du framework, la politique est libre. Avec nom et payload, la grille autorise au grain du membre oneOf. this === session et l'identité vit dans session.data : l'utilisateur est connu sans qu'on le passe. Et il faut bien que le login passe : seul défaut permissif du canal.

Dans le chat

Avant identification, seuls acces_demande et deconnexion_demande passent. Après, tout. Effacer data.pseudo referme la porte sans rien reposer.

Contre-exemple : poser la grille après un await

if (event === "connected") {
	const droits = await this.deps.db.lireDroits(session.data.user); // fenêtre ouverte !
	session.allowMessage = (name) => droits.includes(name);
}

Pendant l'attente, allowMessage est undefined : une trame pipelinée passe. Posez d'abord un deny-sauf-login synchrone, puis remplacez.

Ce que voit le canal

WARN (websocket): message 'message_demande' refusé pour la session 8fa1ee2f-… (allowMessage) — jeté

Le pattern complet

handleMessage(message) {
	if (message.login) {
		const user = this.#authenticate(message.login);
		if (user !== null) message.session.data.user = user; // visible de tous, dès maintenant
		this.broker.publish(this, { login_result: { granted: user !== null }, id: message.id });
	}
	if (message.connection_event?.channel === this.canal) {   // un composant d'auth PAR canal
		const { event } = message.connection_event;
		const session = message.session;
		if (event === "connected") session.allowMessage = (name, payload) => {
			const user = session.data.user;
			if (!user) return name === "login";
			if (name === "gerer_clients" && payload.delete) return user.role === "admin"; // grain oneOf
			return true;
		};
		if (event === "resumed") { /* re-valider : banni entre-temps ? */ }
		if (event === "expired") { /* libérer */ }
	}
}

allowMessage ne décide que de l'admission. L'autorisation fine d'une action reste au composant qui l'exécute, par une convention libre (par exemple session.allowAction(...)), hors framework.