我似乎无法理解这一点。我对整个身份验证过程感到困惑。有很多术语——令牌、身份验证代码、身份、帐户、租户、声明主体、作用域、客户端应用程序、OWIN、OpenID、MSAL、ADAL、Azure、AD、Office365、Graph API等。而且它已经更改了几次,所以我看到的任何文档都可能不适用于当前版本!
我将逐步解决我目前的问题,但我也在寻求一些一般性的帮助。对于站点身份验证,我的Startup类中有一些代码用于初始化站点的身份验证:
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions { CookieManager = new SystemWebCookieManager() });
string authority = string.Format(CultureInfo.InvariantCulture, aadInstance, tenant);
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientID,
Authority = authority,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// when an auth code is received...
AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync,
AuthenticationFailed = (context) =>
{
context.HandleResponse();
return Task.FromResult(0);
}
}
});
我认为这可以处理将用户发送出去登录的问题。然后(我认为?!)微软会发回一个身份验证代码,在这里处理:
private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
var idClient = ConfidentialClientApplicationBuilder.Create(clientID)
.WithAuthority(AzureCloudInstance.AzurePublic, tenant)
.WithRedirectUri(notification.Request.Uri.AbsoluteUri)
.WithClientSecret(clientSecret)
.Build();
var signedInUser = new ClaimsPrincipal(notification.AuthenticationTicket.Identity);
var tokenStore = new MemoryTokenStore(idClient.UserTokenCache, HttpContext.Current, signedInUser);
try
{
string[] scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();
var graphClient = new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) => {
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
}));
// Grab and cache user details...
}
catch (Exception ex)
{
// Handle exception...
}
}
然后在我的控制器中,我用以下内容装饰安全操作
[Authorize]
我相信以上所有工作都正常。我真的不明白它在做什么,但我可以登录并查看安全操作。我遇到问题的地方是在操作中访问Graph API:
public async Task<GraphServiceClient> GetAuthenticatedClient()
{
var idClient = ConfidentialClientApplicationBuilder.Create(clientID)
.WithAuthority(AzureCloudInstance.AzurePublic, tenant)
.WithRedirectUri(HttpContext.Request.Url.AbsoluteUri)
.WithClientSecret(clientSecret)
.WithLogging(writeToLog, LogLevel.Verbose, true)
.Build();
var tokenStore = new MemoryTokenStore(idClient.UserTokenCache, HttpContext, ClaimsPrincipal.Current);
var accounts = await idClient.GetAccountsAsync();
var scopes = graphScopes.Split(' ');
var result = await idClient.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
return new GraphServiceClient(
new DelegateAuthenticationProvider(
async (requestMessage) => {
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
}
)
);
}
我所做的基本上与站点内身份验证完全相同,但由于我没有身份验证代码,我尝试使用AcquireTokenSilent。但这需要一个身份,我在阅读的教程中说,我应该从ConfidentialClientApplication获得身份,如图所示。但大多数时候,调用GetAccountsAsync()时,我得到的帐户数为零。有一两次我拿到了账户,一切正常,但很断断续续。当我查看调试信息时,我得到这样的结果:
Tried to use network cache provider for login.microsoftonline.com. Success? False
Tried to use known metadata provider for login.microsoftonline.com. Success? True
在一个实例中,它在我调试时成功检索到帐户,它说:
Tried to use network cache provider for login.microsoftonline.com. Success? True