首页 > 解决方案 > 混合 MSAL 和 MVC 表单身份验证

问题描述

我正在开发具有多个用户的单租户 MVC Web 应用程序。此应用程序针对不同的客户有多种部署,一些客户希望通过 Outlook 365 发送邮件。该应用程序对存储在数据库中的用户使用表单身份验证。

我已经尝试根据以下示例进行工作 - https://github.com/Azure-Samples/ms-identity-aspnet-webapp-openidconnect - 但是它与表单身份验证冲突,因为我被循环回即使登录成功,表单登录页面。

成功登录后,我可以通过将用户定向到 Azure AD 登录来成功检索访问令牌:

var url = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?" +
                "client_id=" + AuthenticationConfig.ClientId +
                "&response_type=code" +
                "&redirect_uri=" + AuthenticationConfig.RedirectUri +
                "&response_mode=query" +
                "&scope=" + AuthenticationConfig.BasicSignInScopes +
                "&state=12345"; 

然后在回调中使用以下内容获取访问令牌:

       public static async Task<string> GetAccessToken(string code)
    {
        var app = ConfidentialClientApplicationBuilder
                    .Create(AuthenticationConfig.ClientId)
                    .WithClientSecret(AuthenticationConfig.ClientSecret)
                    .WithRedirectUri(AuthenticationConfig.RedirectUri)
                    .WithAuthority(AuthenticationConfig.Authority)
                    .Build();

        var scopes = new List<string> { "offline_access", "user.read", "mail.read", "mail.send" };    
        var authenticationResult = await app.AcquireTokenByAuthorizationCode(scopes, code).ExecuteAsync();
        return authenticationResult.AccessToken;
    }

但是,身份验证结果中不会返回刷新令牌。我希望获取访问令牌/到期和刷新令牌/到期并存储它们,以便用户通过 Azure AD 进行一次身份验证,然后我可以在将来使用刷新令牌静默更新访问令牌。

我已经阅读了很多资料,但我能找到的大部分信息都是基于对您的应用使用 Azure AD 登录。我需要保留表单登录和身份验证,仅用于发送电子邮件。这可能吗?

更新以尝试针对用户缓存令牌并将其读回:

        public static async Task OnAuthorisationCodeReceived(string code)
    {
        var app = ConfidentialClientApplicationBuilder
                   .Create(AuthenticationConfig.ClientId)
                   .WithClientSecret(AuthenticationConfig.ClientSecret)
                   .WithRedirectUri(AuthenticationConfig.RedirectUri)
                   .WithAuthority(AuthenticationConfig.Authority)
                   .Build();

        var scopes = new List<string> { "offline_access", "user.read", "mail.read", "mail.send" };
        var authenticationResult = await app.AcquireTokenByAuthorizationCode(scopes, code).ExecuteAsync();
        var account = authenticationResult.Account;

        var identity = new ClaimsIdentity();
        identity.AddClaim(new System.Security.Claims.Claim(ClaimConstants.ObjectId, account.HomeAccountId.ObjectId));
        identity.AddClaim(new System.Security.Claims.Claim(ClaimConstants.TenantId, account.HomeAccountId.TenantId));
        identity.AddClaim(new System.Security.Claims.Claim(System.Security.Claims.ClaimTypes.Upn, account.Username));
        var claimsPrincipal = new ClaimsPrincipal(identity);

        // as per example store the cache
        var userTokenCache = new MSALPerUserMemoryTokenCache(app.UserTokenCache, claimsPrincipal);
        // no accounts returned
        var accounts = await app.GetAccountsAsync();

        var newres = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync().ConfigureAwait(false);
    }

没有返回任何帐户,我可以看到缓存令牌的唯一方法是如果我保留默认值,那么它们不会针对用户存储。

标签: asp.net-mvcoauth-2.0forms-authenticationazure-ad-graph-apimsal

解决方案


不幸的是,MSAL.NET(以及一般的 MSAL)不公开刷新令牌。

可以看到AuthenticationResult中没有“refreshToken”。

您可以通过调用 AcquireTokenSilent 自动处理刷新令牌。


推荐阅读