无法使用MSI对Azure存储容器(blob)实施Azure Web App服务访问

时间:2019-06-23 19:00:02

标签: azure-web-sites azure-storage-blobs azure-managed-identity

我有一个Azure资源组,其中包含Web App Service和BLOB容器存储。我的Web应用程序(.NET Core)尝试从容器中检索并显示图像。容器没有对内容的公共访问(访问级别为私有)。我为我的应用程序创建了系统分配的标识,并在存储访问控制(IAM)中赋予了它读者角色。

这是我通过应用程序代码访问blob的方式:

const string blobName = "https://storagename.blob.core.windows.net/img/Coast.jpg";
string storageAccessToken = await GetStorageAccessTokenAsync();
var tokenCredential = new TokenCredential(storageAccessToken);
var storageCredentials = new StorageCredentials(tokenCredential);
var blob = new CloudBlockBlob(new Uri(blobName), storageCredentials);
ImageBlob = blob.Uri;

GetStorageAccessTokenAsync()执行此操作:

var tokenProvider = new AzureServiceTokenProvider();
return await tokenProvider.GetAccessTokenAsync("https://storage.azure.com/");

然后通过

显示图像
<img src="@Model.ImageBlob" />

我的代码中没有任何异常,但是在浏览器控制台中,BLOB容器中的图像未显示并显示404错误(指定的资源不存在)。 当我将容器的访问级别更改为“ blob”(公共访问)时,应用正常运行并显示图像。 显然,获取凭据不正确,但是我找不到任何有效的示例,也找不到详细的解释说明它实际上应该如何工作。 任何帮助都非常感谢。

UDPATE: 谢谢所有回答。所以,看来我这里有两个问题。

1)我没有正确获得凭证。 我可以看到我创建的“ AzureServiceTokenProvider”对象(Microsoft.Azure.Services.AppAuthentication)在运行时具有空属性PrincipalUsed。

我的应用程序部署到Azure App Service,该应用程序具有系统管理的身份,并且该身份(服务主体)在Azure存储中获得了权限(我建议将权限从帐户读取器更改为Storage Blob数据读取器)。

不是应该从当前上下文中获取所有需要的数据吗?如果没有,我在这里可以做什么?

2)我使用了错误的方法来显示图像,但是由于该应用仍然无法访问存储,因此我无法修复它。

但仍然-在我的情况下,通常的做法是什么?我的意思是没有对存储的公共访问,我使用“ CloudBlockBlob”来获取图像。

3 个答案:

答案 0 :(得分:1)

Reader允许读取控制平面,但不能读取数据平面。您需要的角色是Storage Blob Data Reader,它可以访问读取Blob内容。

有关此的更多详细信息,请查看:https://docs.microsoft.com/en-us/azure/role-based-access-control/role-definitions#data-operations-example

答案 1 :(得分:0)

使用<img src="@Model.ImageBlob" />时,浏览器不会在请求中发送任何授权标头。在您的代码中,您正在获取令牌,但是在获取映像时,令牌未在授权标头中发送。因此,存储API认为这是一个匿名请求。这就是您得到404的原因。

获取图像时,您需要发送验证码。这段代码对我有用

public async Task<ActionResult> Image()
        {
            const string blobName = "https://storage.blob.core.windows.net/images/image.png";
            string storageAccessToken = await GetStorageAccessTokenAsync().ConfigureAwait(false);

            var tokenCredential = new TokenCredential(storageAccessToken);
            var storageCredentials = new StorageCredentials(tokenCredential);

            var blob = new CloudBlockBlob(new Uri(blobName), storageCredentials);
            Stream blobStream = blob.OpenRead();
            return File(blobStream, blob.Properties.ContentType, "image.png");
        }

在视图中,我使用

<img src="/Home/Image" />

答案 2 :(得分:0)

最后,我明白了。首先,有关从Azure存储中获取令牌和图像的代码部分是可以的。我在视图中使用以下代码解决了在RazorPages应用程序中显示图像的第二个问题:

<form asp-page-handler="GetImage" method="get">
    <img src="/MyPageName?handler=GetImage" />
</form>

和模型中的相应代码:

public async Task<ActionResult> OnGetGetImageAsync()
{
   //getting image code and returning FileContentResult
}

但是我仍在思考:是否有更简单的方法来做到这一点?喜欢将图像集合添加到模型中,使用“ OnGet ...”处理程序填充它,然后在视图中使用其显示内容。我没有找到在<img>标记中使用模型属性的方法。有人有建议吗?