使用 Java 管理 Azure Data Lake Storage 中的 ACL
此文章說明如何使用 Java 來取得、設定及更新目錄和檔案的存取控制清單。
在上層目錄底下新建的下層項目已可使用 ACL 繼承。 但是您也可以在父目錄的現有子項目上以遞迴方式新增、更新和移除 ACL,而不需要針對每個子項目個別進行這些變更。
套件 (Maven) | 範例 | API 參考 | Gen1 對 Gen2 對應 | 提供意見反應
必要條件
- Azure 訂用帳戶 - 建立免費帳戶。
- 已啟用階層命名空間 (HNS) 的 Azure 儲存體帳戶。 遵循下列指示以建立帳戶。
- Java Development Kit (JDK) 第 8 版或更新版本。
- 在此範例中,Apache Maven 用於專案管理。
- Azure CLI
2.6.0
版或更高版本。 - 下列其中一個安全性權限:
- 已佈建的 Microsoft Entra ID 安全性主體,該主體已獲派儲存體 Blob 資料擁有者角色,且範圍設定為目標容器、儲存體帳戶、上層資源群組或訂用帳戶。
- 您計劃套用 ACL 設定的目標容器或目錄的擁有使用者。 若要以遞迴方式設定 ACL,這包括目標容器或目錄中的所有子項目。
- 儲存體帳戶金鑰。
設定您的專案
注意
本文使用 Maven 建置工具來建置和執行範例程式碼。 Gradle 等其他建置工具也能與適用於 Java 的 Azure SDK 搭配運作。
使用 Maven 建立新的控制台應用程式,或開啟現有的專案。 請遵循下列步驟來安裝套件並新增必要的 import
指示詞。
安裝套件
在文字編輯器中開啟 pom.xml
檔案。 包含 BOM 檔案或包含直接相依性以安裝套件。
包含 BOM 檔案
新增 azure-sdk-bom,以相依於最新版本的程式庫。 在下列程式碼片段中,將 {bom_version_to_target}
預留位置取代為版本號碼。 使用 azure-sdk-bom 可讓您不必指定每個個別相依性的版本。 若要深入了解 BOM,請參閱 Azure SDK BOM 讀我檔案 (英文)。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-sdk-bom</artifactId>
<version>{bom_version_to_target}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
將下列相依性元素新增至相依性群組。 需要 azure-identity 相依性才能對 Azure 服務進行無密碼連線。
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-file-datalake</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-common</artifactId>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
</dependency>
包含直接相依性
若要相依於特定版本的程式庫,請將直接相依性新增至您的專案:
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-file-datalake</artifactId>
<version>{package_version_to_target}</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-storage-common</artifactId>
<version>{package_version_to_target}</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>{package_version_to_target}</version>
</dependency>
包含匯入指示詞
新增必要的 import
指示詞。 在此範例中,我們會在 App.java 檔案中新增下列指示詞:
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.storage.file.datalake.DataLakeDirectoryClient;
import com.azure.storage.file.datalake.DataLakeFileClient;
import com.azure.storage.file.datalake.DataLakeFileSystemClient;
import com.azure.storage.file.datalake.DataLakeServiceClient;
import com.azure.storage.file.datalake.DataLakeServiceClientBuilder;
import com.azure.storage.file.datalake.models.ListPathsOptions;
import com.azure.storage.file.datalake.models.PathItem;
import com.azure.storage.file.datalake.models.AccessControlChangeCounters;
import com.azure.storage.file.datalake.models.AccessControlChangeResult;
import com.azure.storage.file.datalake.models.AccessControlType;
import com.azure.storage.file.datalake.models.PathAccessControl;
import com.azure.storage.file.datalake.models.PathAccessControlEntry;
import com.azure.storage.file.datalake.models.PathPermissions;
import com.azure.storage.file.datalake.models.PathRemoveAccessControlEntry;
import com.azure.storage.file.datalake.models.RolePermissions;
import com.azure.storage.file.datalake.options.PathSetAccessControlRecursiveOptions;
連線到帳戶
若要使用此文章中的程式碼範例,您必須建立代表儲存體帳戶的 DataLakeServiceClient 執行個體。 您可以使用 Microsoft Entra ID 認證或帳戶金鑰來授權用戶端物件。
您可以使用適用於 Java 的 Azure 身分識別用戶端程式庫,向 Microsoft Entra ID 驗證您的應用程式。
首先,您必須將下列其中一個 Azure 角色型存取控制 (Azure RBAC) 角色指派給您的安全性主體:
角色 | ACL 設定功能 |
---|---|
儲存體 Blob 資料擁有者 | 帳戶中的所有目錄和檔案。 |
儲存體 Blob 資料參與者 | 只有安全性主體所擁有的目錄和檔案。 |
接著,建立 DataLakeServiceClient 執行個體,並傳入 DefaultAzureCredential 類別的新執行個體。
static public DataLakeServiceClient GetDataLakeServiceClient(String accountName){
DefaultAzureCredential defaultCredential = new DefaultAzureCredentialBuilder().build();
DataLakeServiceClient dataLakeServiceClient = new DataLakeServiceClientBuilder()
.endpoint("https://" + accountName + ".dfs.core.windows.net")
.credential(defaultCredential)
.buildClient();
return dataLakeServiceClient;
}
若要進一步了解如何使用 DefaultAzureCredential
授權資料存取權,請參閱適用於 Java 的 Azure 身分識別用戶端程式庫。
設定 ACL
設定 ACL 時,您會取代整個 ACL,包括其所有項目。 如果您想要變更安全性主體的權限層級,或將新的安全性主體新增至 ACL,而不會影響其他現有的項目,您應該改為更新 ACL。 若要更新 ACL 而非取代,請參閱本文的更新 ACL 一節。
如果您選擇設定 ACL,則必須新增擁有使用者的項目、擁有群組的項目,以及所有其他使用者的項目。 若要深入了解擁有使用者、擁有群組和所有其他使用者,請參閱使用者和身分識別。
本節說明如何:
- 設定目錄的 ACL
- 設定檔案的 ACL
- 以遞迴方式設定 ACL
設定目錄的 ACL
此範例會取得並設定名為 my-directory
之目錄的 ACL。 此範例會為擁有使用者提供讀取、寫入及執行權限,僅為擁有群組提供讀取和執行權限,並為所有其他人員提供讀取權限。
public void ManageDirectoryACLs(DataLakeFileSystemClient fileSystemClient){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("");
PathAccessControl directoryAccessControl =
directoryClient.getAccessControl();
List<PathAccessControlEntry> pathPermissions = directoryAccessControl.getAccessControlList();
System.out.println(PathAccessControlEntry.serializeList(pathPermissions));
RolePermissions groupPermission = new RolePermissions();
groupPermission.setExecutePermission(true).setReadPermission(true);
RolePermissions ownerPermission = new RolePermissions();
ownerPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
RolePermissions otherPermission = new RolePermissions();
otherPermission.setReadPermission(true);
PathPermissions permissions = new PathPermissions();
permissions.setGroup(groupPermission);
permissions.setOwner(ownerPermission);
permissions.setOther(otherPermission);
directoryClient.setPermissions(permissions, null, null);
pathPermissions = directoryClient.getAccessControl().getAccessControlList();
System.out.println(PathAccessControlEntry.serializeList(pathPermissions));
}
您也可以取得和設定容器根目錄的 ACL。 若要取得根目錄,請將空字串 (""
) 傳遞到 DataLakeFileSystemClient.getDirectoryClient 方法。
設定檔案的 ACL
此範例會取得並設定名為 upload-file.txt
之檔案的 ACL。 此範例會為擁有使用者提供讀取、寫入及執行權限,僅為擁有群組提供讀取和執行權限,並為所有其他人員提供讀取權限。
public void ManageFileACLs(DataLakeFileSystemClient fileSystemClient){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-directory");
DataLakeFileClient fileClient =
directoryClient.getFileClient("uploaded-file.txt");
PathAccessControl fileAccessControl =
fileClient.getAccessControl();
List<PathAccessControlEntry> pathPermissions = fileAccessControl.getAccessControlList();
System.out.println(PathAccessControlEntry.serializeList(pathPermissions));
RolePermissions groupPermission = new RolePermissions();
groupPermission.setExecutePermission(true).setReadPermission(true);
RolePermissions ownerPermission = new RolePermissions();
ownerPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
RolePermissions otherPermission = new RolePermissions();
otherPermission.setReadPermission(true);
PathPermissions permissions = new PathPermissions();
permissions.setGroup(groupPermission);
permissions.setOwner(ownerPermission);
permissions.setOther(otherPermission);
fileClient.setPermissions(permissions, null, null);
pathPermissions = fileClient.getAccessControl().getAccessControlList();
System.out.println(PathAccessControlEntry.serializeList(pathPermissions));
}
以遞迴方式設定 ACL
藉由呼叫 DataLakeDirectoryClient.setAccessControlRecursive 方法,以遞迴方式設定 ACL。 將 PathAccessControlEntry 物件的清單傳遞給這個方法。 每個 PathAccessControlEntry 都會定義 ACL 項目。
如果您想要設定預設 ACL 項目,則呼叫 PathAccessControlEntry 的 setDefaultScope 方法,並且傳遞 true 值。
此範例會設定名為 my-parent-directory
目錄的 ACL。 這個方法會接受名為 isDefaultScope
的布林參數,指定是否要設定預設 ACL。 每次呼叫 PathAccessControlEntry 的 setDefaultScope 方法時,都會使用該參數。 ACL 的項目會為擁有使用者提供讀取、寫入及執行權限,僅為擁有群組提供讀取和執行權限,對所有其他人員不提供任何權限。 此範例的最後一個 ACL 項目會提供物件識別碼 "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 讀取和執行權限給特定使用者。
public void SetACLRecursively(DataLakeFileSystemClient fileSystemClient, Boolean isDefaultScope){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-parent-directory");
List<PathAccessControlEntry> pathAccessControlEntries =
new ArrayList<PathAccessControlEntry>();
// Create owner entry.
PathAccessControlEntry ownerEntry = new PathAccessControlEntry();
RolePermissions ownerPermission = new RolePermissions();
ownerPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
ownerEntry.setDefaultScope(isDefaultScope);
ownerEntry.setAccessControlType(AccessControlType.USER);
ownerEntry.setPermissions(ownerPermission);
pathAccessControlEntries.add(ownerEntry);
// Create group entry.
PathAccessControlEntry groupEntry = new PathAccessControlEntry();
RolePermissions groupPermission = new RolePermissions();
groupPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(false);
groupEntry.setDefaultScope(isDefaultScope);
groupEntry.setAccessControlType(AccessControlType.GROUP);
groupEntry.setPermissions(groupPermission);
pathAccessControlEntries.add(groupEntry);
// Create other entry.
PathAccessControlEntry otherEntry = new PathAccessControlEntry();
RolePermissions otherPermission = new RolePermissions();
otherPermission.setExecutePermission(false).setReadPermission(false).setWritePermission(false);
otherEntry.setDefaultScope(isDefaultScope);
otherEntry.setAccessControlType(AccessControlType.OTHER);
otherEntry.setPermissions(otherPermission);
pathAccessControlEntries.add(otherEntry);
// Create named user entry.
PathAccessControlEntry userEntry = new PathAccessControlEntry();
RolePermissions userPermission = new RolePermissions();
userPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(false);
userEntry.setDefaultScope(isDefaultScope);
userEntry.setAccessControlType(AccessControlType.USER);
userEntry.setEntityId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
userEntry.setPermissions(userPermission);
pathAccessControlEntries.add(userEntry);
directoryClient.setAccessControlRecursive(pathAccessControlEntries);
}
更新 ACL
當您更新 ACL 時,您會修改 ACL 而不是取代 ACL。 例如,您可以將新的安全性主體新增至 ACL,而不會影響 ACL 中列出的其他安全性主體。 若要取代 ACL 而不是更新,請參閱這篇文章的設定 ACL 一節。
本節說明如何:
- 更新 ACL
- 以遞迴方式更新 ACL
更新 ACL
首先,藉由呼叫 PathAccessControl.getAccessControlList 方法來取得目錄的 ACL。 將 ACL 項目的清單複製到 PathAccessControlListEntry 類型的新清單物件。 然後找出您想要更新的項目,並將其取代為清單中的項目。 藉由呼叫 DataLakeDirectoryClient.setAccessControlList 方法來設定 ACL。
此範例會藉由取代所有其他使用者的項目,來更新名為 my-parent-directory
的目錄 ACL。
public void UpdateACL(DataLakeFileSystemClient fileSystemClient, Boolean isDefaultScope){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-parent-directory");
List<PathAccessControlEntry> pathAccessControlEntries =
directoryClient.getAccessControl().getAccessControlList();
int index = -1;
for (PathAccessControlEntry pathAccessControlEntry : pathAccessControlEntries){
if (pathAccessControlEntry.getAccessControlType() == AccessControlType.OTHER){
index = pathAccessControlEntries.indexOf(pathAccessControlEntry);
break;
}
}
if (index > -1){
PathAccessControlEntry userEntry = new PathAccessControlEntry();
RolePermissions userPermission = new RolePermissions();
userPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
userEntry.setDefaultScope(isDefaultScope);
userEntry.setAccessControlType(AccessControlType.OTHER);
userEntry.setPermissions(userPermission);
pathAccessControlEntries.set(index, userEntry);
}
directoryClient.setAccessControlList(pathAccessControlEntries,
directoryClient.getAccessControl().getGroup(),
directoryClient.getAccessControl().getOwner());
}
您也可以取得和設定容器根目錄的 ACL。 若要取得根目錄,請將空字串 (""
) 傳遞到 DataLakeFileSystemClient.getDirectoryClient 方法。
以遞迴方式更新 ACL
若要以遞迴方式更新 ACL,請使用您想要更新的 ACL 項目來建立新的 ACL 物件,然後在更新 ACL 作業中使用該物件。 請勿取得現有的 ACL,只提供要更新的 ACL 項目。
藉由呼叫 DataLakeDirectoryClient.updateAccessControlRecursive 方法,以遞迴方式更新 ACL。 將 PathAccessControlEntry 物件的清單傳遞給這個方法。 每個 PathAccessControlEntry 都會定義 ACL 項目。
如果您想要更新預設 ACL 項目,可以呼叫 PathAccessControlEntry 的 setDefaultScope 方法,並且傳遞 true 值。
此範例會使用寫入權限更新 ACL 項目。 這個方法會接受名為 isDefaultScope
的布林參數,指定是否要更新預設 ACL。 呼叫 PathAccessControlEntry 的 setDefaultScope 方法時,會使用該參數。
public void UpdateACLRecursively(DataLakeFileSystemClient fileSystemClient, Boolean isDefaultScope){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-parent-directory");
List<PathAccessControlEntry> pathAccessControlEntries =
new ArrayList<PathAccessControlEntry>();
// Create named user entry.
PathAccessControlEntry userEntry = new PathAccessControlEntry();
RolePermissions userPermission = new RolePermissions();
userPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
userEntry.setDefaultScope(isDefaultScope);
userEntry.setAccessControlType(AccessControlType.USER);
userEntry.setEntityId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
userEntry.setPermissions(userPermission);
pathAccessControlEntries.add(userEntry);
directoryClient.updateAccessControlRecursive(pathAccessControlEntries);
}
移除 ACL 項目
您可以移除一或多個 ACL 項目。 本節說明如何:
- 移除 ACL 項目
- 以遞迴方式移除 ACL 項目
移除 ACL 項目
首先,藉由呼叫 PathAccessControl.getAccessControlList 方法來取得目錄的 ACL。 將 ACL 項目的清單複製到 PathAccessControlListEntry 類型的新清單物件。 然後找出您想要移除的項目,並呼叫清單物件的移除方法。 藉由呼叫 DataLakeDirectoryClient.setAccessControlList 方法來設定更新的 ACL。
public void RemoveACLEntry(DataLakeFileSystemClient fileSystemClient, Boolean isDefaultScope){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-parent-directory");
List<PathAccessControlEntry> pathAccessControlEntries =
directoryClient.getAccessControl().getAccessControlList();
PathAccessControlEntry entryToRemove = null;
for (PathAccessControlEntry pathAccessControlEntry : pathAccessControlEntries){
if (pathAccessControlEntry.getEntityId() != null){
if (pathAccessControlEntry.getEntityId().equals("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")){
entryToRemove = pathAccessControlEntry;
break;
}
}
}
if (entryToRemove != null){
pathAccessControlEntries.remove(entryToRemove);
directoryClient.setAccessControlList(pathAccessControlEntries,
directoryClient.getAccessControl().getGroup(),
directoryClient.getAccessControl().getOwner());
}
}
以遞迴方式移除 ACL 項目
若要以遞迴方式移除 ACL 項目,請為要移除的 ACL 項目建立新 ACL 物件,然後在移除 ACL 作業中使用該物件。 請勿取得現有的 ACL,只提供要移除的 ACL 項目。
藉由呼叫 DataLakeDirectoryClient.removeAccessControlRecursive 方法來移除 ACL 項目。 將 PathAccessControlEntry 物件的清單傳遞給這個方法。 每個 PathAccessControlEntry 都會定義 ACL 項目。
如果您想要移除預設 ACL 項目,可以呼叫 PathAccessControlEntry 的 setDefaultScope 方法,並且傳遞 true 值。
此範例會從名為 my-parent-directory
的目錄 ACL,移除 ACL 項目。 這個方法會接受名為 isDefaultScope
的布林參數,指定是否要從預設 ACL 移除項目。 呼叫 PathAccessControlEntry 的 setDefaultScope 方法時,會使用該參數。
public void RemoveACLEntryRecursively(DataLakeFileSystemClient fileSystemClient, Boolean isDefaultScope){
DataLakeDirectoryClient directoryClient =
fileSystemClient.getDirectoryClient("my-parent-directory");
List<PathRemoveAccessControlEntry> pathRemoveAccessControlEntries =
new ArrayList<PathRemoveAccessControlEntry>();
// Create named user entry.
PathRemoveAccessControlEntry userEntry = new PathRemoveAccessControlEntry();
RolePermissions userPermission = new RolePermissions();
userPermission.setExecutePermission(true).setReadPermission(true).setWritePermission(true);
userEntry.setDefaultScope(isDefaultScope);
userEntry.setAccessControlType(AccessControlType.USER);
userEntry.setEntityId("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
pathRemoveAccessControlEntries.add(userEntry);
directoryClient.removeAccessControlRecursive(pathRemoveAccessControlEntries);
}
從失敗中復原
您可能會遇到執行階段或權限錯誤。 如果是執行階段錯誤,請從頭開始重新啟動程序。 如果安全性主體沒有足夠的權限可修改要修改的目錄階層中目錄或檔案的 ACL,則可能會發生權限錯誤。 解決權限問題,然後選擇使用接續權杖從失敗點繼續處理程序,或從頭開始重新啟動程序。 如果您想要從頭開始重新啟動,就不需要使用接續權杖。 您可以重新套用 ACL 項目,而不會產生負面影響。
此範例會在發生失敗時傳回接續權杖。 應用程式可以在解決錯誤之後,再次呼叫這個範例方法,然後傳入接續權杖。 如果是第一次呼叫此範例方法,應用程式可以傳入 null
的值作為接續權杖參數。
public String ResumeSetACLRecursively(DataLakeFileSystemClient fileSystemClient,
DataLakeDirectoryClient directoryClient,
List<PathAccessControlEntry> accessControlList,
String continuationToken){
try{
PathSetAccessControlRecursiveOptions options = new PathSetAccessControlRecursiveOptions(accessControlList);
options.setContinuationToken(continuationToken);
Response<AccessControlChangeResult> accessControlChangeResult =
directoryClient.setAccessControlRecursiveWithResponse(options, null, null);
if (accessControlChangeResult.getValue().getCounters().getFailedChangesCount() > 0)
{
continuationToken =
accessControlChangeResult.getValue().getContinuationToken();
}
return continuationToken;
}
catch(Exception ex){
System.out.println(ex.toString());
return continuationToken;
}
}
如果您想要讓程序完成而不受權限錯誤干擾,您可以指定。
若要確保程序完成而不受干擾,請呼叫 PathSetAccessControlRecursiveOptions 物件的 setContinueOnFailure 方法,並且傳入 true 值。
此範例會以遞迴方式設定 ACL 項目。 如果此程式碼遇到權限錯誤,則會記錄該失敗並繼續執行。 此範例會將失敗次數列印到主控台。
public void ContinueOnFailure(DataLakeFileSystemClient fileSystemClient,
DataLakeDirectoryClient directoryClient,
List<PathAccessControlEntry> accessControlList){
PathSetAccessControlRecursiveOptions options =
new PathSetAccessControlRecursiveOptions(accessControlList);
options.setContinueOnFailure(true);
Response<AccessControlChangeResult> accessControlChangeResult =
directoryClient.setAccessControlRecursiveWithResponse(options, null, null);
AccessControlChangeCounters counters = accessControlChangeResult.getValue().getCounters();
System.out.println("Number of directories changes: " +
counters.getChangedDirectoriesCount());
System.out.println("Number of files changed: " +
counters.getChangedDirectoriesCount());
System.out.println("Number of failures: " +
counters.getChangedDirectoriesCount());
}
最佳作法
本節提供您以遞迴方式設定 ACL 的一些最佳做法指導方針。
處理執行階段錯誤
有許多原因可能會發生執行階段錯誤 (例如:中斷或用戶端連線問題)。 如果您遇到執行階段錯誤,請重新啟動遞迴 ACL 程序。 ACL 可以重新套用至項目,而不會造成負面影響。
處理權限錯誤 (403)
如果您在執行遞迴 ACL 程序時遇到存取控制例外狀況,則您的 AD 安全性主體可能沒有足夠權限可將 ACL 套用至目錄階層中的一或多個子項目。 發生權限錯誤時,程序會停止,並提供接續權杖。 修正權限問題,然後使用接續權杖來處理剩餘的資料集。 已成功處理的目錄和檔案不需要重新處理。 您也可以選擇重新啟動遞迴 ACL 程序。 ACL 可以重新套用至項目,而不會造成負面影響。
認證
建議您在目標儲存體帳戶或容器的範圍中,佈建已獲指派儲存體 Blob 資料擁有者角色的 Microsoft Entra 安全性主體。
效能
若要減少延遲,建議您在位於與儲存體帳戶相同區域中的 Azure 虛擬機器 (VM) 中執行遞迴 ACL 程序。
ACL 限制
您可以套用至目錄或檔案的 ACL 數目上限是 32 個存取 ACL 和 32 個預設 ACL。 如需詳細資訊,請參閱 Azure Data Lake Storage Gen2 中的存取控制。