Autorizzazione dei canali
Qualsiasi client in possesso della app key può sottoscrivere i canali pubblici. Due prefissi nel nome del canale richiedono che il tuo backend autorizzi la sottoscrizione. Non devi configurare i canali separatamente.
Un canale con nome private-… richiede che il tuo backend approvi ogni sottoscrizione. Un canale con nome presence-… fa lo stesso e in più associa un'identità al sottoscrittore, così chiunque sia sul canale può vedere chi altro è presente. Qualsiasi altro nome è pubblico.
Solo il tuo backend possiede l'app secret. Il client chiede al tuo server di firmare una sottoscrizione specifica e l'edge Realtime verifica quella firma prima di accettarla. Il tuo server decide se il chiamante può sottoscrivere senza esporre il secret al client.
Indirizza il client al tuo endpoint
Fornisci al client un authEndpoint sul tuo backend:
import { BirdRealtime } from "@messagebird/realtime";
const bird = new BirdRealtime({
appKey: "your-app-key",
region: "us1",
authEndpoint: "/bird/auth",
});
const room = bird.subscribe("presence-room-1");import BirdRealtime
let bird = BirdRealtime(options: .init(
appKey: "your-app-key",
region: "us1",
authEndpoint: URL(string: "https://your-backend.example.com/bird/auth")
))
let room = bird.subscribe("presence-room-1")import com.bird.realtime.BirdRealtime
import com.bird.realtime.BirdRealtimeOptions
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
authEndpoint = "https://your-backend.example.com/bird/auth",
)
)
val room = bird.subscribe("presence-room-1")Il client chiama questo endpoint per ogni sottoscrizione private o presence, incluse le sottoscrizioni ripristinate dopo una riconnessione. L'autorizzazione si applica a una singola connessione perché la firma include il suo connection ID.
Il client browser richiede un endpoint same-origin per impostazione predefinita. Imposta allowCrossOriginAuth: true per usare un authEndpoint cross-origin. Il client browser invia i authHeaders configurati solo agli endpoint same-origin.
Cosa riceve e restituisce il tuo endpoint
Il client invia in POST JSON:
Esempio di codice
{ "connection_id": "26896.319537", "channel_name": "presence-room-1" }Rispondi con la firma:
Esempio di codice
{ "auth": "your-app-key:8f9a…" }Per un canale presence, restituisci anche l'identità del membro come JSON stringa, la stessa stringa che hai firmato:
Esempio di codice
{
"auth": "your-app-key:8f9a…",
"member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}member_id è l'identità che gli altri membri vedono e il valore su cui opera la disconnessione. member_info contiene dati JSON opzionali consegnati a ogni membro del canale. Ha un limite di 1 KB, quindi includi solo dati di profilo piccoli e non sensibili.
Autorizza il chiamante in questo endpoint usando il suo session cookie o bearer token. Restituisci 403 Forbidden quando il chiamante non deve entrare nel canale. Per i canali presence, assegna l'identità nella stessa risposta.
La stringa da firmare
Concatena con i due punti, poi applica HMAC-SHA256 con l'app secret e codifica in esadecimale. Prefissa il risultato con l'app key e un due punti.
| Tipo di canale | Stringa da firmare |
|---|---|
| private-… | <connection_id>:<channel_name> |
| private-encrypted-… | <connection_id>:<channel_name> |
| presence-… | <connection_id>:<channel_name>:<member_data> |
Per i canali presence, firma esattamente la stringa member_data che restituisci. Riserializzare lo stesso oggetto può cambiare l'ordine delle chiavi o la spaziatura e invalidare la firma.
Un canale encrypted viene firmato come uno private e la sua risposta di autenticazione restituisce in più la chiave di decrittazione del canale come shared_secret. L'helper SDK la aggiunge automaticamente; Canali encrypted descrive la derivazione e il comportamento del canale.
Ogni SDK server fornisce un helper authorizeChannel. Firma con le credenziali dell'app configurate e restituisce il corpo della risposta senza effettuare una richiesta di rete. Per i canali encrypted, l'helper aggiunge anche shared_secret.
app.post("/bird/auth", async (req, res) => {
const { connection_id, channel_name } = req.body;
// Your own authorization decision goes here.
const user = getUserFromSession(req);
if (!user || !mayJoin(user, channel_name)) return res.sendStatus(403);
const memberData = channel_name.startsWith("presence-")
? JSON.stringify({ member_id: user.id, member_info: { name: user.name } })
: undefined;
res.json(
await bird.realtime.authorizeChannel({
connectionId: connection_id,
channelName: channel_name,
memberData,
}),
);
});import json
@app.post("/bird/auth")
def bird_auth():
body = request.get_json()
channel_name = body["channel_name"]
# Your own authorization decision goes here.
user = get_user_from_session()
if user is None or not may_join(user, channel_name):
abort(403)
member_data = None
if channel_name.startswith("presence-"):
member_data = json.dumps({"member_id": user.id, "member_info": {"name": user.name}})
return client.realtime.authorize_channel(
connection_id=body["connection_id"],
channel_name=channel_name,
member_data=member_data,
)func birdAuth(w http.ResponseWriter, r *http.Request) {
var body struct {
ConnectionID string `json:"connection_id"`
ChannelName string `json:"channel_name"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
// Your own authorization decision goes here.
user, ok := userFromSession(r)
if !ok || !mayJoin(user, body.ChannelName) {
http.Error(w, "forbidden", http.StatusForbidden)
return
}
params := bird.RealtimeChannelAuthorizationParams{
ConnectionID: body.ConnectionID,
ChannelName: body.ChannelName,
}
if strings.HasPrefix(body.ChannelName, "presence-") {
memberData, _ := json.Marshal(map[string]any{
"member_id": user.ID,
"member_info": map[string]string{"name": user.Name},
})
params.MemberData = string(memberData)
}
auth, err := client.Realtime.AuthorizeChannel(params)
if err != nil {
http.Error(w, "authorization failed", http.StatusInternalServerError)
return
}
json.NewEncoder(w).Encode(auth)
}function birdAuth(string $connectionId, string $channelName, User $user): array
{
// Your own authorization decision goes here.
if (!mayJoin($user, $channelName)) {
http_response_code(403);
exit;
}
$memberData = null;
if (str_starts_with($channelName, 'presence-')) {
$memberData = json_encode(['member_id' => $user->id, 'member_info' => ['name' => $user->name]]);
}
return $bird->realtime->authorizeChannel($connectionId, $channelName, $memberData);
}Il contratto di firma è lo stesso in un linguaggio senza un SDK: applica HMAC-SHA256 alla stringa con l'app secret, codifica in esadecimale e prefissa con l'app key e un due punti.
Membri e connessioni
Un membro è un'identità, mentre una connessione è un singolo WebSocket aperto. Se qualcuno apre la tua app in tre schede, un membro possiede tre connessioni. member_added scatta quando la prima connessione sottoscrive e member_removed scatta quando l'ultima lascia. Le altre connessioni modificano il conteggio delle connessioni del canale senza produrre eventi membro.
Errori comuni
Una sottoscrizione rifiutata arriva come errore client. Verifica queste cause comuni:
- Firma non valida. La stringa che hai firmato non corrisponde. Quasi sempre un member_data riserializzato, oppure una firma calcolata sul nome del canale senza il suo prefisso private- o presence-.
- Chiave non valida. La chiave in auth appartiene a un'app diversa oppure è stata revocata. Ruotare le chiavi significa aggiornare sia l'appKey del client sia il secret con cui il tuo endpoint firma.
- Dati membro mancanti. Una sottoscrizione presence è arrivata senza member_data. I canali presence non possono essere sottoscritti in modo anonimo.
- Un 403 dal tuo endpoint. La tua decisione di autorizzazione ha rifiutato, che è il risultato previsto per un utente che non può entrare.
Prossimi passi
- Invia il tuo primo evento realtime è la guida end-to-end su cui si basa questa guida.
- Canali encrypted si basano su questa firma per consegnare ai sottoscrittori approvati anche una chiave di decrittazione.
- Canali presence trattano la lista dei membri, gli eventi membro e la lettura della presence dal tuo server.
- Terminare le connessioni di un membro è l'altra firma che il tuo backend calcola e quella che ti permette di chiudere le connessioni di un membro.
- Webhook ed eventi tratta gli eventi realtime.*, inclusi membri che entrano ed escono, sul tuo endpoint.
Risorse correlate
Prosegui con la documentazione, le guide e gli esempi per questo argomento. Le risorse sono in inglese.