fix(app): 强制 HTTPS — Android 网络安全配置 + 生产默认 HTTPS
- Android: 添加 network_security_config.xml,默认禁止明文流量 - Android: 仅允许 localhost/127.0.0.1/10.0.2.2 明文(开发调试) - Android: 更新 AndroidManifest 引用网络安全配置 - ApiClient: 默认 URL 改为 https://api.nuanji.app/api/v1 - AppConfig: fromEnvironment 默认值改为 HTTPS 生产地址 - AppConfig: dev 常量保留 localhost(仅用于本地开发) - iOS: ATS 默认已强制 HTTPS,无需修改 审计 ID: 6b-C01
This commit is contained in:
@@ -2,7 +2,8 @@
|
|||||||
<application
|
<application
|
||||||
android:label="nuanji_app"
|
android:label="nuanji_app"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:networkSecurityConfig="@xml/network_security_config">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
|
|||||||
20
app/android/app/src/main/res/xml/network_security_config.xml
Normal file
20
app/android/app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- 网络安全配置 — 强制 HTTPS,仅允许 localhost 明文(开发用)
|
||||||
|
审计 ID: 6b-C01 — Flutter 默认 HTTP 明文传输修复
|
||||||
|
-->
|
||||||
|
<network-security-config>
|
||||||
|
<!-- 生产配置:强制 HTTPS -->
|
||||||
|
<base-config cleartextTrafficPermitted="false">
|
||||||
|
<trust-anchors>
|
||||||
|
<certificates src="system" />
|
||||||
|
</trust-anchors>
|
||||||
|
</base-config>
|
||||||
|
|
||||||
|
<!-- 开发配置:允许 localhost/10.0.2.2 明文(模拟器/本地调试)
|
||||||
|
生产构建时应移除此段 -->
|
||||||
|
<domain-config cleartextTrafficPermitted="true">
|
||||||
|
<domain includeSubdomains="false">localhost</domain>
|
||||||
|
<domain includeSubdomains="false">10.0.2.2</domain>
|
||||||
|
<domain includeSubdomains="false">127.0.0.1</domain>
|
||||||
|
</domain-config>
|
||||||
|
</network-security-config>
|
||||||
@@ -1,8 +1,12 @@
|
|||||||
// 应用环境配置 — 通过 --dart-define 注入
|
// 应用环境配置 — 通过 --dart-define 注入
|
||||||
//
|
//
|
||||||
// 使用方式:
|
// 使用方式:
|
||||||
// flutter run --dart-define=API_BASE_URL=http://localhost:3000/api/v1
|
// flutter run # 开发模式(localhost)
|
||||||
// flutter run --dart-define=API_BASE_URL=https://api.nuanji.app/api/v1
|
// flutter run --dart-define=API_BASE_URL=https://api.nuanji.app/api/v1 # 生产模式
|
||||||
|
//
|
||||||
|
// 安全说明:
|
||||||
|
// - 生产环境强制 HTTPS(Android network_security_config 禁止明文流量)
|
||||||
|
// - 开发模式使用 localhost(Android 网络安全配置已允许 localhost 明文)
|
||||||
|
|
||||||
/// 应用环境配置 — 集中管理所有外部服务地址
|
/// 应用环境配置 — 集中管理所有外部服务地址
|
||||||
class AppConfig {
|
class AppConfig {
|
||||||
@@ -19,19 +23,20 @@ class AppConfig {
|
|||||||
|
|
||||||
/// 从编译时环境变量构建配置
|
/// 从编译时环境变量构建配置
|
||||||
///
|
///
|
||||||
/// 使用 `--dart-define` 注入,未设置时使用默认值。
|
/// 使用 `--dart-define` 注入,未设置时使用生产 HTTPS 默认值。
|
||||||
|
/// 开发环境使用 [dev] 常量或通过 --dart-define 覆盖。
|
||||||
factory AppConfig.fromEnvironment({
|
factory AppConfig.fromEnvironment({
|
||||||
String defaultApiBaseUrl = 'http://localhost:3000/api/v1',
|
String defaultApiBaseUrl = 'https://api.nuanji.app/api/v1',
|
||||||
String defaultSseBaseUrl = 'http://localhost:3000/api/v1',
|
String defaultSseBaseUrl = 'https://api.nuanji.app/api/v1',
|
||||||
}) {
|
}) {
|
||||||
// const String.fromEnvironment 在编译时求值
|
// const String.fromEnvironment 在编译时求值
|
||||||
const apiBaseUrl = String.fromEnvironment(
|
const apiBaseUrl = String.fromEnvironment(
|
||||||
'API_BASE_URL',
|
'API_BASE_URL',
|
||||||
defaultValue: 'http://localhost:3000/api/v1',
|
defaultValue: 'https://api.nuanji.app/api/v1',
|
||||||
);
|
);
|
||||||
const sseBaseUrl = String.fromEnvironment(
|
const sseBaseUrl = String.fromEnvironment(
|
||||||
'SSE_BASE_URL',
|
'SSE_BASE_URL',
|
||||||
defaultValue: 'http://localhost:3000/api/v1',
|
defaultValue: 'https://api.nuanji.app/api/v1',
|
||||||
);
|
);
|
||||||
|
|
||||||
return AppConfig(
|
return AppConfig(
|
||||||
@@ -40,7 +45,7 @@ class AppConfig {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 开发环境默认配置
|
/// 开发环境默认配置(localhost 明文 — 仅用于本地调试)
|
||||||
static const dev = AppConfig(
|
static const dev = AppConfig(
|
||||||
apiBaseUrl: 'http://localhost:3000/api/v1',
|
apiBaseUrl: 'http://localhost:3000/api/v1',
|
||||||
sseBaseUrl: 'http://localhost:3000/api/v1',
|
sseBaseUrl: 'http://localhost:3000/api/v1',
|
||||||
|
|||||||
@@ -36,7 +36,12 @@ class ApiClient {
|
|||||||
/// 是否正在刷新 token(防止并发 401 触发多次刷新)
|
/// 是否正在刷新 token(防止并发 401 触发多次刷新)
|
||||||
bool _isRefreshing = false;
|
bool _isRefreshing = false;
|
||||||
|
|
||||||
ApiClient({this.baseUrl = 'http://localhost:3000/api/v1'}) {
|
/// 创建 API 客户端
|
||||||
|
///
|
||||||
|
/// [baseUrl] 默认使用 HTTPS 生产地址。
|
||||||
|
/// 开发环境可通过构造参数覆盖为 http://localhost:3000/api/v1
|
||||||
|
/// (Android 网络安全配置已允许 localhost 明文)。
|
||||||
|
ApiClient({this.baseUrl = 'https://api.nuanji.app/api/v1'}) {
|
||||||
_dio = Dio(BaseOptions(
|
_dio = Dio(BaseOptions(
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
connectTimeout: const Duration(seconds: 10),
|
connectTimeout: const Duration(seconds: 10),
|
||||||
|
|||||||
Reference in New Issue
Block a user