Zamykanie połączeń członka
Autoryzacja kanałów kontroluje subskrypcje, ale nie przypisuje tożsamości na poziomie połączenia. Bez tej tożsamości wylogowanie w innym miejscu nie zamyka istniejącego gniazda ani nie usuwa jego subskrypcji kanałów.
Wywołaj signin(), aby przypisać połączeniu member_id z Twojego backendu. Operacja rozłączenia może wtedy zamknąć każde połączenie tego członka w aplikacji.
Użyj tego przepływu po zdalnym wylogowaniu, unieważnieniu tokena, zablokowaniu, zmianie hasła lub usunięciu miejsca w obszarze roboczym.
1. Zaloguj połączenie
Skieruj klienta na endpoint w swoim backendzie i wywołaj signin() raz:
import { BirdRealtime } from "@messagebird/realtime";
const bird = new BirdRealtime({
appKey: "your-app-key",
region: "us1",
memberAuthEndpoint: "/bird/auth/member",
});
const member = await bird.signin();
console.log("signed in as", member.member_id);import BirdRealtime
let bird = BirdRealtime(options: .init(
appKey: "your-app-key",
region: "us1",
memberAuthEndpoint: URL(string: "https://your-backend.example.com/bird/auth/member")
))
let member = try await bird.signin()
print("signed in as", member.memberId)import com.bird.realtime.BirdRealtime
import com.bird.realtime.BirdRealtimeOptions
val bird = BirdRealtime(
BirdRealtimeOptions(
appKey = "your-app-key",
region = "us1",
memberAuthEndpoint = "https://your-backend.example.com/bird/auth/member",
)
)
val member = bird.signin() // suspending
println("signed in as ${member.memberId}")Tożsamość należy do połączenia. Wywołaj signin() raz, a klient loguje się ponownie po każdym ponownym połączeniu.
Logowanie nie autoryzuje subskrypcji kanałów. Kanały prywatne i kanały obecności nadal wywołują Twój endpoint autoryzacji kanałów. Połączenie bez tożsamości członka może subskrybować każdy kanał zatwierdzony przez ten endpoint. Zobacz Autoryzacja kanałów.
2. Podpisz tożsamość ze swojego backendu
Klient wysyła ID połączenia w żądaniu POST:
Przykład kodu
{ "connection_id": "26896.319537" }Twój endpoint odpowiada tożsamością jako JSON string oraz podpisem tego dokładnego ciągu:
Przykład kodu
{
"auth": "your-app-key:8f9a…",
"member_data": "{\"member_id\":\"u_42\",\"member_info\":{\"name\":\"Ada\"}}"
}Ciąg do podpisania to <connection_id>::member::<member_data>, z dwoma dwukropkami po każdej stronie member. Oblicz HMAC-SHA256 z kluczem sekretnym aplikacji, zakoduj szesnastkowo i dodaj prefiks klucza aplikacji:
import { createHmac } from "node:crypto";
app.post("/bird/auth/member", (req, res) => {
const { connection_id } = req.body;
// Your own decision: who is this caller, and may they connect at all?
const user = getUserFromSession(req);
if (!user) return res.sendStatus(403);
const memberData = JSON.stringify({
member_id: user.id,
member_info: { name: user.name },
});
const sig = createHmac("sha256", process.env.BIRD_REALTIME_SECRET)
.update(`${connection_id}::member::${memberData}`)
.digest("hex");
res.json({ auth: `${process.env.BIRD_REALTIME_KEY}:${sig}`, member_data: memberData });
});import hmac, hashlib, json, os
def sign_in(connection_id: str, user) -> dict:
key = os.environ["BIRD_REALTIME_KEY"]
secret = os.environ["BIRD_REALTIME_SECRET"].encode()
member_data = json.dumps({"member_id": user.id, "member_info": {"name": user.name}})
to_sign = f"{connection_id}::member::{member_data}"
sig = hmac.new(secret, to_sign.encode(), hashlib.sha256).hexdigest()
return {"auth": f"{key}:{sig}", "member_data": member_data}func signIn(connectionID string, user User) (map[string]string, error) {
key := os.Getenv("BIRD_REALTIME_KEY")
secret := []byte(os.Getenv("BIRD_REALTIME_SECRET"))
memberData, err := json.Marshal(map[string]any{
"member_id": user.ID,
"member_info": map[string]string{"name": user.Name},
})
if err != nil {
return nil, err
}
mac := hmac.New(sha256.New, secret)
mac.Write([]byte(connectionID + "::member::" + string(memberData)))
return map[string]string{
"auth": key + ":" + hex.EncodeToString(mac.Sum(nil)),
"member_data": string(memberData),
}, nil
}function signIn(string $connectionId, User $user): array
{
$key = getenv('BIRD_REALTIME_KEY');
$secret = getenv('BIRD_REALTIME_SECRET');
$memberData = json_encode(['member_id' => $user->id, 'member_info' => ['name' => $user->name]]);
$sig = hash_hmac('sha256', "{$connectionId}::member::{$memberData}", $secret);
return ['auth' => "{$key}:{$sig}", 'member_data' => $memberData];
}Podpisz dokładnie ten ciąg member_data, który zwracasz. Ponowna serializacja obiektu może zmienić jego bajty i unieważnić podpis.
member_id to wartość wskazywana przez operację rozłączenia. Przyjmuje do 128 znaków bezpiecznych w URL, w tym + : @ . _ -, ale nie / ? # % ani białe znaki. Jeśli Twój identyfikator zawiera nieobsługiwane znaki, zamapuj go na stabilną bezpieczną wartość przed podpisaniem. Serwer brzegowy odrzuca nieprawidłowy ID członka, pozostawiając połączenie bez tożsamości, którą operacja rozłączenia mogłaby wskazać.
member_info jest opcjonalne. Przy logowaniu połączenia jest zwracane do tego klienta, a nie rozgłaszane na kanale obecności.
Tożsamość może też zawierać tablicę watchlist z identyfikatorami członków. W aplikacjach z włączonym watchlist_events połączenie jest wtedy informowane, gdy ci członkowie przechodzą w tryb online lub offline; zobacz Zdarzenia listy obserwowanych.
Ciąg podpisywany tutaj celowo różni się od ciągu podpisywanego przez subskrypcję obecności, więc autoryzacja obecności nigdy nie może zostać odtworzona w celu przejęcia tożsamości, mimo że oba ładunki nazywają się member_data.
3. Rozłącz członka
await bird.realtime.members.disconnect("rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42");client.realtime.members.disconnect("rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42")if err := client.Realtime.Members.Disconnect(context.Background(), "rap_01krdgeqcxet5s7t44vh8rt9mg", "u_42"); err != nil {
log.Fatal(err)
}$bird->realtime->members->disconnect('rap_01krdgeqcxet5s7t44vh8rt9mg', 'u_42');curl -X POST \
https://us1.platform.bird.com/v1/realtime/apps/rap_01krdgeqcxet5s7t44vh8rt9mg/members/u_42/disconnect \
-H "Authorization: Bearer $BIRD_API_KEY" \
-H "X-Realtime-Key: $BIRD_REALTIME_KEY" \
-H "X-Realtime-Secret: $BIRD_REALTIME_SECRET"Operacja zamyka każde zalogowane połączenie tego członka w aplikacji, łącznie z innymi kartami i urządzeniami. Nie zamyka połączeń anonimowych ani połączeń przypisanych do innego członka.
Co widzi klient
Połączenie zamyka się z kodem 4009 i nie łączy się ponownie automatycznie:
bird.connection.bind("error", (e) => {
if (e.code === 4009) showSignedOutScreen();
});bird.onError { error in
if error.code == 4009 { showSignedOutScreen() }
}bird.onError { error ->
if (error.code == 4009) showSignedOutScreen()
}Pokaż stan wylogowania, gdy uwierzytelnianie się zakończyło. Wywołanie bird.connect() uruchamia nowe połączenie, które loguje się przez Twój endpoint, więc łącz ponownie dopiero po zmianie stanu autoryzacji członka.
Nieudane logowanie nie zamyka gniazda. Klient zgłasza błąd osobno i pozostawia połączenie bez tożsamości członka. Po ponownym połączeniu klient zgłasza to przez signin_error, ponieważ oryginalna obietnica signin() została już rozwiązana.
bird.connection.bind("signin_error", (e) => {
console.warn("connection has no identity:", e.message);
});bird.onSigninError { error in
print("connection has no identity:", error.message)
}bird.onSigninError { error ->
println("connection has no identity: ${error.message}")
}Połączenie nadal może odbierać zdarzenia z autoryzowanych kanałów, ale operacje zdarzeń członka i rozłączenia nie mogą go wskazać. W kliencie przeglądarkowym bird.signedInMember ma wartość null w tym stanie.
Zapobieganie ponownemu połączeniu
Operacja rozłączenia zamyka bieżące połączenia bez tworzenia trwałej blokady. Ten sam klient może połączyć się ponownie.
Unieważnij sesję lub zapisz blokadę przed rozłączeniem członka. Twój endpoint autoryzacji członka może wtedy zwrócić 403 Forbidden, jeśli klient połączy się ponownie.
Następne kroki
- Autoryzacja kanałów opisuje drugi podpis, który oblicza Twój backend, dla subskrypcji prywatnych i subskrypcji obecności.
- Rozłącz członka to pełna dokumentacja API dla tego żądania.
- Wysyłanie zdarzeń do członka to druga operacja adresowana do członka.
- Kanały obecności wyjaśniają, dlaczego jeden członek może mieć kilka połączeń.
Powiązane zasoby
Kontynuuj z dokumentacją, przewodnikami i przykładami dotyczącymi tego tematu. Zasoby są w języku angielskim.
Poznaj możliwościRealtimePodążaj ścieżką naukiBuild your first integrationPrzewodnik wdrożeniowySend your first realtime event
Wypróbuj ćwiczenie i uzyskaj brief wdrożeniowy