上一篇
安卓开发之网络验证
- 行业动态
- 2025-04-22
- 4
网络请求基础
网络权限配置
在 AndroidManifest.xml
中声明网络权限:
<uses-permission android:name="android.permission.INTERNET" />
常用网络库对比
库名 | 特点 | 适用场景 |
---|---|---|
HttpURLConnection | Android 内置,轻量级,需手动处理线程和数据解析 | 简单请求,学习原理 |
OkHttp | 高效、支持缓存/拦截器、自动压缩 | 复杂网络请求,主流选择 |
Retrofit | 基于 OkHttp,通过注解生成 API 接口,支持 RxJava/Coroutines | RESTful API 开发 |
Volley | Google 开源,适合短时间、小数据量请求,内置 ImageLoader | 列表加载、图片请求 |
基础请求示例(OkHttp)
OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url("https://api.example.com/login") .post(RequestBody.create(JSON, "{"username":"test"}")) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 处理失败 } @Override public void onResponse(Call call, Response response) throws IOException { // 处理成功(UI 线程需切换) } });
网络验证流程
验证类型与场景
验证类型 | 说明 | 典型场景 |
---|---|---|
Token 验证 | 服务器返回令牌,后续请求携带该令牌 | 登录后保持会话 |
签名验证 | 客户端签名参数防止改动 | 敏感操作(如支付) |
时间戳验证 | 请求携带时间戳,服务器校验时效性 | 防止重放攻击 |
设备指纹验证 | 采集设备信息(如 IMEI)生成唯一标识 | 多设备登录限制 |
Token 验证流程
登录获取 Token
- 客户端发送账号密码 → 服务器验证 → 返回
access_token
和refresh_token
- 示例:
{"access_token":"abc123","expires_in":3600}
- 客户端发送账号密码 → 服务器验证 → 返回
存储 Token
- 推荐使用
SharedPreferences
或 EncryptedSharedPreferences(存储时加密) - 避免存入
File
或SQLite
(易被逆向破解)
- 推荐使用
请求携带 Token
- 在 HTTP Header 中添加
Authorization: Bearer abc123
- 示例(Retrofit):
OkHttpClient client = new OkHttpClient.Builder() .addInterceptor(chain -> { Request request = chain.request() .newBuilder() .addHeader("Authorization", "Bearer " + token) .build(); return chain.proceed(request); }) .build();
- 在 HTTP Header 中添加
Token 刷新
- 当
access_token
过期时,用refresh_token
重新获取 - 需处理 token 刷新的并发问题(如使用同步锁)
- 当
安全优化策略
HTTPS 配置
- 强制 HTTPS:在
network_security_config.xml
中配置:<domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">api.example.com</domain> </domain-config>
- 证书锁定:将服务器证书的公钥哈希加入配置,防止中间人攻击。
防止抓包与重放攻击
方案 | 说明 |
---|---|
请求签名 | 使用 HMAC-SHA256 对参数签名,服务器验证签名一致性 |
时间戳+随机数 | 请求体包含 timestamp 和 nonce ,服务器校验时间差(如 5 分钟内) |
设备证书绑定 | 集成设备证书(如 Keystore)生成唯一标识,服务器校验 |
数据加密示例(AES)
// 加密 SecretKeySpec key = new SecretKeySpec("1234567890abcdef".getBytes(), "AES"); Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, key); byte[] encrypted = cipher.doFinal("sensitive data".getBytes()); // 解密 cipher.init(Cipher.DECRYPT_MODE, key); String decrypted = new String(cipher.doFinal(encrypted));
常见问题与解决方案
网络请求失败排查表
现象 | 原因 | 解决方案 |
---|---|---|
UnknownHostException |
DNS 解析失败/网络不可用 | 检查网络权限、域名是否正确 |
SSLHandshakeException |
证书未信任/协议不匹配 | 配置 HTTPS 证书信任或升级 TLS 版本 |
SocketTimeoutException |
服务器响应慢 | 设置超时时间(如 connectTimeout=10s) |
JSON 解析异常处理
- 问题:字段缺失或类型不匹配导致
JSONParser
崩溃。 - 解决方案:使用
Gson
的TypeToken
或@SerializedName
注解:class User { @SerializedName("username") String name; // 对应 JSON 的 "username" 字段 int age; }
相关问题与解答
Q1:如何判断当前网络是否可用?
A1:使用 ConnectivityManager
检测网络状态:
ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo info = cm.getActiveNetworkInfo(); boolean isAvailable = info != null && info.isConnected();
注意:需在 AndroidManifest
中添加 ACCESS_NETWORK_STATE
权限。
Q2:如何防止第三方应用劫持我的网络请求?
A2:通过以下方式增强安全性:
- 使用 HTTPS:避免明文传输敏感数据。
- 证书绑定:在客户端预埋服务器证书哈希,拒绝未知证书。
- 请求签名:对关键接口(如支付)的参数进行 HMAC 签名。
- 限制域名:在
network_security_config
中明确允许的