gpt4 book ai didi

MVC 应用程序中的 Azure AD ADAL - token 过期

转载 作者:行者123 更新时间:2023-12-03 03:09:02 24 4
gpt4 key购买 nike

我已经使用 Azure AD 创建了一个 Web 应用程序进行身份验证。访问 token 在一小时后过期(默认情况下)。由于我的应用程序主要使用 Telerik Controls,因此它不会对服务器进行任何整页往返。为了刷新 token ,我实现了 JavaScript 倒计时。我尝试过不同的方法

  1. 插入隐藏的 IFrame 并在 token 过期之前使用我的应用内的页面刷新 IFrame 的内容
  2. 插入隐藏的 IFrame 并使用 Microsoft 登录链接刷新 IFrame 的内容,如这篇 Microsoft 文章中所述:https://learn.microsoft.com/en-us/azure/active-directory/active-directory-v2-protocols-implicit
  3. 使用 Microsoft 登录链接打开临时窗口
  4. 我还查看了 ADAL JavaScript 库:https://github.com/AzureAD/azure-activedirectory-library-for-js/tree/dev但这意味着我必须重建整个应用程序

所有方法均无效。更糟糕的是:如果我在浏览器中按 F5 进行整个页面刷新,在 token 过期前大约 5 分钟,页面将不再加载,并且浏览器中的“正在加载”圆圈会无休止地旋转。

有人知道如何在 MVC 中处理 ADAL 访问 token 的工作方法吗?

这是配置我的身份验证的代码

 public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(new CookieAuthenticationOptions() { CookieSecure = CookieSecureOption.Always });

app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = "https://login.microsoftonline.com/common/",

TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
// instead of using the default validation (validating against a single issuer value, as we do in line of business apps (single tenant apps)),
// we turn off validation
//
// NOTE:
// * In a multitenant scenario you can never validate against a fixed issuer string, as every tenant will send a different one.
// * If you don’t care about validating tenants, as is the case for apps giving access to 1st party resources, you just turn off validation.
// * If you do care about validating tenants, think of the case in which your app sells access to premium content and you want to limit access only to the tenant that paid a fee,
// you still need to turn off the default validation but you do need to add logic that compares the incoming issuer to a list of tenants that paid you,
// and block access if that’s not the case.
// * Refer to the following sample for a custom validation logic: https://github.com/AzureADSamples/WebApp-WebAPI-MultiTenant-OpenIdConnect-DotNet

ValidateIssuer = false
},

Notifications = new OpenIdConnectAuthenticationNotifications()
{
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;

ClientCredential credential = new ClientCredential(clientId, appKey);
string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;

AuthenticationContext authContext = new AuthenticationContext(string.Format("{0}/{1}", "https://login.microsoftonline.com", tenantID), new ADALTokenCache(signInUserId));

// Get the access token for AAD Graph. Doing this will also initialize the token cache associated with the authentication context
// In theory, you could acquire token for any service your application has access to here so that you can initialize the token cache
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, "https://graph.windows.net");

return Task.FromResult(0);
},

RedirectToIdentityProvider = (context) =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy your app (to Azure Web Sites, for example)without having to change settings
// Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;

return Task.FromResult(0);
},

AuthenticationFailed = (context) =>
{
// Suppress the exception if you don't want to see the error
context.HandleResponse();
return Task.FromResult(0);
}
}

});
}

这是我的 BaseController 中用于在 token 过期之前刷新 token 的代码。我监控 token 过期客户端并在 token 过期之前调用此方法:

[HttpGet]
public ActionResult RefreshAuthenticationToken()
{
var refreshToken = DirectoryUserRepository.GetTokenForApplication().Result.RefreshToken;
var newToken = DirectoryUserRepository.RefreshToken(refreshToken);
return Json(new { TokenExpirationTimestampUTC = newToken.ExpiresOn.GetUnixTimestamp() }, JsonRequestBehavior.AllowGet);
}

这是其他缺失的方法

public async Task<AuthenticationToken> GetTokenForApplication()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
try
{

var authenticationResult = await authenticationContext
.AcquireTokenSilentAsync(
graphResourceID,
new ClientCredential(clientId, appKey),
new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return new AuthenticationToken(authenticationResult.AccessToken) { ExpiresOn = authenticationResult.ExpiresOn, RefreshToken = authenticationResult.RefreshToken };

//return authenticationResult.AccessToken;

}
catch (AggregateException e)
{
foreach (Exception inner in e.InnerExceptions)
{
if (!(inner is AdalException)) continue;
if (((AdalException)inner).ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
authenticationContext.TokenCache.Clear();
}
}
throw e.InnerException;
}
catch (AdalException exception)
{
if (exception.ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
authenticationContext.TokenCache.Clear();
throw;
}
return null;
}
}



public AuthenticationToken RefreshToken(string refreshToken)
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;

// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
try
{

var authenticationResult = authenticationContext
.AcquireTokenByRefreshToken(
refreshToken,
clientcred,
graphResourceID);
return new AuthenticationToken(authenticationResult.AccessToken) { ExpiresOn = authenticationResult.ExpiresOn, RefreshToken = authenticationResult.RefreshToken };
}
catch (AggregateException e)
{
foreach (Exception inner in e.InnerExceptions)
{
if (!(inner is AdalException)) continue;
if (((AdalException)inner).ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
authenticationContext.TokenCache.Clear();
}
}
throw e.InnerException;
}
catch (AdalException exception)
{
if (exception.ErrorCode == AdalError.FailedToAcquireTokenSilently)
{
authenticationContext.TokenCache.Clear();
throw;
}
return null;
}
}

最佳答案

我们可以在 Web 应用程序中使用两种访问 token 来调用 Web API。

第一个是使用委托(delegate)用户身份和 OAuth 2.0 授权代码授予流程。第二个是将应用程序身份与 OAuth 2.0 客户端凭据授予流程一起使用。

当我们使用委托(delegate)用户 token 时,我们可以通过Web应用程序服务器端刷新 token ,然后 token 就会过期。

如果您使用应用程序身份来获取 token ,我们可以使用应用程序的凭据再次获取访问 token 。

Since my Application mainly uses Telerik Controls it doesn't do any full page roundtrips to the server.

你的意思是控件使用AJAX来接收数据吗?如果我理解正确的话,我们可以在 MVC 应用程序中开发一个代理来获取数据。并且在代理服务中,我们可以在token过期时更新token。

下图是 Web 应用程序调用 Web API 的流程:

enter image description here

更新(通过HTTP请求刷新访问 token )

 public static void RefreshToken(string refreshToken)
{
HttpClient client = new HttpClient();
string clientId = "{clientId}";
string secret = "{secret}";
string resource = "https://graph.windows.net";
StringBuilder sb = new StringBuilder();
sb.Append($"client_id={clientId}");
sb.Append($"&grant_type=refresh_token");
sb.Append($"&client_secret={secret}");
sb.Append($"&resource={resource}");
sb.Append($"&refresh_token={refreshToken}");

HttpContent bodyContent = new StringContent(sb.ToString(), Encoding.UTF8, "application/x-www-form-urlencoded");
var tokenResponse = client.PostAsync("https://login.microsoftonline.com/common/oauth2/token", bodyContent).Result;
var stringResponse = tokenResponse.Content.ReadAsStringAsync().Result;
JObject jObject = JObject.Parse(stringResponse);
Console.WriteLine(jObject["access_token"].Value<string>());
}

关于MVC 应用程序中的 Azure AD ADAL - token 过期,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41264957/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com