【问题标题】:ADAL to MSAL Migration Securing Web APIADAL 到 MSAL 迁移保护 Web API
【发布时间】:2021-07-16 03:50:09
【问题描述】:

我正在开展一个将 ADAL 迁移到 MSAL 的项目。 UI 部分是 Angular,Web API 是 .Net Framework 4.7.2。 在 Startup.Auth.cs 中,我看到代码在验证传入的 API 请求时非常有效。但是,当我在 Angular 中更改从 MSAL 获取的令牌并将熊令牌发送到 API 时,API 无法告知用户已通过身份验证,也无法告知用户是谁(它将始终返回 false)。

我看到很多来自 .net Core 的例子,有没有什么好的方法可以在 .net Framework 中进行更改?

        public void ConfigureAuth(IAppBuilder app)
        {
            var constants = UnityConfig.GetConfiguredContainer().Resolve<IConstants>();
            app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                {
                    Tenant = constants.TenantId,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidAudiences = new List<string> { constants.Audience, constants.ClientId}
                    },
                    AuthenticationType = "OAuth2Bearer",
                    AuthenticationMode = AuthenticationMode.Active
                });

        }

【问题讨论】:

    标签: .net angular azure-active-directory msal


    【解决方案1】:

    你可以使用我的 nuget,MSALTokenGeneratorv3。

    public static async Task ConfidentialClientBuilderApp(string resource = null, string clientId = null, 字符串 clientSecret = null,字符串权限 = null,IEnumerable scopes = null) { // 我们将使用 MSAL.NET 获取令牌以代表当前用户调用 API 尝试 { // 使用构建模式创建一个 ConfidentialClientApplication (https://github.com/AzureAD/microsoft-authentication-library-for-dotnet/wiki/Client-Applications) ExponentialRetryStrategy retryStrategy = new ExponentialRetryStrategy();

                    _confidentialClientApp = ConfidentialClientApplicationBuilder.Create(clientId)
                        .WithAuthority(String.Format(CultureInfo.InvariantCulture, authority))
                        .WithClientSecret(clientSecret).WithLegacyCacheCompatibility(false)
                        .Build();
    
                    // In memory distributed token cache
                    _confidentialClientApp.AddInMemoryTokenCache();
    
                    // Acquiring an AuthenticationResult for the scope user.read, impersonating the user represented by userAssertion, using the OBO flow
                    await RetryHelper.RetryAsync(async () =>
                    {
                        _authenticationResult = await _confidentialClientApp.AcquireTokenForClient(scopes).ExecuteAsync().ConfigureAwait(false);
                    }, (exception) =>
                    {
                        return true;
                    }, retryStrategy.ShouldRetry(), new Action<Exception, RetryErrorType, int>(LogTokenGenerationFailure)).ConfigureAwait(false);
    
                    if (_authenticationResult != null && !string.IsNullOrEmpty(_authenticationResult.AccessToken))
                        accessToken = _authenticationResult.AccessToken;
    
                    if (accessToken == null)
                    {
                        throw new Exception("Access Token could not be acquired.");
                    }
    
                    return accessToken;
                }
                catch (MsalUiRequiredException)
                {
                    /*
                    * If you used the scope `.default` on the client application, the user would have been prompted to consent for Graph API back there
                    * and no incremental consents are required (this exception is not expected). However, if you are using the scope `access_as_user`,
                    * this exception will be thrown at the first time the API tries to access Graph on behalf of the user for an incremental consent.
                    * You must then, add the logic to delegate the consent screen to your client application here.
                    * This sample doesn't use the incremental consent strategy.
                    */
                    throw;
                }
                catch (Exception)
                {
                    throw;
                }
        }
    

    public static async Task PublicClientBuilderApp(IEnumerable scope, string tenantId, string clientId = null, 字符串用户名 = null,字符串密码 = null) { ConvertStringToSecureString convertToSecureString = new ConvertStringToSecureString(); ExponentialRetryStrategy retryStrategy = new ExponentialRetryStrategy();

            // We will use MSAL.NET to get a token to call the API On Behalf Of the current user
            try
            {
                _publicClientApp = PublicClientApplicationBuilder.Create(clientId).WithAuthority(AzureCloudInstance.AzurePublic, 
                    tenantId).WithLegacyCacheCompatibility(false).Build();
    
                // Acquiring an AuthenticationResult for the scope user.read, impersonating the user represented by userAssertion, using the OBO flow
                await RetryHelper.RetryAsync(async () =>
                {
                    //To clear the token cache every time the new request comes , else it uses cached userassertion
                    var accounts = await _publicClientApp.GetAccountsAsync().ConfigureAwait(false);
    
                    IEnumerator<IAccount> enumerator = accounts.GetEnumerator();
                    while (enumerator.Current != null)
                    {
                        await _publicClientApp.RemoveAsync(enumerator.Current).ConfigureAwait(false);
    
                    }
                    // Acquiring an AuthenticationResult for the scope user.read, impersonating the user represented by userAssertion, using the OBO flow
                    _authenticationResult = await _publicClientApp.AcquireTokenByUsernamePassword(scope, userName, convertToSecureString.StringToSecureString(password)).ExecuteAsync().ConfigureAwait(false);
                }, (exception) =>
                {
                    return true;
                }, retryStrategy.ShouldRetry(), new Action<Exception, RetryErrorType, int>(LogTokenGenerationFailure)).ConfigureAwait(false);
    
                if (_authenticationResult != null && !string.IsNullOrEmpty(_authenticationResult.AccessToken))
                    accessToken = _authenticationResult.AccessToken;
    
                if (accessToken == null)
                {
                    throw new Exception("Access Token could not be acquired.");
                }
    
                return accessToken;
            }
            catch (MsalUiRequiredException)
            {
                /*
                * If you used the scope `.default` on the client application, the user would have been prompted to consent for Graph API back there
                * and no incremental consents are required (this exception is not expected). However, if you are using the scope `access_as_user`,
                * this exception will be thrown at the first time the API tries to access Graph on behalf of the user for an incremental consent.
                * You must then, add the logic to delegate the consent screen to your client application here.
                * This sample doesn't use the incremental consent strategy.
                */
                throw;
            }
            catch (Exception)
            {
                throw;
            }
        }
    
        public static void LogTokenGenerationFailure(Exception exception, RetryErrorType errorType, int retryCount)
        {
        }
    

    【讨论】:

    • 您的代码格式在这个答案中不是很一致(其中一些最终成为常规文本)。你能修复 C# 代码的降价吗?此外,您可能应该添加一些信息,说明您的包到底是做什么的,它拥有什么许可证,以及它是否是开源的等。在 Nuget 上,没有指向项目网站或 repo 的链接。谢谢!
    • 非常好的反馈,周末会更新,非常感谢您的指出。
    猜你喜欢
    • 2022-01-21
    • 2021-01-23
    • 2021-08-22
    • 2021-08-21
    • 2020-11-23
    • 2011-07-31
    • 2021-04-10
    • 2019-12-17
    • 1970-01-01
    相关资源
    最近更新 更多