无法在Azure中使用系统分配的托管身份使用Blob存储操作

时间:2020-05-12 17:36:43

标签: c# azure azure-storage azure-storage-blobs azure-managed-identity

获取“服务器未能对请求进行身份验证。请确保正确形成包括签名在内的Authorization标头的值。” 尝试在Azure中使用C#语言使用系统分配的托管身份时出错。 / p>

遵循的步骤

  • 使用已启用身份(已分配系统)创建新的VM
  • 使用存储帐户中的角色分配在IAM中添加了虚拟机
  • 能够使用C#生成令牌
  • 但是在读取blob时出现异常,以下是异常详细信息
import React from 'react';
import { View, Text, StyleSheet, TextInput, Button } from 'react-native';

import Card from '../components/Card';

  const StartGameScreen = props => {
    return (
     <View style={styles.screen}>
       <Text style={styles.title}>Start a New Game!</Text>
        <Card style={styles.inputContainer}>
          <Text>Select a Number</Text>
          <TextInput />
          <View style={styles.buttonContainer}>
            <View style={styles.button}><Button title="Reset" onPress={() => {}} /></View>
            <View style={styles.button}><Button title="Confirm" onPress={() => {}} /></View>
          </View>
         </Card>
     </View>
   );
 };

 const styles = StyleSheet.create({
  screen: {
    flex: 1,
    padding: 10,
    alignItems: 'center'
    },
  title: {
    fontSize: 20,
    marginVertical: 10
    },
  inputContainer: {

    width: 300,
    maxWidth: '80%',
    alignItems: 'center'

    },

  buttonContainer: {
    flexDirection: 'row',
    width: '100%',
    justifyContent: 'space-between',
    paddingHorizontal: 15
      },
  button: {
    width:100
     }
   });

export default StartGameScreen;

程序类

Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
   at Microsoft.Azure.Storage.Core.Executor.Executor.<ExecuteAsync>d__1`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Storage.Blob.CloudBlockBlob.<DownloadTextAsync>d__72.MoveNext()

AzureCloudBlob类,用于使用系统分配的受管身份访问令牌来连接和读取Blob

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                var blob = new AzureCloudBlob();
                Console.WriteLine(blob.ReadBlob());
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
        }
    }

1 个答案:

答案 0 :(得分:1)

如果要通过Azure AD身份访问Azure存储,则应使用resouce=https://storage.azure.com/获取Azure AD访问令牌。但是您使用resource=https://management.azure.com/。请更换它。此外,请注意,您需要为MSI分配正确的角色。角色应该是 Storage Blob数据读取器 Storage Blob数据贡献者 Storage Blob数据所有者

详细步骤如下

  1. 在Azure VM上启用系统分配的托管身份

    $vm = Get-AzVM -ResourceGroupName myResourceGroup -Name myVM
    Update-AzVM -ResourceGroupName myResourceGroup -VM $vm -AssignIdentity:$SystemAssigned
    
  2. 在存储帐户范围内将角色分配给MSI

    $sp =Get-AzADServicePrincipal -displayname "<your VM name>"
    New-AzRoleAssignment -ObjectId $sp.id `
        -RoleDefinitionName "Storage Blob Data Reader" `
        -Scope  "/subscriptions/<subscription>/resourceGroups/sample-resource-group/providers/Microsoft.Storage/storageAccounts/<storage-account>"
    
  3. 代码

    class Program
    {
        static void Main(string[] args)
        {
            //get token
            string accessToken = GetMSIToken("https://storage.azure.com/");
    
            //create token credential
            TokenCredential tokenCredential = new TokenCredential(accessToken);
    
            //create storage credentials
            StorageCredentials storageCredentials = new StorageCredentials(tokenCredential);
    
            Uri blobAddress = new Uri("<URI to blob file>");
    
            //create block blob using storage credentials
            CloudBlockBlob blob = new CloudBlockBlob(blobAddress, storageCredentials);
    
            //retrieve blob contents
            Console.WriteLine(blob.DownloadText());
            Console.ReadLine();
        }
    
        static string GetMSIToken(string resourceID)
        {
            string accessToken = string.Empty;
            // Build request to acquire MSI token
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=" + resourceID);
            request.Headers["Metadata"] = "true";
            request.Method = "GET";
    
            try
            {
                // Call /token endpoint
                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    
                // Pipe response Stream to a StreamReader, and extract access token
                StreamReader streamResponse = new StreamReader(response.GetResponseStream());
                string stringResponse = streamResponse.ReadToEnd();
                JavaScriptSerializer j = new JavaScriptSerializer();
                Dictionary<string, string> list = (Dictionary<string, string>)j.Deserialize(stringResponse, typeof(Dictionary<string, string>));
                accessToken = list["access_token"];
                return accessToken;
            }
            catch (Exception e)
            {
                string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
                return accessToken;
            }
        }
    }
    

enter image description here