Android Studio中使用jcifs访问SMB共享出现SmbAuthException认证失败问题
我仔细看了你的问题:ES文件浏览器能正常访问公司的SMB共享,说明你的网络连接、用户名和密码都是正确的,问题应该出在jcifs的认证配置或者版本兼容性上。下面是几个针对性的排查和解决方向:
1. 缺失域参数导致认证失败
公司的Windows共享通常基于域环境,而你当前使用的NtlmPasswordAuthentication(user)构造方法只传入了用户名:密码的字符串,jcifs会默认用设备的本地机器名作为域,这显然和公司的域环境不匹配,直接导致认证被拒绝。
修改方式:
使用带域参数的构造方法,明确指定公司的域名(可以是完整的engstl1.us.crownlift.net,或者IT部门提供的短域名,比如CROWNLIFT):
// 替换原来的认证对象创建代码 NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication("engstl1.us.crownlift.net", USER_NAME, PASSWORD);
同时不要把用户名密码放在SMB路径URL中,jcifs 1.3.x版本对URL中的凭据解析支持并不稳定,分开指定认证对象更可靠。
2. 修正路径拼写错误
你的路径里存在拼写错误:Ready_for_Exectuion应该是Ready_for_Execution?虽然Windows文件系统不区分大小写,但拼写错误可能导致路径不存在,部分SMB服务器会在路径不存在时返回认证失败的错误,间接触发你遇到的异常。
修正后的基础路径:
static final String SMB_BASE_PATH = "smb://engstl1.us.crownlift.net/vol1/PIL_SYNECT_TEST_PLAN/Ready_for_Execution/"; String path = SMB_BASE_PATH + "testfile.text";
3. 升级jcifs版本解决兼容性问题
jcifs 1.3.19是非常老旧的版本(发布于2015年),它仅支持SMB 1.0协议,而现代Windows服务器可能已经禁用了SMB 1.0,或者对旧协议的认证做了限制。ES文件浏览器因为支持SMB 2/3所以能正常访问,但旧版jcifs无法适配。
建议替换为jcifs-ng(jcifs的官方维护分支,支持SMB 2/3):
- 如果你用Gradle,在
build.gradle中添加依赖:
implementation 'org.codelibs:jcifs-ng:2.1.30'
- 包名仍为
jcifs.smb,和旧版兼容,但API更完善,能更好地适配现代SMB环境。
修改后的完整示例代码
static final String SMB_BASE_PATH = "smb://engstl1.us.crownlift.net/vol1/PIL_SYNECT_TEST_PLAN/Ready_for_Execution/"; static final String DOMAIN = "engstl1.us.crownlift.net"; static final String USER_NAME = "你的用户名"; static final String PASSWORD = "你的密码"; static final String fileContent = "Here is something in this file"; static boolean successful; @Override protected void onPreExecute() { Log.i(TAG, "开始执行SMB文件写入任务"); } @Override protected String doInBackground(Void... voids) { try{ Log.i(TAG, "进入文件写入逻辑"); // 初始化带域的认证对象 NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(DOMAIN, USER_NAME, PASSWORD); String filePath = SMB_BASE_PATH + "testfile.text"; SmbFile sFile = new SmbFile(filePath, auth); // 确保文件存在(如果需要创建新文件) if (!sFile.exists()) { sFile.createNewFile(); } SmbFileOutputStream sfos = new SmbFileOutputStream(sFile, true); sfos.write(fileContent.getBytes()); sfos.close(); // 务必关闭流释放资源 successful = true; Log.i(TAG, "文件写入成功"); } catch (Exception e) { successful = false; Log.e(TAG, "文件写入失败", e); e.printStackTrace(); } return successful ? "执行成功" : "执行失败"; }
额外注意事项
- 确保你的Android应用已经申请了
INTERNET权限:
<uses-permission android:name="android.permission.INTERNET" />
- 如果是Android 9及以上,需要允许访问该SMB服务器的明文流量(SMB默认不使用HTTPS),可以在
res/xml/network_security_config.xml中配置:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="true"> <domain includeSubdomains="true">engstl1.us.crownlift.net</domain> </domain-config> </network-security-config>
然后在AndroidManifest.xml的<application>标签中引用:
android:networkSecurityConfig="@xml/network_security_config"
内容的提问来源于stack exchange,提问作者T.Rode

