登录及登出 IM

更新时间: 2024/12/12 15:44:07

初始化 NIM SDK 之后,您可以调用接口登录 IM。登录成功后,应用才能正常调用收发消息和创建会话等其他 SDK 接口。本文介绍账号集成与登录的技术原理、实现 IM 登录及登出的流程、IM 登录状态转换流程,以及相关常见问题。

支持平台

本文内容适用的开发平台或框架如下表所示:

Android iOS macOS/Windows Web/uni-app/小程序 HarmonyOS Flutter
✔️️️ ✔️️️ ✔️️️ ✔️️️ ✔️️️ ✔️️️

登录策略

根据鉴权方式,登录策略分为三种:静态 Token 登录、动态 Token 登录和通过第三方回调登录。您可按需实现 一种或多种 登录策略。更多相关说明,请参考 IM 登录最佳实践登录鉴权

登录流程

IM 的登录与账号集成密切相关。下图展示了应用集成 NIM SDK 后,从账号集成到登录 IM 成功的主要流程:

sequenceDiagram
autoNumber
participant app as 开发者应用客户端
participant appserver as 开发者应用服务端
participant imserver as 网易云信服务端
appserver->>imserver:调用服务端接口创建 IM 账<br>号(accountId),您可<br>指定 Token 或使用返回的 Token
imserver-->>appserver:返回 accountId 和 Token,您需要<br>在应用服务端保存两者的映射关系
app->>appserver:发起登录请求
appserver-->>app:登录成功,返回 accountId 和 Token,您<br>需要保存两者的映射关系
app->>imserver:SDK 带 Token 进行登录认证
imserver-->>app:认证成功,登录 IM 服务成功
  1. 用户在应用客户端注册用户账号时,由应用服务端向网易云信服务端发起 注册 IM 账号 的请求。

  2. IM 账号创建成功后,网易云信服务端会返回该 IM 账号(即 accountId)和 token 等信息。此时,应用服务端需要负责保存 accountIdtoken 的映射关系。

  3. 应用客户端发起登录请求时,先走应用自有的登录验证逻辑,如账号和密码的验证。

  4. 验证成功后,应用服务端将与该用户对应的 accountIdtoken 等信息返回给应用客户端。此时,应用客户端需要负责保存 accountIdtoken 的映射关系。

  5. 当应用客户端需要调用网易云信的 IM 服务时,需要先进行 token 验证,以登录 IM 服务。

  6. token 验证成功后,应用客户端登录 IM 服务成功。之后用户便可调用 NIM SDK 的相关接口使用 IM 服务,如进行 IM 消息收发。

    • 终端用户使用网易云信 IM 服务时,应用本身的用户账号和网易云信的 IM 账号(accountId彼此独立。网易云信的 IM 账号只用于网易云信 IM 服务的鉴权,IM 账号并不等同于应用的用户账号
    • 应用的用户账号和密码,与网易云信登录 IM 使用的 accountIdtoken 完全不一致。accountIdtoken 不由终端用户创建,而是由应用服务端分配,以保证安全性。

前提条件

根据本文操作前,请确保您已经完成了以下操作:

第一步:配置 IM 登录策略

登录策略指您的应用需要采用的一种或多种 IM 登录方式。登录 IM 前,您需要在 网易云信控制台 配置应用的 IM 登录策略。如未配置相应的登录策略,后续调用登录接口时可能因无登录权限而报错(状态码:403)。

  1. 网易云信控制台 首页 应用管理 中选择应用,然后单击 IM 即时通讯 下的 功能配置 按钮进入功能配置页。

    image.png
  2. 在顶部选择 基础功能 页签,配置 登录策略

    image.png

第二步:准备 Token

根据以上配置的登录策略,您需要获取对应的 Token 以供后续鉴权。

  • 静态 Token:默认永久有效。如有需要,可通过网易云信新版服务端 API 主动刷新 Token

  • 动态 Token:具有时效性,可在生成时设置有效期。

  • 动态登录扩展数据(LoginExtension):适用于所有登录模式。如果在 第三方回调登录 模式中设置动态登录扩展数据,第三方服务器可使用该值来进行鉴权。

获取静态 Token

您可以通过以下两种方式获取静态 Token,用于 静态 Token 登录 的鉴权。

  • 方式一:在 网易云信控制台 获取静态 Token

    如果您只需进行简单的 体验或快速测试,那么可以在 网易云信控制台 创建 IM 测试账号,并获取与该账号对应的静态 Token,获取方式请参考 注册 IM 账号

  • 方式二:调用服务端 API 获取静态 Token

    如果您有正式的 生产环境,且您的业务 需保障基础的用户信息安全,那么可通过网易云信 IM 新版服务端 API 注册 IM 正式账号,并获取与之相对应的静态 Token。

获取动态 Token

如果您有正式的 生产环境,且您的业务 对用户信息安全有较高的要求,可选择 动态 Token 登录。获取动态 Token 步骤如下:

  1. 注册 IM 账号,获取 accountId

    • 方式一:在 网易云信控制台 注册 IM 测试账号

      如果您只需进行简单的 体验或快速测试,那么可以在 网易云信控制台 创建 IM 测试账号,请参考 注册 IM 账号

    • 方式二:调用服务端 API 注册 IM 正式账号

      如果您有正式的 生产环境,且您的业务 需保障基础的用户信息安全,那么可通过网易云信 IM 新版服务端 API 注册 IM 正式账号

  2. 基于 App Key、App Secret 和 accountId,通过 约定算法应用服务端 生成动态 Token。

  3. 客户端可在登录时通过 tokenProvider,从回调中获取动态 Token。具体实现方式请参考下文 动态 Token 登录

获取动态登录扩展数据

客户端可在登录时通过 loginExtensionProvider,从回调中获取动态登录扩展数据。具体实现方式请参考下文 通过第三方回调登录

第三步:注册登录相关事件监听

1. 注册登录状态相关监听

Android/iOS/macOS/Windows

调用 addLoginListener 方法注册登录相关监听器,包括登录状态变化、登录失败、登录终端被踢、登录终端信息变更。

  • 相关回调:

    • onLoginStatus:登录状态变化回调
    • onLoginFailed:登录失败回调
    • onKickedOffline:登录终端被其他端踢下线回调
    • onLoginClientChanged:登录终端登录信息变更回调
  • 示例代码:

    Android
    JavaNIMClient.getService(V2NIMLoginService.class).addLoginListener(new V2NIMLoginListener() {
        @Override
        public void onLoginStatus(V2NIMLoginStatus status) {
            // Handle login status
        }
        @Override
        public void onLoginFailed(V2NIMError error) {
            // Handle login error
        }
        @Override
        public void onKickedOffline(V2NIMKickedOfflineDetail detail) {
            // Handle kicked offline detail
        }
        @Override
        public void onLoginClientChanged(V2NIMLoginClientChange change, List<V2NIMLoginClient> clients) {
            // Handle login client change
        }
    });
    
    iOS
    Objective-C@interface V2NIMLoginServiceSample : NSObject<V2NIMLoginListener>
    
    @end
    
    @implementation V2NIMLoginServiceSample
    
    - (void)listen {
        [[[NIMSDK sharedSDK] v2LoginService] addLoginListener:self];
    }
    
    - (void)onLoginStatus:(V2NIMLoginStatus)status {
        // Handle login status
    }
    
    - (void)onLoginFailed:(V2NIMError *)error {
        // Handle login error
    }
    
    - (void)onKickedOffline:(V2NIMKickedOfflineDetail *)detail {
        // Handle kicked offline detail
    }
    
    - (void)onLoginClientChanged:(V2NIMLoginClientChange)change clients:(nullable NSArray<V2NIMLoginClient *> *)clients {
        // Handle login client change
    }
    
    @end
    
    macOS/Windows
    C++V2NIMLoginListener listener;
    listener.onLoginStatus = [](V2NIMLoginStatus status) {
        // Handle login status
    };
    listener.onLoginFailed = [](V2NIMError error) {
        // Handle login error
    };
    listener.onKickedOffline = [](V2NIMKickedOfflineDetail detail) {
        // Handle kicked offline detail
    };
    listener.onLoginClientChanged = [](V2NIMLoginClientChange change, std::vector<V2NIMLoginClient> clients) {
        // Handle login client change
    };
    loginService.addLoginListener(listener);
    

    如需移除登录相关监听器,可调用 removeLoginListener

    Android
    JavaNIMClient.getService(V2NIMLoginService.class).removeLoginListener(listener);
    
    iOS
    Objective-Cid<V2NIMLoginListener> listener;
    [[[NIMSDK sharedSDK] v2LoginService] removeLoginListener:listener];
    
    macOS/Windows
    C++V2NIMLoginListener listener;
    loginService.removeLoginListener(listener);
    

Web/uni-app/小程序/HarmonyOS

调用 on("EventName") 方法注册登录相关监听器,包括登录状态变化、登录失败、登录终端被踢、登录终端信息变更。

  • 相关回调:

    • onLoginStatus:登录状态变化回调
    • onLoginFailed:登录失败回调
    • onKickedOffline:登录终端被其他端踢下线回调
    • onLoginClientChanged:登录终端登录信息变更回调
  • 示例代码:

    Web/uni-app/小程序
    TypeScriptnim.V2NIMLoginService.on("onLoginStatus", theListnerFn)
    nim.V2NIMLoginService.on("onLoginFailed", theListnerFn)
    nim.V2NIMLoginService.on("onKickedOffline", theListnerFn)
    nim.V2NIMLoginService.on("onLoginClientChanged", theListnerFn)
    

    如需移除登录相关监听器,可调用 off("EventName")

    TypeScriptnim.V2NIMLoginService.off("onLoginStatus")
    nim.V2NIMLoginService.off("onLoginFailed")
    nim.V2NIMLoginService.off("onKickedOffline")
    nim.V2NIMLoginService.off("onLoginClientChanged")
    
    HarmonyOS
    TypeScriptnim.loginService.on("onLoginStatus", (status: V2NIMLoginStatus) => {})
    nim.loginService.on("onLoginFailed", (error: V2NIMError) => {})
    nim.loginService.on("onKickedOffline", (detail: V2NIMKickedOfflineDetail) => {})
    nim.loginService.on("onLoginClientChanged", (change: V2NIMLoginClientChange, clients: V2NIMLoginClient[]) => {})
    

    如需移除登录相关监听器,可调用 off("EventName")

    TypeScriptnim.loginService.off("onLoginStatus", theListnerFn)
    nim.loginService.off("onLoginFailed", theListnerFn)
    nim.loginService.off("onKickedOffline", theListnerFn)
    nim.loginService.off("onLoginClientChanged", theListnerFn)
    

Flutter

调用 add 方法注册登录相关监听器,包括登录状态变化、登录失败、登录终端被踢、登录终端信息变更。

  • 相关回调:

    • onLoginStatus:登录状态变化回调
    • onLoginFailed:登录失败回调
    • onKickedOffline:登录终端被其他端踢下线回调
    • onLoginClientChanged:登录终端登录信息变更回调
  • 示例代码:

    Dartfinal subsriptions = <StreamSubscription>[];
    subsriptions.add(NimCore.instance.loginService.onLoginStatus.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onLoginFailed.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onKickedOffline.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onLoginClientChanged.listen((event) {
    }));
    

    如需移除登录相关监听器,可调用 cancel 方法移除。

    Dartsubsriptions.forEach((subsription) {
    subsription.cancel();
    });
    

2. 注册登录连接状态监听

登录 IM 时,客户端会与 IM 服务端建立长连接,连接成功则登录成功。

Android/iOS/macOS/Windows

登录 IM 成功后,SDK 会自动同步离线消息、漫游消息、用户信息、群信息、系统通知等数据。数据同步完成时,整个登录过程才算真正完成

调用 addLoginDetailListener 方法注册登录连接状态监听器,包括登录连接状态变化、断开连接、连接失败、数据同步状态。

  • 相关回调:

    • onConnectStatus:登录连接状态变化回调
    • onDisconnected:登录连接断开回调
    • onConnectFailed:登录连接失败回调
    • onDataSync:数据同步状态变化回调。发送消息等后续操作要求数据库处于开启状态,否则可能导致发送消息失败,或者阻塞等待数据库开启。
  • 示例代码:

    Android
    JavaNIMClient.getService(V2NIMLoginService.class).addLoginDetailListener(new V2NIMLoginDetailListener() {
    
        @Override
        public void onConnectStatus(V2NIMConnectStatus status) {
            // TODO
        }
    
        @Override
        public void onDisconnected(V2NIMError error) {
            // TODO
        }
    
        @Override
        public void onConnectFailed(V2NIMError error) {
            // TODO
        }
    
        @Override
        public void onDataSync(V2NIMDataSyncType type, V2NIMDataSyncState state, V2NIMError error) {
            // TODO
        }
    });
    
    iOS
    Objective-C@interface V2NIMLoginServiceSample : NSObject <V2NIMLoginDetailListener>
    
    @end
    
    @implementation V2NIMLoginServiceSample
    
    - (void)listen {
        [[[NIMSDK sharedSDK] v2LoginService] addLoginDetailListener:self];
    }
    
    - (void)onConnectStatus:(V2NIMConnectStatus)status {
        // Handle connect status
    }
    
    - (void)onDisconnected:(nullable V2NIMError *)error {
        // Handle disconnected error
    }
    
    - (void)onConnectFailed:(nullable V2NIMError *)error {
        // Handle connect failed error
    }
    
    - (void)onDataSync:(V2NIMDataSyncType)type
                state:(V2NIMDataSyncState)state
                error:(nullable V2NIMError *)error {
        // Handle data sync
    }
    
    @end
    
    macOS/Windows
    C++V2NIMLoginDetailListener listener;
    listener.onConnectStatus = [](V2NIMConnectStatus status) {
        // Handle connect status
    };
    listener.onDisconnected = [](V2NIMError error) {
        // Handle disconnected error
    };
    listener.onConnectFailed = [](V2NIMError error) {
        // Handle connect failed error
    };
    listener.onDataSync = [](V2NIMDataSyncType type, V2NIMDataSyncState state, V2NIMError error) {
        // Handle data sync
    };
    loginService.addLoginDetailListener(listener);
    

    如需移除登录连接状态监听器,可调用 removeLoginDetailListener

    Android
    JavaNIMClient.getService(V2NIMLoginService.class).removeLoginDetailListener(listener);
    
    iOS
    Objective-Cid<V2NIMLoginDetailListener> listener;
    [[[NIMSDK sharedSDK] v2LoginService] removeLoginDetailListener:listener];
    
    macOS/Windows
    C++V2NIMLoginDetailListener listener;
    loginService.removeLoginDetailListener(listener);
    

Web/uni-app/小程序/HarmonyOS

登录 IM 成功后,SDK 会自动同步离线消息、漫游消息、用户信息、群信息、系统通知等数据。数据同步完成时,整个登录过程才算真正完成

调用 on("EventName") 方法注册登录连接状态监听器,包括登录连接状态变化、断开连接、连接失败、数据同步状态。

  • 相关回调:

    • onConnectStatus:登录连接状态变化回调
    • onDisconnected:登录连接断开回调
    • onConnectFailed:登录连接失败回调
    • onDataSync:数据同步状态变化回调。发送消息等后续操作要求数据库处于开启状态,否则可能导致发送消息失败,或者阻塞等待数据库开启。
  • 示例代码:

    Web/uni-app/小程序
    TypeScriptnim.V2NIMLoginService.on("onConnectStatus", function (status: V2NIMConnectStatus) {})
    nim.V2NIMLoginService.on("onDisconnected", function (error: V2NIMError) {})
    nim.V2NIMLoginService.on("onConnectFailed", function (error: V2NIMError) {})
    nim.V2NIMLoginService.on("onDataSync", function (type: V2NIMDataSyncType, state:    V2NIMDataSyncState, error?: V2NIMError) {})
    

    如需移除登录连接状态监听器,可调用 off("EventName")

    TypeScriptnim.V2NIMLoginService.off("onConnectStatus")
    nim.V2NIMLoginService.off("onDisconnected")
    nim.V2NIMLoginService.off("onConnectFailed")
    nim.V2NIMLoginService.off("onDataSync")
    
    HarmonyOS
    TypeScriptnim.loginService.on("onConnectStatus", (status: V2NIMConnectStatus) => {})
    nim.loginService.on("onDisconnected", (error: V2NIMError) => {})
    nim.loginService.on("onConnectFailed", (error: V2NIMError) => {})
    nim.loginService.on("onDataSync", (type: V2NIMDataSyncType, state: V2NIMDataSyncState, error?: V2NIMError) => {})
    

    如需移除登录连接状态监听器,可调用 off("EventName")

    TypeScriptnim.loginService.off("onConnectStatus", theListner)
    nim.loginService.off("onDisconnected", theListner)
    nim.loginService.off("onConnectFailed", theListner)
    nim.loginService.off("onDataSync", theListner)
    

Flutter

登录 IM 成功后,SDK 会自动同步离线消息、漫游消息、用户信息、群信息、系统通知等数据。数据同步完成时,整个登录过程才算真正完成。

调用 add 方法注册登录连接状态监听器,包括登录连接状态变化、断开连接、连接失败、数据同步状态。

  • 相关回调:

    • onConnectStatus:登录连接状态变化回调
    • onDisconnected:登录连接断开回调
    • onConnectFailed:登录连接失败回调
    • onDataSync:数据同步状态变化回调。发送消息等后续操作要求数据库处于开启状态,否则可能导致发送消息失败,或者阻塞等待数据库开启。
  • 示例代码:

    Dartfinal subsriptions = <StreamSubscription>[];
    subsriptions.add(NimCore.instance.loginService.onConnectStatus.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onDisconnected.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onConnectFailed.listen((event) {
    }));
    subsriptions.add(NimCore.instance.loginService.onDataSync.listen((event) {
    }));
    

    如需移除登录相关监听器,可调用 cancel 方法移除。

    Dartsubsriptions.forEach((subsription) {
      subsription.cancel();
    });
    

第四步:登录 IM

静态 Token 登录

调用 login 方法登录 IM,鉴权方式为静态 Token 鉴权。

调用后,SDK 会自动连接 IM 服务端,传递用户信息并返回登录结果。登录过程中用户可主动取消登录。如果因为网络或其他原因导致 IM 服务端长时间未响应,用户未主动取消登录,SDK 将在 45 秒后自动重连 IM 服务端,并返回 错误码

  • 登录部分参数说明:

    参数名称 说明
    accountId IM 为用户分配的唯一登录账号。通过网易云信控制台获取或调用新版服务端 API 注册。获取方式请参考 获取静态 Token
    token 静态鉴权 Token,通过网易云信控制台获取或调用服务端 API 生成。获取方式请参考 获取静态 Token
    option 登录配置。静态 Token 登录可配置如下字段:
  • forceMode:是否强制登录
  • timeout:登录超时时间
  • retryCount:登录失败后重试次数
  • authType:鉴权方式,默认为 0 静态 Token 鉴权
  • syncLevel:数据同步模式,分为完全同步和基础数据同步
  • 示例代码:

    Android
    JavaNIMClient.getService(V2NIMLoginService.class).login("account", "token", null, new V2NIMSuccessCallback<Void>() {
        @Override
        public void onSuccess(Void unused) {
            // TODO
        }
    },
        new V2NIMFailureCallback() {
        @Override
        public void onFailure(V2NIMError error) {
            int code = error.getCode();
            String desc = error.getDesc();
            // TODO
        }
    });
    
    iOS
    Objective-C- (void)login
    {
        NSString *accountId = @"accountId";
        NSString *token = @"token";
        [[NIMSDK sharedSDK].v2LoginService login:accountId token:token
                option:nil
                  success:^{
            NSLog(@"login succ");
        }
                  failure:^(V2NIMError * _Nonnull error) {
            NSLog(@"login fail: error = %@", error);
        }];
    }
    
    macOS/Windows
    C++V2NIMLoginOption option;
    loginService.login(
        "accountId",
        "token",
        option,
        []() {
            // login succeeded
        },
        [](V2NIMError error) {
            // login failed, handle error
        });
    
    Web/uni-app/小程序
    TypeScripttry {
      await nim1.V2NIMLoginService.login("ACCOUNT_ID", "TOKEN", {
        "forceMode": false
      })
    } catch (err) {
      // TODO failed, check code
      // console.log(err.code)
    }
    
    HarmonyOS
    TypeScripttry {
    await nim.loginService.login("ACCOUNT_ID", "TOKEN", {
        forceMode: false
    } as V2NIMLoginOption)
    } catch (err) {
    // TODO failed, check code
    // console.log(err.code)
    }
    
    Flutter
    Dartfinal loginResult = await NimCore.instance.loginService.login(
        "ACCOUNT_ID", "TOKEN", NIMLoginOption());
    

动态 Token 登录

调用 login 方法登录 IM,鉴权方式为动态 Token 鉴权。您需要将 authType 设置为 1,并设置获取动态 Token 回调 tokenProvider

调用完成后,NIM SDK 会自动连接网易云信服务端,传递用户信息,返回登录结果。登录过程中可主动取消登录。如果因为网络或其他原因导致网易云信服务端长时间未响应,用户也没有主动取消登录,NIM SDK 将在 45 秒后自动重新连接网易云信服务端,并返回错误码,错误码详情参考 错误码 连接错误章节。

  • 登录部分参数说明:

    参数名称 说明
    accountId IM 为用户分配的唯一登录账号。通过网易云信控制台获取或调用服务端 API 注册。获取方式请参考 获取动态 Token
    token 静态鉴权 Token,可不填。
    如果您的应用启用了聊天室功能,并且采用非独立模式&静态 Token 登录策略,那么该参数必须设置,后续非独立模式的聊天室静态登录时会使用该静态 Token。
    option 登录配置。动态 Token 登录可配置如下字段:
  • forceMode:是否强制登录
  • timeout:登录超时时间
  • retryCount:登录失败后重试次数
  • authType:鉴权方式,必须设置为 1
  • syncLevel:数据同步模式,分为完全同步和基础数据同步
  • tokenProvider:获取动态 Token 回调,如果使用动态 Token 鉴权方式该字段必填。动态 Token 基于 App Key、App Secret 和 accountId,通过约定算法在服务端生成。该回调在登录连接完成、登录鉴权校验前触发。若函数执行有异常或返回非预期内容(非法字符串),则登录中止并报错。
  • 如果设置了获取动态 Token 回调,但返回空值且未传入静态 Token,则返回 414 错误码,网易云信 IM 不做登录请求。
  • 若设置了获取动态 Token 回调且返回空值,但是已传入静态 Token,也会返回相关错误码。但 SDK 会持续与服务端进行重连,直到获取到动态 Token(不计入自动重连次数)。
  • 示例代码:

    Android
    JavaV2NIMLoginOption option = new V2NIMLoginOption();
    //set auth type
    option.setAuthType(V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN);
    //set auth token provider
    option.setTokenProvider(new V2NIMTokenProvider() {
        @Override
        public String getToken(String accountId) {
            return "return your token with accountId";
        }
    });
    NIMClient.getService(V2NIMLoginService.class).login("accountId",null,option,new V2NIMSuccessCallback<Void>() {
            @Override
            public void onSuccess(Void unused) {
                // TODO
            }
        },
        new V2NIMFailureCallback() {
            @Override
            public void onFailure(V2NIMError error) {
                int code = error.getCode();
                String desc = error.getDesc();
                // TODO
            }
        });
    
    iOS
    Objective-C@interface YourTokenProvider : NSObject <V2NIMTokenProvider>
    
    @end
    
    @implementation YourTokenProvider
    
    - (NSString *)getToken:(NSString *)accountId
    {
        return @"return your token with accountId";
    }
    
    @end
    
    - (void)loginWithDynamicToken
    {
        NSString *accountId = @"accountId";
        V2NIMLoginOption *option = [[V2NIMLoginOption alloc] init];
        option.authType = V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN; // setup type
        option.tokenProvider = [[YourTokenProvider alloc] init]; // setup provider
        [[NIMSDK sharedSDK].v2LoginService login:accountId token:nil
                option:option
                  success:^{
            NSLog(@"login succ");
        }
                  failure:^(V2NIMError * _Nonnull error) {
            NSLog(@"login fail: error = %@", error);
        }];
    }
    
    macOS/Windows
    C++auto& instance = V2NIMInstance::get();
    auto& loginService = instance.getLoginService();
    V2NIMLoginOption option;
    option.authType = V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN;
    option.tokenProvider = [](nstd::string accountId) {
        nstd::string token;
        // get token
        // ...
        return token;
    };
    loginService.login(
        "accountId",
        "",
        option,
        []() {
            // login succeeded
        },
        [](V2NIMError error) {
            // login failed, handle error
        });
    
    Web/uni-app/小程序
    TypeScripttry {
      await nim.V2NIMLoginService.login("ACCOUNT_ID", "", {
        "forceMode": false,
        "authType": 1, // V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN
        "tokenProvider": function(accountId) {
          return Promise.resolve('YOUR_DYNAMIC_TOKEN')
        }
      })
    } catch (err) {
      // TODO failed, check code
      // console.log(err.code)
    }
    
    HarmonyOS
    TypeScripttry {
    await nim.loginService.login("ACCOUNT_ID", "", {
        forceMode: false,
        authType: V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN, // 1, V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_DYNAMIC_TOKEN
        tokenProvider: ((accountId: string): Promise<string> | string => {
        return Promise.resolve('YOUR_DYNAMIC_TOKEN')
        }) as V2NIMTokenProvider
    } as V2NIMLoginOption)
    } catch (err) {
    // TODO failed, check code
    // console.log(err.code)
    }
    
    Flutter
    Dartvar options = NIMLoginOption();
    
    options.authType = NIMLoginAuthType.authTypeDynamicToken;
    
    NimCore.instance.loginService.loginExtensionProvider =
        (String accountId) async {
      return "return your token with accountId";
    };
    
    final loginResult = await NimCore.instance.loginService.login(
        accountEditingController.text, passwordEditingController.text, options);
    

通过第三方回调登录

如采用该登录策略,网易云信 IM 不做登录鉴权,鉴权工作需由指定的第三方服务器(可以是应用服务器)进行。

  1. 通过第三方回调登录 IM,首先需要 开通和配置第三方服务

  2. 如果您需要采用第三方服务器的动态登录扩展数据或动态 Token 进行鉴权,那么需要在调用 login 方法登录时将 authType 设置为 2,并设置获取动态登录扩展数据 loginExtensionProvider 回调和获取动态 Token 回调 tokenProvider,SDK 会在登录过程中获取第三方回调的动态扩展数据和动态 Token。

    调用完成后,NIM SDK 会自动连接网易云信服务端,传递用户信息,返回登录结果。登录过程中可主动取消登录。如果因为网络或其他原因导致网易云信服务端长时间未响应,用户也没有主动取消登录,NIM SDK 将在 45 秒后自动重新连接网易云信服务端,并返回 错误码

  • 登录部分参数说明:

    参数名称 说明
    accountId IM 为用户分配的唯一登录账号。通过网易云信控制台获取或调用服务端 API 注册。
    token 静态鉴权 Token,可不填。
    如果您的应用启用了聊天室功能,并且采用非独立模式&静态 Token 登录策略,那么该参数必须设置,后续非独立模式的聊天室静态登录时会使用该静态 Token。
    option 登录配置。动态 Token 登录可配置如下字段:
  • forceMode:是否强制登录
  • timeout:登录超时时间
  • retryCount:登录失败后重试次数
  • authType:鉴权方式,必须设置为 2
  • syncLevel:数据同步模式,分为完全同步和基础数据同步
  • loginExtensionProvider:获取用户登录业务扩展数据回调,如果使用第三方回调鉴权方式,该字段必填。该回调在登录连接完成、登录鉴权校验前触发。若函数执行有异常或返回非预期内容(非法字符串),则登录中止并报错
  • tokenProvider:获取动态 Token 回调,如果使用第三方回调鉴权方式,该字段用于第三方服务器的动态 Token 鉴权
  • 如果设置了获取动态登录扩展数据回调和获取动态 Token 回调,但都返回空值且未传入静态 Token,则返回 414 错误码,网易云信 IM 不做登录请求。
  • 若设置了获取动态登录扩展数据回调和获取动态 Token 回调且返回空值,但是已传入静态 Token,也会返回相关错误码。但 SDK 会持续与服务端进行重连,直到获取到动态登录扩展数据或动态 Token(不计入自动重连次数)。
  • 示例代码:

    以通过 第三方动态登录扩展数据 loginExtensionProvider 回调登录为例:

    Android
    JavaV2NIMLoginOption option = new V2NIMLoginOption();
    // set auth type
    option.setAuthType(V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY);
    // set auth token provider
    option.setLoginExtensionProvider(new V2NIMLoginExtensionProvider() {
        @Override
        public String getLoginExtension(String accountId) {
            return "return your login extension with accountId";
        }
    });
    NIMClient.getService(V2NIMLoginService.class).login("accountId", "token", option, new V2NIMSuccessCallback<Void>() {
        @Override
        public void onSuccess(Void unused) {
            // TODO
        }
    }, new V2NIMFailureCallback() {
        @Override
        public void onFailure(V2NIMError error) {
            int code = error.getCode();
            String desc = error.getDesc();
            // TODO
        }
    });
    
    iOS
    Objective-C@interface YourLoginExtensionProvider : NSObject <V2NIMLoginExtensionProvider>
    
    @end
    
    @implementation YourLoginExtensionProvider
    
    - (NSString *)getLoginExtension:(NSString *)accountId
    {
        return @"return your login extension with accountId";
    }
    
    @end
    
    - (void)loginWithThirdParty
    {
        NSString *accountId = @"accountId";
        NSString *token = @"token";
        V2NIMLoginOption *option = [[V2NIMLoginOption alloc] init];
        option.authType = V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY; // setup type
        option.loginExtensionProvider = [[YourLoginExtensionProvider alloc] init]; // setup provider
        [[NIMSDK sharedSDK].v2LoginService login:accountId token:token
                                          option:option
                                         success:^{
            NSLog(@"login succ");
        } failure:^(V2NIMError * _Nonnull error) {
            NSLog(@"login fail: error = %@", error);
        }];
    }
    
    macOS/Windows
    C++auto& instance = V2NIMInstance::get();
    auto& loginService = instance.getLoginService();
    V2NIMLoginOption option;
    option.authType = V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY;
    option.loginExtensionProvider = [](std::string accountId) {
        std::string loginExtension;
        // get login extension
        // ...
        return loginExtension;
    };
    loginService.login(
        "accountId",
        "",
        option,
        []() {
            // login succeeded
        },
        [](V2NIMError error) {
            // login failed, handle error
        });
    
    Web/uni-app/小程序
    TypeScripttry {
      await nim.V2NIMLoginService.login("ACCOUNT_ID", "", {
        "forceMode": false,
        "authType": 2, // V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY
        "loginExtensionProvider": function(accountId) {
          return Promise.resolve('YOUR_LOGIN_EXTENSION')
        }
      })
    } catch (err) {
      // TODO failed, check code
      // console.log(err.code)
    }
    
    HarmonyOS
    TypeScripttry {
    await nim.loginService.login("ACCOUNT_ID", "", {
        forceMode: false,
        authType: V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY, // 2, V2NIMLoginAuthType.V2NIM_LOGIN_AUTH_TYPE_THIRD_PARTY
        loginExtensionProvider: ((accountId: string): Promise<string> | string => {
        return Promise.resolve('YOUR_LOGIN_EXTENSION')
        }) as V2NIMLoginExtensionProvider
    } as V2NIMLoginOption)
    // success
    } catch (err) {
    // TODO failed, check code
    // console.log(err.code)
    }
    
    Flutter
    Dartvar options = NIMLoginOption();
    
    options.authType = NIMLoginAuthType.authTypeThirdParty;
    
    NimCore.instance.loginService.loginExtensionProvider =
        (String accountId) async {
      return "return your login extension with accountId";
    };
    
    final loginResult = await NimCore.instance.loginService.login(
        accountEditingController.text, passwordEditingController.text, options);
    
    • 通过第三方回调登录,如果设置了获取第三方动态 Token 和登录扩展数据回调,但都返回空值且未传入静态 Token 和登录扩展数据(可能第三方服务器设置了动态时间),则直接返回 414 错误码,网易云信 IM 内部不做登录请求。
    • 若设置了获取第三方动态 Token 和登录扩展数据回调且返回空值,但是已传入静态 Token,也会返回相关错误码,但会持续与服务端进行重连,直到动态 Token 传入(不计入自动重连次数)。
  1. 在服务端发起 登录相关回调 请求,由第三方服务器进行鉴权并判定 IM 登录事件是否放行通过。

    若不通过,网易云信服务端将返回 302 错误码。

第五步:(可选)查询登录状态

通过 getLoginStatus 方法主动查询当前账号是否处于登录状态。

返回当前用户的登录的状态枚举值说明,请参考 IM 登录最佳实践的 获取登录状态

Android
JavaV2NIMLoginStatus status = NIMClient.getService(V2NIMLoginService.class).getLoginStatus();
iOS
Objective-C- (void)printLoginStatus:(V2NIMLoginStatus)status
{
    switch (status) {
        case V2NIM_LOGIN_STATUS_LOGOUT:
            NSLog(@"login status = logout");
            break;
        case V2NIM_LOGIN_STATUS_LOGINING:
            NSLog(@"login status = logining");
            break;
        case V2NIM_LOGIN_STATUS_LOGINED:
            NSLog(@"login status = logined");
            break;
        default:
            NSLog(@"login status = %ld", status);
    }
}

V2NIMLoginStatus status = [[[NIMSDK sharedSDK] v2LoginService] getLoginStatus];
macOS/Windows
C++auto loginStatus = loginService.getLoginStatus();
Web/uni-app/小程序
TypeScriptconst loginStatus = nim.V2NIMLoginService.getLoginStatus()
HarmonyOS
TypeScriptconst loginStatus = nim.loginService.getLoginStatus()
Flutter
Dartfinal loginStatus = await NimCore.instance.loginService.getLoginStatus();

其他操作

登出 IM

一般情况下,如果您的应用生命周期跟 NIM SDK 生命周期一致,用户在退出应用前可以不登出,直接退出即可。

但某些特殊场景,例如用户仅在进入特定界面后才调用 NIM SDK 的能力,退出界面后不再调用,此时需要调用 NIM SDK 的登出接口注销 IM 登录。登出后,用户将不再接收 IM 的消息。

用户在登出应用/注销自己的账号时需要调用 logout 方法登出 IM,该方法没有回调。

示例代码

Android
Java// 请勿在 Activity 的 `onDestroy` 中调用 `logout` 方法
NIMClient.getService(V2NIMLoginService.class).logout(new V2NIMSuccessCallback(){
     @Override
     public void onSuccess(){
         // TODO
     }
}, new V2NIMFailueCallback<V2NIMError>(){
     @Override
     public void onFailure(V2NIMError error){
         int code = error.code;
         String desc = error.desc;
         // TODO
     }
});
iOS
Objective-C- (void)logout
{
    [[NIMSDK sharedSDK].v2LoginService logout:^{
        NSLog(@"logout succ");
    } failure:^(V2NIMError * _Nonnull error) {
        NSLog(@"logout fail: error = %@", error);
    }];
}
macOS/Windows
C++loginService.logout(
    []() {
        // logout succeeded
    },
    [](V2NIMError error) {
        // logout failed, handle error
    });
Web/uni-app/小程序
TypeScripttry {
  await nim.V2NIMLoginService.logout()
} catch (err) {
  // TODO failed, check code
  // console.log(err.code)
}
HarmonyOS
TypeScripttry {
  await nim.loginService.logout()
} catch (err) {
  // TODO failed, check code
  // console.log(err.code)
}
Flutter
Dartfinal logoutResult = await NimCore.instance.loginService.logout();

请勿频繁调用登录、登出方法,其间隔至少要大于 3 秒。

断线重连

SDK 提供了自动重连机制,当网络问题导致连接断开或超时,SDK 会自动重新建立与网易云信服务端的连接并重新登录,您 无需主动重复登录。您可以调用 addLoginDetailListener 方法注册登录连接状态监听器,通过 onConnectStatus 回调监听重连后的登录状态变更。

查询登录信息

您可以调用 getLoginClientsgetCurrentLoginClient 方法查询多端登录的列表信息和当前登录终端的信息,包括终端类型、IP、登录时间等。

相关文档

涉及接口

Android/iOS/macOS/Windows
API 说明
addLoginListener 注册登录状态监听器
removeLoginListener 取消注册登录状态监听器
addLoginDetailListener 注册登录连接状态监听器
removeLoginDetailListener 取消注册登录连接状态监听器
login 登录 IM
logout 登出 IM
getLoginStatus 获取当前登录状态
tokenProvider 获取动态登录 token
loginExtensionProvider 获取登录扩展信息 loginExtension
getLoginClients 获取多端登录列表信息
getCurrentLoginClient 获取当前登录终端的信息
Web/uni-app/小程序/HarmonyOS
API 说明
on("EventName") 注册登录相关监听器
off("EventName") 取消注册登录相关监听器
login 登录 IM
logout 登出 IM
getLoginStatus 获取当前登录状态
tokenProvider 获取动态登录 token
loginExtensionProvider 获取登录扩展信息 loginExtension
getLoginClients 获取多端登录列表信息
getCurrentLoginClient 获取当前登录终端的信息
Flutter
API 说明
add 注册登录相关监听器
cancel 取消注册登录相关监听器
login 登录 IM
logout 登出 IM
getLoginStatus 获取当前登录状态
tokenProvider 获取动态登录 token
loginExtensionProvider 获取登录扩展信息 loginExtension
getLoginClients 获取多端登录列表信息
getCurrentLoginClient 暂不支持

常见问题

如何根据产品形态选择 IM 登录策略?

接入网易云信 IM 服务的产品大致分为两种形态:

  • IM 产品:通讯作为其核心模块。典型例子如微信、易信、网络直播相关应用。
  • 非 IM 产品:通讯只是其附带模块,典型例子如各种有私信模块的应用。

对于 IM 产品,由于通讯能力是核心能力,如果网易云信无法登录成功则整个应用将无法正常表现,所以推荐在执行业务逻辑前,首先完成应用服务端和网易云信服务端的登录。只有应用服务端和网易云信服务端都登录成功才认为整个登录完成。而对于非 IM 产品而言,通讯能力是可以在登录应用服务端成功后延迟加载,登录成功拿到服务端下发的网易云信 IM 账号和 token 后进行自动登录即可。

如何处理登录请求被拒绝问题?

若您开启了应用标识安全验证,需要在将列表中写入允许的客户端应用标识。当请求登录的客户端应用标识不在列表中时,登录请求将被拒绝。

网易云信控制台 首页 应用管理 选择应用进入 应用配置 页面,顶部选择 标识管理 页签,添加对应的客户端应用标识。

应用标识管理.png
此文档是否对你有帮助?
有帮助
去反馈
  • 支持平台
  • 登录策略
  • 登录流程
  • 前提条件
  • 第一步:配置 IM 登录策略
  • 第二步:准备 Token
  • 获取静态 Token
  • 获取动态 Token
  • 获取动态登录扩展数据
  • 第三步:注册登录相关事件监听
  • 1. 注册登录状态相关监听
  • 2. 注册登录连接状态监听
  • 第四步:登录 IM
  • 静态 Token 登录
  • 动态 Token 登录
  • 通过第三方回调登录
  • 第五步:(可选)查询登录状态
  • 其他操作
  • 登出 IM
  • 断线重连
  • 查询登录信息
  • 相关文档
  • 涉及接口
  • 常见问题
  • 如何根据产品形态选择 IM 登录策略?
  • 如何处理登录请求被拒绝问题?