如何在 ASP.NET Core 3.1 中启用多重身份验证?

Posted

技术标签:

【中文标题】如何在 ASP.NET Core 3.1 中启用多重身份验证?【英文标题】:How to enable multiple authentication in ASP.NET Core 3.1? 【发布时间】:2020-08-31 01:32:49 【问题描述】:

在我的 aspnet core 3.1 项目中,我使用 jwt 进行身份验证。问题是我也在使用 azure 客户端来获取 vm 大小名称列表,并且它也在使用 Bearer 令牌。现在测试我使用 azure 中的 AllowAnonymous 和 Bearer 一切正常,但我需要双重身份验证,一个是经过身份验证的用户的默认设置,一个是 azure 的默认设置。

我的天蓝色助手类看起来像:

        public static async Task<List<string>>  GetAzureVmSizeList(string clientId, string clientSecret, string tenantId, string subscriptionId, string location)
        
            var instanceIds = new List<string>();
            var vmSizes = await VirtualMachineSizes(clientId, clientSecret, tenantId, subscriptionId, location);
            foreach (var vmSize in vmSizes.Where(x => x.NumberOfCores >= 2 && x.MemoryInMB >= 2048)) 
                instanceIds.Add(vmSize.Name);
            

            return instanceIds;
        

        private static async Task<IEnumerable<VirtualMachineSize>> VirtualMachineSizes(string clientId, string clientSecret, string tenantId,
            string subscriptionId, string location)
        
            AzureCredentials credentials = SdkContext.AzureCredentialsFactory.FromServicePrincipal(
                clientId,
                clientSecret,
                tenantId,
                AzureEnvironment.AzureGlobalCloud);
            RestClient restClient = RestClient.Configure()
                .WithEnvironment(AzureEnvironment.AzureGlobalCloud)
                .WithCredentials(credentials)
                .WithLogLevel(HttpLoggingDelegatingHandler.Level.Basic)
                .Build();
            ComputeManagementClient client = new ComputeManagementClient(restClient.Credentials)
            
                SubscriptionId = subscriptionId
            ;

            var vmSizes = await client.VirtualMachineSizes.ListAsync(location);
            return vmSizes;
        

// 如果可能,获取 Azure 令牌我需要在获取 azure vm 大小列表中使用此令牌

public static async Task<string> GetToken(string azureUrl, string clientId, string 
clientSecret)                
                                                                                                               
    var url = $"https://login.microsoftonline.com/azureUrl/oauth2/v2.0/token";                                
    var credentials = new Dictionary<string, string>                                                            
                                                                                                               
        "client_id", clientId,                                                                                
        "client_secret", clientSecret,                                                                        
        "scope", "https://management.azure.com/.default",                                                     
        "grant_type", "client_credentials"                                                                    
    ;                                                                                                          
    var client = new HttpClient();                                                                              
    var req = new HttpRequestMessage(HttpMethod.Post, url)  Content = new 
    FormUrlEncodedContent(credentials) ;
    var res = await client.SendAsync(req);                                                                      
    var result =  res.Content.ReadAsStringAsync().Result;                                                       
    var tokenObject = JObject.Parse(result);                                                                    
    var token = tokenObject["access_token"];                                                                    
    return token.ToString();                                                                                    
                    

// 我正在使用此助手的控制器:

        [AllowAnonymous] // it should be [Authorize]
        [HttpGet("azurevm/projectName")]
        public async Task<IActionResult> GetAzureList(string projectName)
        
            var credentials = await _context.Projects
                .Join(_context.CloudCredentials, project => project.CloudCredentialId, cloud 
           => cloud.Id,
                    (project, cloud) => new project, cloud)
                .Where(@t => @t.cloud.IsAzure 
                                              && @t.project.Name == projectName).Select(x => 
                 new
                
                    azureLocation = x.cloud.AzureLocation,
                    azureClientId = x.cloud.AzureClientId,
                    azureClientSecret = x.cloud.AzureClientSecret,
                    azureSubscriptionId = x.cloud.AzureSubscriptionId,
                    azureTenantId = x.cloud.AzureTenantId,
                    azureUrl = x.cloud.AzureUrl
                ).FirstOrDefaultAsync();

            if (credentials == null)
            
                return BadRequest($"projectName is not Azure based");
            

            var result = await AzureHelper.GetAzureVmSizeList(credentials.azureClientId,
                credentials.azureClientSecret,
                credentials.azureTenantId,
                credentials.azureSubscriptionId,
                credentials.azureLocation);
            if (result == null)
            
                return BadRequest($"projectName is not Azure based");
            

            return Ok(result);
              

//我的启动类jwt配置(或许可以扩展,添加多个jwt)

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                
                    options.TokenValidationParameters = new TokenValidationParameters
                    
                        ValidateIssuerSigningKey = true,
                        IssuerSigningKey =
                            new SymmetricSecurityKey(                                    
            Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
                        ValidateIssuer = false,
                        ValidateAudience = false
                    ;
                );     

【问题讨论】:

【参考方案1】:

要管理虚拟机,您不应代表用户使用授权。因此,在那之后,您应该为您的用户获得一项全局授权,并为您的应用程序获得一项 Azure 门户授权。我建议您使用 Microsoft.Azure.Management.ResourceManager 包来获取虚拟机。

【讨论】:

其实我已经在使用 **Microsoft.Azure.Management.ResourceManager.Fluent; Microsoft.Azure.Management.ResourceManager.Fluent.Authentication; Microsoft.Azure.Management.ResourceManager.Fluent.Core; ** 所以不要使用 JWT 令牌。准备这样的凭据: var credentials = new AzureCredentialsFactory() .FromServicePrincipal(servicePrincipleCredentials.ClientId, servicePrincipleCredentials.ClientSecret, servicePrincipleCredentials.TenantId, AzureEnvironment.AzureGlobalCloud);然后将其传递给身份验证方法 Azure.Configure().Authenticate(credentials) Azure 的凭据可以存储在应用程序设置中。我建议你在 Azure 应用服务中使用 Key Vault 或应用程序设置。不要直接将机密存储在 appsettings.json 中。

以上是关于如何在 ASP.NET Core 3.1 中启用多重身份验证?的主要内容,如果未能解决你的问题,请参考以下文章

仅在 IIS 中发布时,在 ASP.net Core 3.1 WebAPI 中启用 CORS 时出错

在 ASP.NET Core 3.1 中处理多环境的 CORS 策略

如何在 ASP.NET Core 中启用 CORS

如何在 ASP.NET Core 3.1 中使用 Java?

如何在 ASP.NET CORE 3.1 中获取客户端 IP 地址?

如何在 Asp.Net Core 3.0 WebAPI 中启用 CORS