Files
zhini_im/(红头)实名认证功能及使用.txt

663 lines
17 KiB
Plaintext
Raw Normal View History

# 实名认证功能及使用文档
## 一、功能概述
实名认证功能用于验证用户身份,确保用户信息的真实性和安全性。该功能包括:
- 实名认证页面(输入姓名和身份证号)
- 认证结果展示页面
- 认证状态检查(在会话列表、更多操作等场景)
- 认证状态存储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. **工具类封装:** 提供便捷的读写方法
该设计确保了数据的一致性和可靠性,同时提供了良好的用户体验。