Files
zhini_im/(红头)实名认证功能及使用.txt
rw0067680 c01808ac21 first commit
Change-Id: Ib7c2ab10a2562044fcaf9879388a6cbc1db6ac61
2025-12-23 10:00:49 +08:00

663 lines
17 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 实名认证功能及使用文档
## 一、功能概述
实名认证功能用于验证用户身份,确保用户信息的真实性和安全性。该功能包括:
- 实名认证页面(输入姓名和身份证号)
- 认证结果展示页面
- 认证状态检查(在会话列表、更多操作等场景)
- 认证状态存储SharedPreferences + SDK UserInfo.extra字段
- 认证引导弹窗
---
## 二、相关文件
### 2.1 核心文件
#### Activity类
- `app/src/main/java/com/xunpaisoft/social/im/setting/RealNameAuthActivity.java`
- 实名认证输入页面,用户输入姓名和身份证号进行认证
- `app/src/main/java/com/xunpaisoft/social/im/setting/RealNameAuthResultActivity.java`
- 实名认证结果展示页面,显示认证成功信息和脱敏后的姓名、身份证号
#### 工具类
- `app/src/main/java/com/xunpaisoft/social/im/utils/UserInfoExtraHelper.java`
- UserInfo扩展字段工具类用于在SDK的UserInfo.extra字段中存储和读取realAuth
- `app/src/main/java/com/xunpaisoft/social/im/dialog/RealNameAuthDialog.java`
- 实名认证引导弹窗工具类,可在应用任何地方调用显示引导弹窗
#### Fragment类
- `app/src/main/java/com/xunpaisoft/social/im/main/MeFragment.java`
- "我的"页面包含实名认证入口并在获取用户信息时同步认证状态到SDK
- `uikit/src/main/java/cn/wildfire/chat/kit/conversationlist/ConversationListFragment.java`
- 会话列表页面,点击会话时检查实名认证状态
#### 数据模型
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/RealNameAuthResult.java`
- 实名认证接口返回结果数据模型
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserRealnameInfoResult.java`
- 获取用户实名认证信息接口返回结果数据模型
- `uikit/src/main/java/cn/wildfire/chat/kit/net/model/GetUserInfoResult.java`
- 获取用户信息接口返回结果数据模型包含realauth字段
#### SDK模型
- `client/src/main/java/cn/wildfirechat/model/ModifyMyInfoType.java`
- 用户信息修改类型枚举包含Modify_Extra(8)用于扩展字段
- `client/src/main/java/cn/wildfirechat/model/ModifyMyInfoEntry.java`
- 用户信息修改条目用于通过SDK更新用户信息
### 2.2 布局文件
- `app/src/main/res/layout/activity_real_name_auth.xml` - 实名认证输入页面布局
- `app/src/main/res/layout/activity_real_name_auth_result.xml` - 认证结果页面布局
- `app/src/main/res/layout/main_fragment_me.xml` - "我的"页面布局(包含实名认证入口)
### 2.3 网络接口
- `uikit/src/main/java/cn/wildfire/chat/kit/net/AppService.java`
- `realnameAuth()` - 提交实名认证
- `getUserRealnameInfo()` - 获取用户实名认证信息
---
## 三、数据存储
### 3.1 SharedPreferences存储
**存储位置:** `social_app` SharedPreferences文件
**Key** `realAuth`(定义在 `Constants.REAL_AUTH`
**值:**
- `"1"` - 已认证成功
- `"0"` - 未认证(默认值)
**使用工具类:** `SharedPreferencesUtils`
```java
// 保存
SharedPreferencesUtils.putString(Constants.REAL_AUTH, "1");
// 读取
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
boolean isAuth = "1".equals(realAuth);
```
### 3.2 SDK UserInfo.extra字段存储
**存储位置:** 野火SDK的 `UserInfo.extra` 字段
**数据格式:** JSON字符串
**示例:**
```json
{
"realAuth": "1"
}
```
**使用工具类:** `UserInfoExtraHelper`
```java
// 更新到SDK
UserInfoExtraHelper.setRealAuthToSDK(callback);
// 从UserInfo读取
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
```
### 3.3 存储时机
1. **认证成功时:**
- 保存到 SharedPreferences
- 更新到 SDK UserInfo.extra字段
2. **获取用户信息时:**
- 从服务器获取的realauth保存到 SharedPreferences
- 如果已认证但SDK中未同步自动同步到SDK
---
## 四、API接口
### 4.1 提交实名认证
**接口:** `POST /api/user/realnameAuth`
**请求参数:**
```json
{
"username": "张三",
"idcard": "110101199001011234"
}
```
**响应示例:**
```json
{
"error_code": 0,
"reason": "",
"result": {
"realname": "张*",
"idcard": "110101********1234",
"isok": 1,
"IdCardInfor": {
"name": "张三",
"idcard": "110101199001011234"
}
},
"sn": "xxx"
}
```
**调用方式:**
```java
AppService.Instance().realnameAuth(name, idNumber, new SimpleCallback<RealNameAuthResult>() {
@Override
public void onUiSuccess(RealNameAuthResult result) {
if (result != null && result.isSuccess()) {
// 认证成功处理
}
}
@Override
public void onUiFailure(int code, String msg) {
// 认证失败处理
}
});
```
### 4.2 获取用户实名认证信息
**接口:** `POST /api/user/getUserRealnameInfo`
**响应示例:**
```json
{
"id": 123,
"user_id": "1845",
"name": "张*",
"idcard": "110101********1234",
"phone": "",
"address": "",
"birthday": "",
"sex": "",
"status": 1,
"createtime": "2025-01-01 10:00:00",
"updatetime": "2025-01-01 10:00:00",
"status_text": "已认证"
}
```
**调用方式:**
```java
AppService.Instance().getUserRealnameInfo(new SimpleCallback<GetUserRealnameInfoResult>() {
@Override
public void onUiSuccess(GetUserRealnameInfoResult result) {
if (result != null && result.isSuccess()) {
GetUserRealnameInfoResult data = result.getData();
String name = data.getName();
String idcard = data.getIdcard();
}
}
});
```
### 4.3 获取用户信息包含realauth字段
**接口:** `POST /api/user/getUserInfo`
**响应中的realauth字段**
- `"1"` - 已认证成功
- `"0"` - 未认证
---
## 五、功能使用
### 5.1 实名认证入口
**位置:** "我的"页面MeFragment
**布局:** `main_fragment_me.xml`
```xml
<cn.wildfire.chat.kit.widget.OptionItemView
android:id="@+id/realNameAuthOptionItemView"
style="@style/OptionItem"
app:show_divider="true"
app:start_src="@mipmap/icon_my_shezhi"
app:title="实名认证" />
```
**点击逻辑:** `MeFragment.realNameAuth()`
- 如果已认证:跳转到 `RealNameAuthResultActivity`(认证结果页面)
- 如果未认证:跳转到 `RealNameAuthActivity`(认证输入页面)
### 5.2 实名认证流程
1. **用户点击"实名认证"入口**
- 检查认证状态(`Constants.isRealAuth()`
- 根据状态跳转到相应页面
2. **输入认证信息RealNameAuthActivity**
- 输入真实姓名
- 选择证件类型(默认:居民身份证)
- 输入证件号码
- 点击"提交"按钮
3. **提交认证submitToServer**
- 调用 `AppService.realnameAuth()` 接口
- 认证成功:
- 保存到 SharedPreferences`Constants.REAL_AUTH = "1"`
- 更新到 SDK UserInfo.extra字段`UserInfoExtraHelper.setRealAuthToSDK()`
- 跳转到认证结果页面
4. **显示认证结果RealNameAuthResultActivity**
- 如果Intent中有数据直接显示
- 如果没有,调用 `AppService.getUserRealnameInfo()` 从服务器获取
- 显示脱敏后的姓名和身份证号
### 5.3 认证状态检查
#### 5.3.1 在会话列表中检查
**位置:** `ConversationListFragment.handleConversationClick()`
**检查逻辑:**
1. 优先从 `UserInfo.extra` 字段读取
2. 如果extra中没有从 SharedPreferences 读取
3. 如果未认证,显示引导弹窗
4. 如果已认证,正常跳转到会话页面
**代码示例:**
```java
private void handleConversationClick(ConversationInfo conversationInfo) {
String userId = ChatManager.Instance().getUserId();
boolean isRealAuth = false;
// 1. 从UserInfo.extra读取
if (userId != null) {
UserInfo currentUserInfo = ChatManager.Instance().getUserInfo(userId, false);
if (currentUserInfo != null && currentUserInfo.extra != null) {
String realAuth = getRealAuthFromExtra(currentUserInfo.extra);
isRealAuth = "1".equals(realAuth);
}
}
// 2. 从SharedPreferences读取兼容
if (!isRealAuth) {
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
isRealAuth = "1".equals(realAuth);
}
// 3. 根据结果处理
if (!isRealAuth) {
showRealNameAuthDialog(); // 显示引导弹窗
return;
}
// 已认证,正常跳转
Intent intent = new Intent(getActivity(), ConversationActivity.class);
intent.putExtra("conversation", conversationInfo.conversation);
startActivity(intent);
}
```
#### 5.3.2 在更多操作中检查
**位置:** `MainActivity.showMoreActionMenu()`
**检查逻辑:**
```java
private void showMoreActionMenu() {
// 检查是否已实名认证
if (!Constants.isRealAuth()) {
RealNameAuthDialog.show(this);
return;
}
// 已认证,显示更多操作菜单
// ...
}
```
### 5.4 认证引导弹窗
**工具类:** `RealNameAuthDialog`
**使用方式:**
1. **简单调用(默认行为)**
```java
// 在任何Activity中调用
RealNameAuthDialog.show(this);
```
2. **带回调的调用(自定义行为)**
```java
RealNameAuthDialog.show(this, new RealNameAuthDialog.OnRealNameAuthDialogListener() {
@Override
public void onConfirm() {
// 自定义确认行为
Intent intent = new Intent(this, RealNameAuthActivity.class);
startActivity(intent);
}
@Override
public void onCancel() {
// 自定义取消行为
}
});
```
**弹窗内容:**
- 标题:"温馨提示"
- 内容:"为保障用户信息和安全,需要进行实名认证后才能开启相关服务"
- 按钮:
- "取消"(关闭弹窗)
- "去认证"(跳转到实名认证页面)
---
## 六、工具类使用
### 6.1 UserInfoExtraHelper
#### 6.1.1 读取认证状态
```java
// 从UserInfo读取
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
String realAuth = UserInfoExtraHelper.getRealAuth(userInfo);
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
```
#### 6.1.2 更新认证状态到SDK
```java
// 设置为已认证
UserInfoExtraHelper.setRealAuthToSDK(new GeneralCallback() {
@Override
public void onSuccess() {
Log.d("Tag", "更新成功");
}
@Override
public void onFail(int errorCode) {
Log.e("Tag", "更新失败: " + errorCode);
}
});
// 设置为未认证
UserInfoExtraHelper.clearRealAuthFromSDK(callback);
// 自定义值
UserInfoExtraHelper.updateRealAuthToSDK("1", callback);
```
#### 6.1.3 构建extra JSON字符串
```java
String currentExtra = userInfo.extra; // 可能为null
String newExtra = UserInfoExtraHelper.buildExtraWithRealAuth(currentExtra, "1");
// 结果: {"realAuth":"1"}
```
### 6.2 Constants工具方法
```java
// 获取认证状态字符串
String realAuth = Constants.getRealAuth(); // 返回 "1" 或 "0"
// 判断是否已认证
boolean isAuth = Constants.isRealAuth(); // 返回 true 或 false
```
---
## 七、SDK扩展字段使用
### 7.1 Modify_Extra字段说明
`ModifyMyInfoType.Modify_Extra` 是野火SDK提供的扩展字段类型用于在 `UserInfo.extra` 字段中存储自定义JSON数据。
**使用步骤:**
1. **构建JSON字符串**
```java
JSONObject jsonObject = new JSONObject();
jsonObject.put("realAuth", "1");
String extraJson = jsonObject.toString();
```
2. **创建ModifyMyInfoEntry**
```java
ModifyMyInfoEntry entry = new ModifyMyInfoEntry(
ModifyMyInfoType.Modify_Extra,
extraJson
);
```
3. **调用SDK更新**
```java
List<ModifyMyInfoEntry> entries = new ArrayList<>();
entries.add(entry);
ChatManager.Instance().modifyMyInfo(entries, callback);
```
### 7.2 读取extra字段
```java
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
if (userInfo != null && userInfo.extra != null) {
try {
JSONObject jsonObject = new JSONObject(userInfo.extra);
String realAuth = jsonObject.optString("realAuth", "0");
} catch (JSONException e) {
e.printStackTrace();
}
}
```
---
## 八、同步机制
### 8.1 认证成功时同步
**位置:** `RealNameAuthActivity.submitToServer()`
认证成功后:
1. 保存到 SharedPreferences
2. 调用 `UserInfoExtraHelper.setRealAuthToSDK()` 更新到SDK
### 8.2 获取用户信息时同步
**位置:** `MeFragment.getOtherUserInfo()`
当从服务器获取到 `realauth = "1"` 时:
1. 保存到 SharedPreferences
2. 检查SDK的 `UserInfo.extra` 字段
3. 如果extra中没有 `realAuth` 或值不是 "1",自动同步更新
**同步逻辑:**
```java
if ("1".equals(data.getRealauth())) {
// 检查SDK中是否已有realAuth
UserInfo currentUserInfo = ChatManager.Instance().getUserInfo(userId, false);
String currentExtra = currentUserInfo != null ? currentUserInfo.extra : null;
boolean needSync = true;
if (currentExtra != null && !currentExtra.isEmpty()) {
JSONObject jsonObject = new JSONObject(currentExtra);
String existingRealAuth = jsonObject.optString("realAuth", "0");
if ("1".equals(existingRealAuth)) {
needSync = false; // 已经同步过了
}
}
if (needSync) {
UserInfoExtraHelper.setRealAuthToSDK(callback);
}
}
```
---
## 九、调试日志
### 9.1 日志标签
- `ConversationListFragment` - 会话列表认证检查日志
- `UserInfoExtraHelper` - SDK更新日志
- `MeFragment` - 同步检测日志
- `RealNameAuth` - 认证流程日志
### 9.2 关键日志点
1. **认证状态检查**
```
D/ConversationListFragment: === 开始检查实名认证状态 ===
D/ConversationListFragment: 当前用户ID: 1845
D/ConversationListFragment: UserInfo.extra 值: {"realAuth":"1"}
D/ConversationListFragment: 从UserInfo.extra解析的realAuth: 1
D/ConversationListFragment: ✓ 从UserInfo.extra读取到已认证状态
```
2. **SDK更新**
```
D/UserInfoExtraHelper: === 开始更新realAuth到SDK ===
D/UserInfoExtraHelper: 要设置的realAuth值: 1
D/UserInfoExtraHelper: 当前UserInfo.extra: null
D/UserInfoExtraHelper: 构建后的newExtra: {"realAuth":"1"}
D/UserInfoExtraHelper: ✓ 成功更新realAuth到SDK的UserInfo.extra
```
3. **同步检测**
```
D/MeFragment: 检测到已认证但SDK中extra字段未同步开始同步...
D/MeFragment: ✓ 成功同步realAuth到SDK的UserInfo.extra
```
---
## 十、注意事项
### 10.1 数据一致性
- SharedPreferences 和 SDK UserInfo.extra 字段都存储认证状态
- 优先从 SDK 的 extra 字段读取(更可靠)
- SharedPreferences 作为兼容和备用方案
### 10.2 更新extra字段时
- 必须保留现有数据,只更新 `realAuth` 字段
- 使用 `UserInfoExtraHelper.buildExtraWithRealAuth()` 方法确保数据不丢失
### 10.3 错误处理
- SDK更新失败不影响 SharedPreferences 的保存
- 即使SDK更新失败认证状态仍可通过 SharedPreferences 读取
### 10.4 性能考虑
- 同步操作是异步的不会阻塞UI
- 在获取用户信息时进行同步,避免频繁调用
---
## 十一、常见问题
### Q1: UserInfo.extra为空怎么办
**A:**
1. 检查是否调用了 `UserInfoExtraHelper.setRealAuthToSDK()`
2. 检查SDK更新是否成功查看日志
3. 如果之前已认证,登录时会自动同步
### Q2: 如何手动同步认证状态到SDK
**A:**
```java
// 如果SharedPreferences中有认证状态但SDK中没有
if (Constants.isRealAuth()) {
UserInfoExtraHelper.setRealAuthToSDK(new GeneralCallback() {
@Override
public void onSuccess() {
// 同步成功
}
@Override
public void onFail(int errorCode) {
// 同步失败
}
});
}
```
### Q3: 如何判断用户是否已认证?
**A:**
```java
// 方式1使用Constants工具方法推荐
boolean isAuth = Constants.isRealAuth();
// 方式2从UserInfo.extra读取
UserInfo userInfo = ChatManager.Instance().getUserInfo(userId, false);
boolean isAuth = UserInfoExtraHelper.isRealAuth(userInfo);
// 方式3从SharedPreferences读取
String realAuth = SharedPreferencesUtils.getString(Constants.REAL_AUTH, "0");
boolean isAuth = "1".equals(realAuth);
```
### Q4: 认证状态在哪里检查?
**A:**
- 会话列表点击时:`ConversationListFragment.handleConversationClick()`
- 更多操作点击时:`MainActivity.showMoreActionMenu()`
- 实名认证入口点击时:`MeFragment.realNameAuth()`
---
## 十二、版本历史
- **v1.0** - 初始版本
- 实现基本的实名认证功能
- 支持SharedPreferences存储
- 支持SDK UserInfo.extra字段存储
- 实现认证状态检查和引导弹窗
- 实现自动同步机制
---
## 十三、相关常量
**定义位置:** `uikit/src/main/java/cn/wildfire/chat/kit/net/Constants.java`
```java
public static final String REAL_AUTH = "realAuth";
public static String getRealAuth() {
return SharedPreferencesUtils.getString(REAL_AUTH, "0");
}
public static boolean isRealAuth() {
return "1".equals(getRealAuth());
}
```
---
## 十四、总结
实名认证功能通过以下方式实现:
1. **数据存储:** SharedPreferences + SDK UserInfo.extra字段双重存储
2. **状态检查:** 优先从SDK读取兼容SharedPreferences
3. **自动同步:** 获取用户信息时自动同步到SDK
4. **引导机制:** 未认证时显示引导弹窗
5. **工具类封装:** 提供便捷的读写方法
该设计确保了数据的一致性和可靠性,同时提供了良好的用户体验。