SQL 服务器身份验证的独立 Azure 函数托管标识
Isolated Azure Function Managed Identity for SQL Server Auth
我有一个 .NET 5 Azure Function 运行 FUNCTIONS_WORKER_RUNTIME
配置值 dotnet-isolated
。
函数应用需要使用 EF Core 5.0.6 连接到 Azure SQL 数据库。
我按照 的指导进行 EF 配置。
我的习惯 dbcontext
现在是:
public class SmsOrderContext : DbContext
{
private readonly AzureServiceTokenProvider azureServiceTokenProvider;
public SmsOrderContext(DbContextOptions<SmsOrderContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
{
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator)this.Database.GetService<IDatabaseCreator>();
databaseCreator.EnsureCreated();
this.azureServiceTokenProvider = azureServiceTokenProvider;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
SqlConnection connection = new SqlConnection();
string? envConString = Environment.GetEnvironmentVariable(ConfigConstants.SqlSvrConnString);
connection.ConnectionString = envConString ?? "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=SmsRouter";
if (azureServiceTokenProvider != null)
connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
optionsBuilder.UseSqlServer(connection);
}
}
存在检查 SqlSvrConnString
环境变量的条件,这样我就可以在本地 运行 应用程序 - 它使用 localdb(这工作正常)而不是 Azure
在program.main我有:
.ConfigureServices(s =>
{
s.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
s.AddDbContext<SmsOrderContext>();
}
在我的函数应用程序中,Identity\System 的“状态”切换设置为“打开”
当我触发 Azure 函数(从 http 请求)时,我在 Application Insights 中看到以下异常:
Failure Exception: Microsoft.Data.SqlClient.SqlException (0x80131904):
Login failed for user ''
我认为这表明身份没有传递到 Sql 服务器?谁能看看我哪里出错了?
如果您想使用Azure MSI访问AzureSQL,请参考以下步骤
启用 MSI
创建 Azure AD 组
Connect-AzureAD
New-AzureADGroup -DisplayName "My new group" -MailEnabled $false -SecurityEnabled $true -MailNickName "NotSet"
- 将 MSI 添加为组成员
Add-AzureADGroupMember -ObjectId "the id of the group" -RefObjectId "the id of the msi"
将组设置为 SQL 服务器 Azure AD 管理员
代码
我的DbContext
using Microsoft.EntityFrameworkCore;
using Microsoft.Data.SqlClient;
using Microsoft.Azure.Services.AppAuthentication;
namespace httpfun{
public class BloggingContext : DbContext
{
private readonly AzureServiceTokenProvider azureServiceTokenProvider;
public BloggingContext(DbContextOptions<BloggingContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
{
this.azureServiceTokenProvider = azureServiceTokenProvider;
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
SqlConnection connection= new SqlConnection();
connection.ConnectionString="Server=tcp:<>database.windows.net,1433;Database=<>;";
connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
options.UseSqlServer(connection);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
}
我的Program.cs
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker.Configuration;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
namespace httpfun
{
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services=>{
services.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
services.AddDbContext<BloggingContext>();
})
.Build();
host.Run();
}
}
}
我的功能代码(我用HTTP触发器测试)
using System.Collections.Generic;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace httpfun
{
public class HttpTrigger1
{
private readonly BloggingContext _context;
public HttpTrigger1(BloggingContext context){
this._context=context;
}
[Function("HttpTrigger1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HttpTrigger1");
logger.LogInformation("C# HTTP trigger function processed a request.");
logger.LogInformation("Inserting a new blog");
_context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
_context.SaveChanges();
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to Azure Functions!");
return response;
}
}
}
我有一个 .NET 5 Azure Function 运行 FUNCTIONS_WORKER_RUNTIME
配置值 dotnet-isolated
。
函数应用需要使用 EF Core 5.0.6 连接到 Azure SQL 数据库。
我按照
我的习惯 dbcontext
现在是:
public class SmsOrderContext : DbContext
{
private readonly AzureServiceTokenProvider azureServiceTokenProvider;
public SmsOrderContext(DbContextOptions<SmsOrderContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
{
RelationalDatabaseCreator databaseCreator =
(RelationalDatabaseCreator)this.Database.GetService<IDatabaseCreator>();
databaseCreator.EnsureCreated();
this.azureServiceTokenProvider = azureServiceTokenProvider;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
SqlConnection connection = new SqlConnection();
string? envConString = Environment.GetEnvironmentVariable(ConfigConstants.SqlSvrConnString);
connection.ConnectionString = envConString ?? "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=SmsRouter";
if (azureServiceTokenProvider != null)
connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
optionsBuilder.UseSqlServer(connection);
}
}
存在检查 SqlSvrConnString
环境变量的条件,这样我就可以在本地 运行 应用程序 - 它使用 localdb(这工作正常)而不是 Azure
在program.main我有:
.ConfigureServices(s =>
{
s.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
s.AddDbContext<SmsOrderContext>();
}
在我的函数应用程序中,Identity\System 的“状态”切换设置为“打开”
当我触发 Azure 函数(从 http 请求)时,我在 Application Insights 中看到以下异常:
Failure Exception: Microsoft.Data.SqlClient.SqlException (0x80131904):
Login failed for user ''
我认为这表明身份没有传递到 Sql 服务器?谁能看看我哪里出错了?
如果您想使用Azure MSI访问AzureSQL,请参考以下步骤
启用 MSI
创建 Azure AD 组
Connect-AzureAD
New-AzureADGroup -DisplayName "My new group" -MailEnabled $false -SecurityEnabled $true -MailNickName "NotSet"
- 将 MSI 添加为组成员
Add-AzureADGroupMember -ObjectId "the id of the group" -RefObjectId "the id of the msi"
将组设置为 SQL 服务器 Azure AD 管理员
代码
我的DbContext
using Microsoft.EntityFrameworkCore;
using Microsoft.Data.SqlClient;
using Microsoft.Azure.Services.AppAuthentication;
namespace httpfun{
public class BloggingContext : DbContext
{
private readonly AzureServiceTokenProvider azureServiceTokenProvider;
public BloggingContext(DbContextOptions<BloggingContext> options, AzureServiceTokenProvider azureServiceTokenProvider) : base(options)
{
this.azureServiceTokenProvider = azureServiceTokenProvider;
}
public DbSet<Blog> Blogs { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
SqlConnection connection= new SqlConnection();
connection.ConnectionString="Server=tcp:<>database.windows.net,1433;Database=<>;";
connection.AccessToken = azureServiceTokenProvider.GetAccessTokenAsync("https://database.windows.net/").Result;
options.UseSqlServer(connection);
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
}
我的Program.cs
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Azure.Functions.Worker.Configuration;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.EntityFrameworkCore;
namespace httpfun
{
public class Program
{
public static void Main()
{
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(services=>{
services.AddSingleton<AzureServiceTokenProvider>(new AzureServiceTokenProvider());
services.AddDbContext<BloggingContext>();
})
.Build();
host.Run();
}
}
}
我的功能代码(我用HTTP触发器测试)
using System.Collections.Generic;
using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace httpfun
{
public class HttpTrigger1
{
private readonly BloggingContext _context;
public HttpTrigger1(BloggingContext context){
this._context=context;
}
[Function("HttpTrigger1")]
public HttpResponseData Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("HttpTrigger1");
logger.LogInformation("C# HTTP trigger function processed a request.");
logger.LogInformation("Inserting a new blog");
_context.Blogs.Add(new Blog { Url = "http://blogs.msdn.com/adonet" });
_context.SaveChanges();
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to Azure Functions!");
return response;
}
}
}