登入與登入裝置
使用者登入 IM 後才能收發訊息。推薦的做法是登入憑證:使用者登入你的業務系統後,你的服務端為他簽發一個憑證,App 拿憑證登入 IM。這樣使用者不需要第二套密碼,你的服務端也不用儲存 IM 密碼。
- 使用者登入你的 App 和業務系統。
- 你的服務端呼叫簽發登入憑證,把
ticket返回給 App。加上auto_create時,使用者不存在會自動建立,省掉單獨建號。 - App 在 5 分鐘內用
grant_type: "ticket"呼叫客戶端登入(客戶端 SDK 已經封裝好),得到 User Token 和 refresh token。
你的服務端只需要這一個呼叫:
curl -X POST "$IM_API/$ORG/$APP/users/zhangsan/login-tickets" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "auto_create": true }'
# {"ticket":"ult_...","expires_in":300,"user_created":true}也可以用密碼登入:App 直接提交使用者名稱和密碼,使用者要先有密碼(建立使用者時設定,或設定密碼)。
每次登入為當前裝置建立一個會話(一臺“登入裝置”)。User Token 用於呼叫客戶端介面和建立長連線,過期前用 refresh token 續期。本頁還介紹:
| 內容 | 見 |
|---|---|
| 一個使用者最多同時登入幾臺裝置,超了怎麼辦 | 多端登入 |
| 檢視使用者的登入裝置、把裝置踢下線 | 查詢登入裝置、踢掉全部裝置、踢掉單臺裝置 |
客戶端收到 session_revoked 時的原因 | 下線原因 |
簽發登入憑證
為使用者簽發一個一次性的登入憑證,App 用它登入 IM。
- 一次性:5 分鐘內有效,只能用一次。提交登入後即作廢,即使登入失敗(如裝置數已滿)也要重新簽發。
- 可以重試:每次呼叫簽發一個新憑證,之前的在 5 分鐘內仍有效。超時重試時,只把最後拿到的交給 App。
- 會作廢的情況:簽發後使用者被設定密碼、封禁、踢掉全部裝置或刪除,或在控制檯要求全部使用者重新登入。
- 自動建立:指定
auto_create時,使用者不存在就建立一個沒有密碼的使用者(created_via為openapi)。
憑證相當於使用者的臨時密碼,請只透過 HTTPS 返回給該使用者的 App,不要寫入日誌。
/{org_name}/{app_name}/users/{username}/login-tickets路徑引數
org_name、app_name 見接入概述。
| 引數 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
請求體
請求體可以省略。
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
auto_create | Boolean | 否 | 使用者不存在時是否自動建立,預設 false |
請求示例
curl -X POST "$IM_API/$ORG/$APP/users/zhangsan/login-tickets" \
-H "Authorization: Bearer $APP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"auto_create": true
}'響應
成功返回 201 Created:
| 欄位 | 型別 | 說明 |
|---|---|---|
ticket | String | 登入憑證,以 ult_ 開頭 |
expires_in | Number | 有效期,單位為秒,固定為 300 |
user_created | Boolean | 本次是否自動建立了使用者 |
{
"ticket": "ult_RjcQrK8ff-Y0lfQ_7DqodLbw4WJZQNgdwIgOfsaW3gI",
"expires_in": 300,
"user_created": true
}錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 403 | user_disabled | 使用者已被封禁 |
| 403 | app_unavailable | 需要自動建立使用者,但應用處於只讀狀態。為已存在的使用者簽發不受影響 |
| 404 | not_found | 使用者不存在或已刪除,且沒有指定 auto_create |
| 409 | limit_exceeded | 需要自動建立使用者,但應用的註冊使用者數已達上限 |
客戶端登入
App 用登入憑證或密碼登入 IM。這是客戶端介面,由 App 直接呼叫:
- 路徑以
/client/v1開頭,不含org_name和app_name,用請求體中的app_key指明應用; - 不需要
Authorization請求頭,不要在 App 中使用 App Token; - 允許瀏覽器跨域呼叫,網頁可以直接呼叫。
AppKey 是應用的公開標識,格式為 {org_name}#{app_name},如 1575529652#demo,可以在控制檯的應用詳情中檢視。它不是金鑰,可以寫在 App 中,憑它只能登入和註冊,沒有任何管理許可權。
/client/v1/sessions請求體
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
app_key | String | 是 | 應用的 AppKey |
grant_type | String | 是 | 登入方式:ticket 憑證登入,password 密碼登入 |
ticket | String | 憑證登入時必填 | 業務服務端簽發的登入憑證 |
username | String | 密碼登入時必填 | 使用者名稱,不區分大小寫。憑證登入時可選,給出時必須是憑證所屬的使用者,否則按憑證無效處理 |
password | String | 密碼登入時必填 | 密碼 |
device_id | String | 是 | 裝置標識,1 到 64 個可見 ASCII 字元。由 App 生成並在裝置上持久儲存,同一臺裝置每次登入使用相同的值 |
device_name | String | 否 | 裝置名稱,如 iPhone 15,最長 64 個字元,超長截斷。其他裝置被這臺裝置擠下線時會看到這個名稱 |
platform | String | 否 | 平臺:ios、android、harmony、windows、macos、linux、web、mini_program,其他值和省略時記為 other。用於按平臺限制裝置數,見多端登入 |
sdk_version | String | 否 | 客戶端版本,最長 32 個字元,超長截斷 |
同一個 device_id 再次登入時,這臺裝置上原來的會話被替換下線。網頁端請讓同一瀏覽器的所有標籤頁共用一個 device_id 和一次登入,各標籤頁分別登入會互相替換。
請求示例
憑證登入:
curl -X POST "$IM_API/client/v1/sessions" \
-H "Content-Type: application/json" \
-d '{
"app_key": "1575529652#demo",
"grant_type": "ticket",
"ticket": "ult_RjcQrK8ff-Y0lfQ_7DqodLbw4WJZQNgdwIgOfsaW3gI",
"device_id": "5f0c2a9e-7d1b-4c7e-9a51-2f6d0f3b8c11",
"device_name": "iPhone 15",
"platform": "ios",
"sdk_version": "1.0.0"
}'密碼登入:
curl -X POST "$IM_API/client/v1/sessions" \
-H "Content-Type: application/json" \
-d '{
"app_key": "1575529652#demo",
"grant_type": "password",
"username": "zhangsan",
"password": "Passw0rd!",
"device_id": "5f0c2a9e-7d1b-4c7e-9a51-2f6d0f3b8c11",
"device_name": "iPhone 15",
"platform": "ios",
"sdk_version": "1.0.0"
}'響應
成功返回 201 Created:
| 欄位 | 型別 | 說明 |
|---|---|---|
access_token | String | User Token。客戶端呼叫客戶端介面和建立長連線時放在請求頭 Authorization: Bearer <User Token> 中 |
access_token_expires_in | Number | User Token 的有效期,單位為秒,預設 86400(1 天)。可為 null,表示不過期 |
refresh_token | String | 用於續期的 refresh token,以 urt_ 開頭 |
refresh_token_expires_in | Number | 會話的有效期,單位為秒,預設 604800(7 天);在此之前續期會順延。可為 null,表示不過期 |
session_id | String | 本次登入的會話 ID,與登入裝置物件的 session_id 相同 |
user | Object | 本人資料:username、nickname、avatar_url、attributes、has_password、version,含義同使用者物件 |
config | Object | 應用的執行配置,如裝置數上限、訊息大小上限、撤回時限、是否開啟已讀回執等,客戶端據此決定介面的顯示。各項的值由控制檯的執行策略決定 |
兩個有效期都由應用的執行策略決定。示例中縮短了令牌,config 只列出了部分欄位:
{
"access_token": "eyJhbGciOiJFZERTQSIsImtpZCI6ImsxIiwidHlwIjoiSldUIn0.eyJpc3Mi...",
"access_token_expires_in": 86400,
"refresh_token": "urt_99582942128373760_2AhAQZTPK86ahHMlW1waLQP2vOw0wJcGlFTuZPqGSEs",
"refresh_token_expires_in": 604800,
"session_id": "99582942128373760",
"user": {
"username": "zhangsan",
"nickname": "张三丰",
"avatar_url": "",
"attributes": { "gender": "1", "level": "vip" },
"has_password": true,
"version": 3
},
"config": {
"version": "1.1.0",
"max_online_devices_per_user": 4,
"device_limits_by_platform": null,
"single_read_ack_enabled": true,
"max_message_body_bytes": 5120,
"recall_window_seconds": 120,
"message_retention_days": 90
}
}錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 400 | invalid_argument | grant_type 不是 password 或 ticket;device_id 缺失或格式不對;密碼登入時使用者名稱格式不對或密碼為空 |
| 401 | invalid_credentials | 使用者名稱或密碼錯誤、使用者不存在或沒有設定密碼;憑證無效、已使用、已過期或已作廢。為防止探測使用者名稱,這幾種情況不作區分。憑證登入失敗時,App 可以向業務系統重新獲取一次憑證後重試 |
| 403 | user_disabled | 使用者已被封禁。只在密碼正確或憑證有效時返回,可以據此提示“賬號已被封禁” |
| 403 | tenant_unavailable | 租戶已暫停服務 |
| 403 | app_unavailable | 應用已停用或被暫停服務 |
| 404 | not_found | app_key 對應的應用不存在 |
| 409 | device_limit_exceeded | 登入裝置數已達上限,且應用設定為拒絕新裝置登入,見多端登入 |
| 429 | too_many_attempts | 密碼錯誤次數過多,暫時不能用密碼登入,按 Retry-After 響應頭等待後再試,不要自動重試。憑證登入不受影響 |
| 429 | rate_limited | 登入請求過於頻繁,按 Retry-After 等待後重試。每個客戶端 IP 每分鐘最多 120 次,另計入應用的客戶端請求額度 |
為防止猜密碼,密碼登入失敗有以下限制。暫停期間已登入的裝置和憑證登入都不受影響:
| 失敗 | 結果 |
|---|---|
| 同一使用者在同一 IP 失敗 10 次 | 這個 IP 15 分鐘內不能再用密碼登入這個使用者 |
| 同一 IP 1 小時內對同一應用失敗 100 次 | 這個 IP 在這個應用的密碼登入全部暫停 |
| 同一使用者 1 小時內(不分 IP)失敗 100 次 | 這個使用者的密碼登入暫停 |
續期與退出
- 續期:User Token 過期前,App 呼叫
POST /client/v1/sessions/refresh,請求體為{"refresh_token": "..."},返回新的access_token、refresh_token和它們的有效期。每次續期都會換髮新的 refresh token,請儲存新的值;會話有效期隨之順延,只要使用者在有效期內使用過 App,就一直保持登入。 - 退出:使用者退出登入時,App 呼叫
POST /client/v1/sessions/logout,請求體為{"refresh_token": "..."},成功返回204。只在本地清除令牌會讓服務端以為這臺裝置仍在登入,繼續佔用裝置數,也會繼續收到這個使用者的離線推送。 - 被下線:裝置被踢、被擠下線或使用者被封禁後,客戶端介面返回
401 session_revoked,details.reason說明原因,見下線原因。這時不要續期,清除本地令牌後回到登入頁。 - 推送隨登入解綁:App 登記的推送令牌屬於這次登入。退出登入或被下線後,這臺裝置的推送登記隨之自動解綁,App 不需要另外登出推送;重新登入後再登記。
客戶端自注冊
使用者在 App 中自行註冊,不經過業務服務端。只有應用的註冊模式(registration_mode)為 open 時允許,可以在控制檯的應用管理中修改;新建應用預設為 authorized,只能由服務端建立使用者,這時呼叫返回 403 permission_denied。
只建議在測試應用中開啟
自注冊任何人都能呼叫。正式應用請由你的服務端建立使用者,或在簽發登入憑證時自動建立。
/client/v1/users請求體
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
app_key | String | 是 | 應用的 AppKey |
username | String | 是 | 使用者名稱,規則見使用者名稱與資料 |
password | String | 是 | 密碼,1 到 64 個字元 |
nickname | String | 否 | 暱稱,最長 64 個字元 |
請求示例
curl -X POST "$IM_API/client/v1/users" \
-H "Content-Type: application/json" \
-d '{
"app_key": "1575529652#demo",
"username": "xiaoming",
"password": "secret123",
"nickname": "小明"
}'響應
成功返回 201 Created,響應體為本人資料:
{
"username": "xiaoming",
"nickname": "小明",
"avatar_url": "",
"attributes": {},
"has_password": true,
"version": 1
}錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 400 | invalid_argument | 沒有設定密碼,或引數不符合使用者名稱與資料中的規則 |
| 403 | permission_denied | 應用的註冊模式不是 open,不允許客戶端註冊 |
| 403 | tenant_unavailable / app_unavailable | 租戶或應用暫停服務,或應用處於只讀狀態 |
| 403 | content_rejected | 暱稱未透過內容安全檢查,details.field 為 nickname |
| 404 | not_found | app_key 對應的應用不存在 |
| 409 | already_exists | 使用者名稱已被佔用 |
| 409 | limit_exceeded | 應用的註冊使用者數已達上限 |
| 429 | rate_limited | 註冊過於頻繁,按 Retry-After 等待後重試 |
多端登入
一個使用者可以同時在多臺裝置上登入,每臺裝置一個會話。裝置數有兩級上限,由應用的執行策略決定。其中 device_limits_by_platform 目前不能在控制檯中修改,需要按平臺限制時請聯絡我們:
| 策略 | 說明 | 預設值 |
|---|---|---|
max_online_devices_per_user | 每個使用者同時登入的裝置總數,1 到 20 | 4 |
device_limits_by_platform | 同一平臺分組內的裝置數,每組 1 到 20,用於實現“手機、電腦各一臺”這類同平臺互踢。分組為 mobile(ios、android、harmony)、desktop(windows、macos、linux)、web、mini_program、other | 不按平臺限制 |
device_overflow_policy | 超出上限時的處理:kick_oldest 擠掉最早登入的裝置,reject_new 拒絕新裝置登入 | kick_oldest |
登入新裝置時先檢查新裝置所在平臺分組的上限,再檢查總數上限:
kick_oldest:超出分組上限時擠掉該分組內最早登入的裝置,超出總數上限時擠掉所有裝置中最早登入的裝置。被擠掉的裝置收到原因device_limit,以及新裝置的名稱和平臺,可以提示“你的賬號已在 iPhone 15 上登入”。例如設為{"mobile": 1, "desktop": 1}時,新手機登入會擠掉舊手機,電腦不受影響;reject_new:本次登入返回409 device_limit_exceeded。按登入會話計數,不按是否線上:斷網的裝置仍佔名額,退出、被踢或會話過期後才釋放。用
reject_new時,使用者的舊裝置丟了,可以踢掉單臺裝置釋放名額。調低上限不會踢掉已登入的裝置,下次有新裝置登入時才按新上限處理。
查詢登入裝置
查詢使用者當前登入的裝置,只列出有效的會話(沒有被踢下線、退出或過期),按最近活躍時間倒序排列。裝置數受上限約束,結果不分頁。
/{org_name}/{app_name}/users/{username}/sessions路徑引數
org_name、app_name 見接入概述。
| 引數 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
請求示例
curl "$IM_API/$ORG/$APP/users/zhangsan/sessions" \
-H "Authorization: Bearer $APP_TOKEN"響應
成功返回 200 OK。items 為登入裝置,每項為登入裝置物件;沒有登入的裝置時為空陣列。
{
"items": [
{
"session_id": "99583185116987392",
"device_id": "mac-1a2b3c",
"device_name": "MacBook Pro",
"platform": "macos",
"sdk_version": "1.0.0",
"login_method": "password",
"ip": "203.0.113.8",
"created_at": "2026-10-02T19:08:01.501Z",
"last_active_at": "2026-10-02T19:08:01.501Z",
"expires_at": "2026-10-09T19:08:01.501Z"
},
{
"session_id": "99582942128373760",
"device_id": "5f0c2a9e-7d1b-4c7e-9a51-2f6d0f3b8c11",
"device_name": "iPhone 15",
"platform": "ios",
"sdk_version": "1.0.0",
"login_method": "ticket",
"ip": "198.51.100.23",
"created_at": "2026-10-02T19:07:03.568Z",
"last_active_at": "2026-10-02T19:07:53.750Z",
"expires_at": "2026-10-09T19:07:53.750Z"
}
]
}錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 404 | not_found | 使用者不存在或已刪除 |
踢掉全部裝置
讓使用者的所有裝置下線:線上的裝置會被斷開連線並收到原因 kicked,此前簽發、尚未使用的登入憑證作廢。各裝置登記的推送令牌隨之解綁,不再收到這個使用者的推送。使用者沒有登入的裝置時同樣返回成功。
踢下線不會阻止使用者重新登入。需要禁止登入的,請封禁使用者。每次呼叫都會讓當時登入的全部裝置下線,請求超時後重試,也會讓兩次呼叫之間新登入的裝置下線。
/{org_name}/{app_name}/users/{username}/sessions路徑引數
org_name、app_name 見接入概述。
| 引數 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
請求示例
curl -X DELETE "$IM_API/$ORG/$APP/users/zhangsan/sessions" \
-H "Authorization: Bearer $APP_TOKEN"響應
成功返回 204 No Content,沒有響應體。
錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 404 | not_found | 使用者不存在或已刪除 |
踢掉單臺裝置
讓使用者的一臺裝置下線,線上時會被斷開連線並收到原因 kicked。這臺裝置登記的推送令牌隨之解綁,不再向它推送,見推送裝置與設定。這臺裝置之後仍可以重新登入。
裝置已經下線(被踢、退出或被擠掉)時同樣返回成功,可以放心重試。
/{org_name}/{app_name}/users/{username}/sessions/{session_id}路徑引數
org_name、app_name 見接入概述。
| 引數 | 型別 | 說明 |
|---|---|---|
username | String | 使用者名稱 |
session_id | String | 會話 ID,取自查詢登入裝置的 session_id |
請求示例
curl -X DELETE "$IM_API/$ORG/$APP/users/zhangsan/sessions/99583185116987392" \
-H "Authorization: Bearer $APP_TOKEN"響應
成功返回 204 No Content,沒有響應體。
錯誤
| HTTP 狀態碼 | code | 說明 |
|---|---|---|
| 404 | not_found | 使用者不存在或已刪除;會話不存在或不屬於這個使用者 |
下線原因
裝置下線後,線上的裝置會被斷開連線,離線的裝置在下一次請求時收到 401 session_revoked,details.reason 說明原因:
reason | 原因 |
|---|---|
replaced | 同一臺裝置(相同的 device_id)重新登入 |
device_limit | 登入裝置數超出上限,被新裝置擠掉 |
kicked | 被業務服務端、控制檯踢下線,或被使用者本人在其他裝置上踢下線 |
password_changed | 密碼被修改或重置 |
user_disabled | 使用者被封禁 |
user_deleted | 使用者被刪除 |
relogin_required | 在控制檯要求應用內全部使用者重新登入 |
token_reuse | 已經換下的 refresh token 被再次使用,可能已經洩露 |
expired | 會話過期(超過有效期沒有續期) |
原因為 replaced 或 device_limit 時,details 另有 device_name 和 platform,為新登入的裝置:
{
"error": {
"code": "session_revoked",
"message": "登录设备数超过上限,你的账号已在其他设备登录",
"details": { "reason": "device_limit", "device_name": "Chrome", "platform": "web" },
"request_id": "LE3YXRXUWZWAUNQY7YODQNV45U"
}
}資料結構
登入裝置物件
| 欄位 | 型別 | 說明 |
|---|---|---|
session_id | String | 會話 ID |
device_id | String | 裝置標識,登入時由客戶端提交 |
device_name | String | 裝置名稱,沒有時為空字串 |
platform | String | 平臺:ios、android、harmony、windows、macos、linux、web、mini_program 或 other |
sdk_version | String | 客戶端版本,沒有時為空字串 |
login_method | String | 登入方式:ticket 憑證登入,password 密碼登入 |
ip | String | 登入時的客戶端 IP |
created_at | String | 登入時間 |
last_active_at | String | 最近一次登入或續期的時間 |
expires_at | String | 會話的過期時間,按應用當前的執行策略計算,在此之前續期會順延。可為 null,表示不過期 |
{
"session_id": "99582942128373760",
"device_id": "5f0c2a9e-7d1b-4c7e-9a51-2f6d0f3b8c11",
"device_name": "iPhone 15",
"platform": "ios",
"sdk_version": "1.0.0",
"login_method": "ticket",
"ip": "198.51.100.23",
"created_at": "2026-10-02T19:07:03.568Z",
"last_active_at": "2026-10-02T19:07:53.750Z",
"expires_at": "2026-10-09T19:07:53.750Z"
}