提问人:Kumar 提问时间:10/30/2023 更新时间:11/2/2023 访问量:44
使用 SQLProvider 和 MemberShip 的 ASP.Net 应用程序在使用 Azure 托管标识时无法连接到 DB
ASP.Net Application which uses SQLProvider and MemberShip Fails to connect to DB when using Azure Managed Identity
问:
从 SQL Server 身份验证迁移到 Azure 托管标识时,我们面临以下登录问题
异常信息: 异常类型:SqlException 异常消息:用户“”登录失败。 在 System.Data.SqlClient.SqlInternalConnectionTds。ctor(DbConnectionPoolIdentity 标识、SqlConnectionString connectionOptions、SqlCredential 凭据、Object providerInfo、String newPassword、SecureString newSecurePassword、Boolean redirectedUserInstance、SqlConnectionString userConnectionOptions、SessionData reconnectSessionData、DbConnectionPool pool、String accessToken、Boolean applyTransientFaultHandling、SqlAuthenticationProviderManager sqlAuthProviderManager) 在 System.Data.SqlClient.SqlConnectionFactory.CreateConnection (DbConnectionOptions 选项、 DbConnectionPoolKey poolKey、 对象 poolGroupProviderInfo、 DbConnectionPool 池、 DbConnection owningConnection、 DbConnectionOptions 用户选项) 在 System.Data.ProviderBase.DbConnectionFactory.CreatePooledConnection (DbConnectionPool 池、 DbConnection owningObject、 DbConnectionOptions 选项、 DbConnectionPoolKey poolKey、 DbConnectionOptions 用户选项) 在 System.Data.ProviderBase.DbConnectionPool.CreateObject (DbConnection owningObject、 DbConnectionOptions 用户选项、 DbConnectionInternal oldConnection) 在 System.Data.ProviderBase.DbConnectionPool.UserCreateRequest (DbConnection owningObject、 DbConnectionOptions 用户选项、 DbConnectionInternal oldConnection) 在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection (DbConnection owningObject、UInt32 waitForMultipleObjectsTimeout、 布尔值 allowCreate、 布尔值 onlyOneCheckConnection、 DbConnectionOptions userOptions、 DbConnectionInternal& 连接) 在 System.Data.ProviderBase.DbConnectionPool.TryGetConnection (DbConnection owningObject、 TaskCompletionSource1 重试、 DbConnectionOptions userOptions、 DbConnectionInternal oldConnection、 DbConnectionInternal& 连接) 在 System.Data.ProviderBase.DbConnectionInternal.TryOpenConnectionInternal (DbConnection outerConnection、 DbConnectionFactory connectionFactory、 TaskCompletionSource1 重试) 在 System.Data.SqlClient.SqlConnection.TryOpen (TaskCompletionSource'1 重试) 在 System.Data.SqlClient.SqlConnection.Open() 在 System.Web.DataAccess.SqlConnectionHolder.Open (HttpContext 上下文,布尔值 revertImpersonate) 在 System.Web.DataAccess.SqlConnectionHelper.GetConnection (字符串 connectionString,布尔值 revertImpersonation) 在 System.Web.Security.SqlRoleProvider.GetRolesForUser (字符串用户名) 在 System.Web.Security.RolePrincipal.IsInRole (字符串角色) 在 System.Web.Configuration.AuthorizationRule.IsTheUserInAnyRole (StringCollection 角色,IPrincipal 主体) 在 System.Web.Configuration.AuthorizationRule.IsUserAllowed (IPrincipal 用户,字符串谓词) 在 System.Web.Configuration.AuthorizationRuleCollection.IsUserAllowed (IPrincipal 用户,字符串谓词) 在 System.Web.Security.UrlAuthorizationModule.OnEnter (对象源,EventArgs eventArgs) 在 System.Web.HttpApplication.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 在 System.Web.HttpApplication.ExecuteStepImpl (IExecutionStep 步骤) 在 System.Web.HttpApplication.ExecuteStep (IExecutionStep 步骤,布尔值&完成同步)
1 retry, DbConnectionOptions userOptions, DbConnectionInternal& connection) at System.Data.ProviderBase.DbConnectionFactory.TryGetConnection(DbConnection owningConnection, TaskCompletionSource
1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource
下面是 web.config
<system.web>
<roleManager enabled="true" cacheRolesInCookie="true"
defaultProvider="CustomizedRoleProvider" cookieTimeout="60">
<providers>
<clear />
<add connectionStringName="ProjectConnection"
type="System.Web.Security.SqlRoleProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" applicationName="/"
name="CustomizedRoleProvider" />
</providers>
</roleManager>
<membership defaultProvider="CustomizedProvider">
<providers>
<remove name="AspNetSqlMembershipProvider" />
<add connectionStringName="ProjectConnection" enablePasswordRetrieval="false"
enablePasswordReset="true" requiresQuestionAndAnswer="false" applicationName="/"
requiresUniqueEmail="true" passwordFormat="Hashed"
maxInvalidPasswordAttempts="3" minRequiredNonalphanumericCharacters="1"
passwordAttemptWindow="3" minRequiredPasswordLength="8"
passwordStrengthRegularExpression="^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,16}$"
name="CustomizedProvider" type="System.Web.Security.SqlMembershipProvider,
System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</providers>
</membership>
<authentication mode="Forms">
<forms slidingExpiration="true" loginUrl="Login/Login" defaultUrl="~/"
timeout="10800" requireSSL="false" protection="All" />
</authentication>
<authorization>
<deny users="?" />
<allow roles="Admin" />
</authorization>
<customErrors mode="Off" />
</system.web>
<connectionStrings>
<add name="ProjectConnection"
connectionString="Server=tcp:xx.database.windows.net,1433;Database=xx;" />
</connectionStrings>
答:
我参考了这个 MS 文档并创建了一个连接到 Azure SQL 的文档,它在部署后成功加载,如下所示:-Asp.Net app
现在,为了成功启用托管标识,我引用了此 MS Document2 将我的 Azure Web 应用托管标识与 Azure SQL 连接,如下所示:-
- 我在我的 Azure SQL 服务器中添加了一个用户作为管理员,如下所示:-
- 然后我访问了我的 Azure Web 应用>环境变量>连接字符串,并将下面的 ConnectionString 添加到 MyDbConnection:-
"Server=tcp:sqlservername.database.windows.net;Authentication=Active Directory Default; Database=dotnetsiliconsqldb;"
可以在本地 web.config 文件中更新此连接字符串,也可以在 asp.net 代码中更新appsettings.json文件。
- 现在,启用 Azure Web 应用托管标识,并将其所需的角色分配给 Azure SQL,如下所示:-
使用 Azure AD 凭据连接到 Azure SQL Server,并运行以下命令以添加 Web 应用托管标识角色以访问 Azure SQL。
Web 应用托管标识的名称与 Web 应用的名称相同:-
SQL查询:-
CREATE USER [web-app-name<identity-name>] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [web-app-name<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [web-app-name<identity-name>];
ALTER ROLE db_ddladmin ADD MEMBER [web-app-name<identity-name>];
GO
请确保选中“允许 Azure 服务和资源访问此服务器”,以便我们的 Web 应用通过防火墙访问 Azure SQL Server。我还允许从我的 Azure SQL 中的所有 IP 进行连接:-:-
可以参考 Mark McGookin 的 SO 答案 - 使用托管标识和 VSCode - Stack Overflow 将本地 asp dotnet 核心应用连接到 Azure SQL,以通过 Azure CLI 执行所有这些步骤。
评论