代码之家  ›  专栏  ›  技术社区  ›  Agi Hammerthief

如何使uCanAccess使用Samba身份验证,在用户名或密码中使用特殊字符?

  •  1
  • Agi Hammerthief  · 技术社区  · 6 年前

    TL;DR: 什么 Database.FileFormat

    jCIFS . 它允许我创建/覆盖文件,如果给予正确的身份验证凭据,无论我在域中的哪台电脑上使用它。

    我还有一个应用程序,它使用uCanAccess/jackcess连接到网络共享上的MDB。但是(据我所知),它使用登录用户的凭据,其中许多用户具有只读访问权限。只有系统/网络管理员具有写入权限。

    有问题的数据库没有密码保护。(打开时不需要输入密码。)

    我的意图是让应用程序在写入数据库之前,使用uCanAccess连接中的Samba凭据请求管理员的Samba凭据,这样它就不会抛出错误 java.nio.channels.NonWritableChannelException ,根据以下堆栈跟踪:

    java.nio.channels.NonWritableChannelException
      at sun.nio.ch.FileChannelImpl.write(FileChannelImpl.java:747)
      at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:310)
      at com.healthmarketscience.jackcess.impl.PageChannel.writePage(PageChannel.java:247)
      at com.healthmarketscience.jackcess.impl.TableImpl.writeDataPage(TableImpl.java:1980)
      at com.healthmarketscience.jackcess.impl.TableImpl.addRows(TableImpl.java:2229)
      at com.healthmarketscience.jackcess.impl.TableImpl.addRow(TableImpl.java:2067)
      at net.ucanaccess.converters.UcanaccessTable.addRow(UcanaccessTable.java:44)
      at net.ucanaccess.commands.InsertCommand.insertRow(InsertCommand.java:101)
      at net.ucanaccess.commands.InsertCommand.persist(InsertCommand.java:148)
      at net.ucanaccess.jdbc.UcanaccessConnection.flushIO(UcanaccessConnection.java:315)
      at net.ucanaccess.jdbc.UcanaccessConnection.commit(UcanaccessConnection.java:205)
      at net.ucanaccess.jdbc.AbstractExecute.executeBase(AbstractExecute.java:217)
      at net.ucanaccess.jdbc.Execute.execute(Execute.java:46)
      at net.ucanaccess.jdbc.UcanaccessPreparedStatement.execute(UcanaccessPreparedStatement.java:228)
      at myapp.db.Digger.addTransaction(Digger.java:993)
      at myapp.tasks.TransactionRunnable.run(TransactionRunnable.java:42)
      at java.lang.Thread.run(Thread.java:745)
    

    更新: smbFileChannel Gord Thompson和J.T.Alhborn的课, shown here . 我的代码基于该答案中显示的主类,如下所示:

    // Ask the user for login credentials and the path to the database
    String smbURL = (chosenDir.endsWith("/") ? chosenDir : chosenDir + '/') 
      + dbName;
    System.out.println("DB Path to use for URL: " + smbURL);
    URL u = new URL(smbURL);
    try (
      // construct the SMB DB URL
      SmbFileChannel sfc = new SmbFileChannel(smbURL);
      Database db = new DatabaseBuilder().setChannel(sfc)
        .setFileFormat(Database.FileFormat.GENERIC_JET4).create();
    ) {
      // Model the table
      Table tbl = new TableBuilder("Transactions")
        .addColumn(new ColumnBuilder("TransactionID", DataType.LONG).setAutoNumber(true))
        .addColumn(new ColumnBuilder("ControllerID", DataType.LONG).setAutoNumber(false))
        .addColumn(new ColumnBuilder("ReaderID", DataType.LONG).setAutoNumber(false))
        .addColumn(new ColumnBuilder("Event", DataType.LONG).setAutoNumber(false))
        .addColumn(new ColumnBuilder("Timestamp", DataType.SHORT_DATE_TIME).setAutoNumber(false))
        .addColumn(new ColumnBuilder("Number", DataType.LONG).setAutoNumber(false))
        .addIndex(new IndexBuilder(IndexBuilder.PRIMARY_KEY_NAME).addColumns("TransactionID").setPrimaryKey())
        .toTable(db);
      // Add the row
      Map<String, Object> values = new HashMap<>();
      values.put("ControllerID", cid);
      values.put("ReaderID", rid);
      values.put("Event", evtNum);
      values.put("Timestamp", ts); // Long; must be converted to DataType.SHORT_DATE_TIME
      values.put("Number", accNum);
      tbl.addRowFromMap(values);
    } catch (IOException IOEx) {
      System.err.println(
        "Failed to write record to Transactions table in database: " 
        + IOEx.getMessage()
       );
       IOEx.printStackTrace(System.err);
      } catch (Exception ex) {
        System.err.println(
          '[' + ex.getClass().getSimpleName() + "]: Failed to write record to "
          + "Transactions table in database: " + ex.getMessage()
        );
        ex.printStackTrace(System.err);
      }
    

    执行上述代码将产生以下输出:

    DB Path to use for URL: smb://machine.vpnName/Storage/me/dbs/DBName.mdb
    Failed to write record to Transactions table in database: Logon failure: account currently disabled.
    jcifs.smb.SmbAuthException: Logon failure: account currently disabled.
       at jcifs.smb.SmbTransport.checkStatus(SmbTransport.java:546)
        at jcifs.smb.SmbTransport.send(SmbTransport.java:663)
        at jcifs.smb.SmbSession.sessionSetup(SmbSession.java:390)
        at jcifs.smb.SmbSession.send(SmbSession.java:218)
        at jcifs.smb.SmbTree.treeConnect(SmbTree.java:176)
        at jcifs.smb.SmbFile.doConnect(SmbFile.java:911)
        at jcifs.smb.SmbFile.connect(SmbFile.java:957)
        at jcifs.smb.SmbFile.connect0(SmbFile.java:880)
        at jcifs.smb.SmbFile.open0(SmbFile.java:975)
        at jcifs.smb.SmbFile.open(SmbFile.java:1009)
        at jcifs.smb.SmbRandomAccessFile.<init>(SmbRandomAccessFile.java:57)
        at jcifs.smb.SmbRandomAccessFile.<init>(SmbRandomAccessFile.java:42)
        at samba.SmbFileChannel.<init>(SmbFileChannel.java:30)
        at samba.SambaLanWriteTest.writeTest(SambaLanWriteTest.java:130)
        at samba.SambaLanWriteTest.main(SambaLanWriteTest.java:181)
    

    在使用Windows文件资源管理器时,我有权写入有问题的数据库文件的测试副本。我在提示时选择了那个。

    更新2: 我意识到我忘了将我的用户名和密码添加到 smb:// 如汤普森的例子所示。我将代码改为:

    String smbCred = "smb://" + auth.getUsername() + ":" + auth.getPassword() + "@",
      fixer = chosenDir.replace("\\", "/").replace("smb://", smbCred),
      smbURL = fixer + dbName;
    System.out.println("DB Path to use for URL: " + smbURL);
    // URL u = new URL(smbURL);
    

    下一个问题是我的密码包含 特殊的 java.net.URLEncoder.encode() auth.getUsername() auth.getPassword() 所以代码不会抛出 MalformedURLException SmbChannel . 但是,我遇到的下一个异常如下:

    Failed to write record to Transactions table in database: File format GENERIC_JET4 [VERSION_4] does not support file creation for null
    java.io.IOException: File format GENERIC_JET4 [VERSION_4] does not support file creation for null
        at com.healthmarketscience.jackcess.impl.DatabaseImpl.create(DatabaseImpl.java:444)
    

    数据库.FileFormat Database 反对?

    1 回复  |  直到 6 年前
        1
  •  1
  •   Agi Hammerthief    6 年前

    原来我需要 Database.FileFormat.V2000 .

    在那之后,一切都是一帆风顺的(尽管我仍然需要找出如何正确转换长时间戳)。

    推荐文章