- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
问题陈述
我正在使用 .NET Core,并且正在尝试使 Web 应用程序与 Web API 通信。两者都需要使用 [Authorize]
进行身份验证属性在他们所有的类上。为了能够在它们之间进行服务器到服务器通信,我需要检索验证 token 。感谢 a Microsoft tutorial 我能够做到这一点.
问题
在本教程中,他们使用对 AcquireTokenByAuthorizationCodeAsync
的调用。为了把token保存在缓存中,这样在其他地方,代码就可以做一个AcquireTokenSilentAsync
,这不需要去管理局验证用户。
This method does not lookup token cache, but stores the result in it, so it can be looked up using other methods such as AcquireTokenSilentAsync
OpenIdConnectEvents.OnAuthorizationCodeReceived
永远不会被调用,因为没有收到授权。只有在有新登录时才会调用该方法。
CookieAuthenticationEvents.OnValidatePrincipal
当用户仅通过 cookie 进行验证时。这有效,我可以获得 token ,但我必须使用
AcquireTokenAsync
,因为我当时没有授权码。根据文档,它
Acquires security token from the authority.
AcquireTokenSilentAsync
失败,因为 token 尚未缓存。我宁愿不总是使用
AcquireTokenAsync
,因为那总是去管理局。
AcquireTokenAsync
得到的token被缓存以便我可以使用
AcquireTokenSilentAsync
其他地方?
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
Events = new CookieAuthenticationEvents()
{
OnValidatePrincipal = OnValidatePrincipal,
}
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectOptions
{
ClientId = ClientId,
Authority = Authority,
PostLogoutRedirectUri = Configuration["AzureAd:PostLogoutRedirectUri"],
ResponseType = OpenIdConnectResponseType.CodeIdToken,
CallbackPath = Configuration["Authentication:AzureAd:CallbackPath"],
GetClaimsFromUserInfoEndpoint = false,
Events = new OpenIdConnectEvents()
{
OnRemoteFailure = OnAuthenticationFailed,
OnAuthorizationCodeReceived = OnAuthorizationCodeReceived,
}
});
private async Task OnValidatePrincipal(CookieValidatePrincipalContext context)
{
string userObjectId = (context.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
ClientCredential clientCred = new ClientCredential(ClientId, ClientSecret);
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectId, context.HttpContext.Session));
AuthenticationResult authResult = await authContext.AcquireTokenAsync(ClientResourceId, clientCred);
// How to store token in authResult?
}
private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
{
// Acquire a Token for the Graph API and cache it using ADAL. In the TodoListController, we'll use the cache to acquire a token to the Todo List API
string userObjectId = (context.Ticket.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier"))?.Value;
ClientCredential clientCred = new ClientCredential(ClientId, ClientSecret);
AuthenticationContext authContext = new AuthenticationContext(Authority, new NaiveSessionCache(userObjectId, context.HttpContext.Session));
AuthenticationResult authResult = await authContext.AcquireTokenByAuthorizationCodeAsync(
context.ProtocolMessage.Code, new Uri(context.Properties.Items[OpenIdConnectDefaults.RedirectUriForCodePropertiesKey]), clientCred, GraphResourceId);
// Notify the OIDC middleware that we already took care of code redemption.
context.HandleCodeRedemption();
}
// Handle sign-in errors differently than generic errors.
private Task OnAuthenticationFailed(FailureContext context)
{
context.HandleResponse();
context.Response.Redirect("/Home/Error?message=" + context.Failure.Message);
return Task.FromResult(0);
}
最佳答案
(注意:我已经在这个确切的问题上苦苦挣扎了好几天。我遵循了与问题中链接的相同的 Microsoft 教程,并跟踪了各种问题,例如野鹅追逐;事实证明该示例包含一大堆看似使用最新版本的 Microsoft.AspNetCore.Authentication.OpenIdConnect
包时不必要的步骤。)。
当我读到这个页面时,我终于有了一个突破性的时刻:
http://docs.identityserver.io/en/release/quickstarts/5_hybrid_and_api_access.html
该解决方案主要涉及让 OpenID Connect auth 将各种 token ( access_token
、 refresh_token
)放入 cookie。
首先,我使用的是 融合应用创建于 https://apps.dev.microsoft.com和 Azure AD 端点的 v2.0。该应用程序具有应用程序 key (密码/公钥)并使用 Allow Implicit Flow
对于 Web 平台。
(出于某种原因,端点的 v2.0 似乎不适用于仅限 Azure AD 的应用程序。我不确定为什么,也不确定它是否真的很重要。)
相关线路来自启动.配置 方法:
// Configure the OWIN pipeline to use cookie auth.
app.UseCookieAuthentication(new CookieAuthenticationOptions());
// Configure the OWIN pipeline to use OpenID Connect auth.
var openIdConnectOptions = new OpenIdConnectOptions
{
ClientId = "{Your-ClientId}",
ClientSecret = "{Your-ClientSecret}",
Authority = "http://login.microsoftonline.com/{Your-TenantId}/v2.0",
ResponseType = OpenIdConnectResponseType.CodeIdToken,
TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = "name",
},
GetClaimsFromUserInfoEndpoint = true,
SaveTokens = true,
};
openIdConnectOptions.Scope.Add("offline_access");
app.UseOpenIdConnectAuthentication(openIdConnectOptions);
OpenIdConnectOptions.Event
回调。不接电话
AcquireTokenAsync
或
AcquireTokenSilentAsync
.否
TokenCache
.这些东西似乎都不是必需的。
OpenIdConnectOptions.SaveTokens = true
的一部分
HttpContext.Authentication.GetTokenAsync("access_token")
获取访问 token :
[HttpGet]
public async Task<IActionResult> Get()
{
var graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(async requestMessage =>
{
var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", accessToken);
}));
var message = new Message
{
Subject = "Hello",
Body = new ItemBody
{
Content = "World",
ContentType = BodyType.Text,
},
ToRecipients = new[]
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "email@address.com",
Name = "Somebody",
}
}
},
};
var request = graphClient.Me.SendMail(message, true);
await request.Request().PostAsync();
return Ok();
}
refresh_token
同样,如果 access_token 过期:
HttpContext.Authentication.GetTokenAsync("refresh_token")
OpenIdConnectOptions
实际上还包括一些我在此省略的内容,例如:
openIdConnectOptions.Scope.Add("email");
openIdConnectOptions.Scope.Add("Mail.Send");
Microsoft.Graph
API 代表当前登录的用户发送电子邮件。
refresh_token
向 Azure AD 服务发布请求获取新的 access_token
(沉默的)。 public class AzureAdRefreshTokenProxy
{
private const string HostUrl = "https://login.microsoftonline.com/";
private const string TokenUrl = $"{Your-Tenant-Id}/oauth2/v2.0/token";
private const string ContentType = "application/x-www-form-urlencoded";
// "HttpClient is intended to be instantiated once and re-used throughout the life of an application."
// - MSDN Docs:
// https://msdn.microsoft.com/en-us/library/system.net.http.httpclient(v=vs.110).aspx
private static readonly HttpClient Http = new HttpClient {BaseAddress = new Uri(HostUrl)};
public async Task<AzureAdTokenResponse> RefreshAccessTokenAsync(string refreshToken)
{
var body = $"client_id={Your-Client-Id}" +
$"&refresh_token={refreshToken}" +
"&grant_type=refresh_token" +
$"&client_secret={Your-Client-Secret}";
var content = new StringContent(body, Encoding.UTF8, ContentType);
using (var response = await Http.PostAsync(TokenUrl, content))
{
var responseContent = await response.Content.ReadAsStringAsync();
return response.IsSuccessStatusCode
? JsonConvert.DeserializeObject<AzureAdTokenResponse>(responseContent)
: throw new AzureAdTokenApiException(
JsonConvert.DeserializeObject<AzureAdErrorResponse>(responseContent));
}
}
}
AzureAdTokenResponse
和
AzureAdErrorResponse
JsonConvert
使用的类:
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class AzureAdTokenResponse
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "token_type", Required = Required.Default)]
public string TokenType { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "expires_in", Required = Required.Default)]
public int ExpiresIn { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "expires_on", Required = Required.Default)]
public string ExpiresOn { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "resource", Required = Required.Default)]
public string Resource { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "access_token", Required = Required.Default)]
public string AccessToken { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "refresh_token", Required = Required.Default)]
public string RefreshToken { get; set; }
}
[JsonObject(MemberSerialization = MemberSerialization.OptIn)]
public class AzureAdErrorResponse
{
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "error", Required = Required.Default)]
public string Error { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "error_description", Required = Required.Default)]
public string ErrorDescription { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "error_codes", Required = Required.Default)]
public int[] ErrorCodes { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "timestamp", Required = Required.Default)]
public string Timestamp { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "trace_id", Required = Required.Default)]
public string TraceId { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, PropertyName = "correlation_id", Required = Required.Default)]
public string CorrelationId { get; set; }
}
public class AzureAdTokenApiException : Exception
{
public AzureAdErrorResponse Error { get; }
public AzureAdTokenApiException(AzureAdErrorResponse error) :
base($"{error.Error} {error.ErrorDescription}")
{
Error = error;
}
}
access_token
(基于我上面链接的答案)
// Configure the OWIN pipeline to use cookie auth.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Events = new CookieAuthenticationEvents
{
OnValidatePrincipal = OnValidatePrincipal
},
});
OnValidatePrincipal
处理程序在
Startup.cs (同样,来自上面链接的答案):
private async Task OnValidatePrincipal(CookieValidatePrincipalContext context)
{
if (context.Properties.Items.ContainsKey(".Token.expires_at"))
{
if (!DateTime.TryParse(context.Properties.Items[".Token.expires_at"], out var expiresAt))
{
expiresAt = DateTime.Now;
}
if (expiresAt < DateTime.Now.AddMinutes(-5))
{
var refreshToken = context.Properties.Items[".Token.refresh_token"];
var refreshTokenService = new AzureAdRefreshTokenService();
var response = await refreshTokenService.RefreshAccessTokenAsync(refreshToken);
context.Properties.Items[".Token.access_token"] = response.AccessToken;
context.Properties.Items[".Token.refresh_token"] = response.RefreshToken;
context.Properties.Items[".Token.expires_at"] = DateTime.Now.AddSeconds(response.ExpiresIn).ToString(CultureInfo.InvariantCulture);
context.ShouldRenew = true;
}
}
}
resource
包含在 API 请求中;文档表明这是必要的,但 API 本身只是回复
resource
不支持。这可能是一件好事 - 大概这意味着访问 token 适用于所有资源(它当然适用于 Microsoft Graph API)
关于c# - 如何使用 Active Directory 存储在 AcquireTokenAsync 中收到的 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41519132/
我创建了一个获取 Azure token 的控制台应用程序,并且我可以毫无问题地与 Graph API 进行通信。当我在 Windows 或 Web 应用程序中使用相同的逻辑时,AcquireToke
我正在尝试使用下面提到的代码在 Web 应用程序中从 AzureAD 获取所有 office365 用户的列表。但是, authContext.AcquireTokenAsync(resrouce,
我正在尝试使用以下重载:authContext.AcquireTokenAsync(, ) 这适用于简单的控制台应用程序,并且我能够检索 token 。但是当我从 Web 应用程序运行它时,调用不会返
我正在使用 ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory v4.3.0) AuthenticationContext.AcquireTok
我正在尝试使用以下重载:authContext.AcquireTokenAsync(, ) 这适用于简单的控制台应用程序,并且我能够检索 token 。但是当我从 Web 应用程序运行它时,调用不会返
我正在使用 ADAL (Microsoft.IdentityModel.Clients.ActiveDirectory v4.3.0) AuthenticationContext.AcquireTok
我希望能够以编程方式从 Azure 获取 token 。 我调用 GetAToken().Wait(); 但失败了。 方法是: public async Task GetAToken() {
我们正在编写一个必须与 Dynamics CRM 2016 Online 集成的 WCF 服务。我正在尝试使用 ADAL 进行身份验证,方法是 AcquireTokenAsync()。问题是,它会显示
我正在尝试从基于站点的 WebService 调用 Azure 托管 WebAPI。基于站点的服务是 adal-angluar SPA,然后必须调用 Azure 中托管的 REST API。来自 AA
我正在使用Active Directory Authentication Library (ADAL) library for Apache Cordova在 Ionic 移动应用程序上。我在调用 a
首先,我不确定这是否重要,但由于@Simon Mourier 在 him answer 中提到的原因,我正在使用 ADAL 的实验版本, this one . 在下面的代码中,我想同步获取一个Auth
在 Azure AD 中,当我们进行诸如 AuthenticationContext.AcquireTokenAsync(resource, new ClientAssertionCertificat
我正在 Xamarin 上开发一个应用程序。我正在尝试跨多个应用程序实现单点登录。为此,我使用 ADAL 首次通过 Azure AD 对用户进行身份验证,然后用户在 AcquireTokenAsync
我正在 Xamarin 上开发一个应用程序。我正在尝试跨多个应用程序实现单点登录。为此,我使用 ADAL 首次通过 Azure AD 对用户进行身份验证,然后用户在 AcquireTokenAsync
我使用 AcquireTokenAsync 通过 Azure Active Directory 进行身份验证。 下面是代码 var uc = new UserCredential(username,
我有一个在 Multi-Tenancy 场景中使用的 native 应用程序。为了对用户进行身份验证——并征得他们同意允许此应用程序代表他们访问 Azure——我只需实例化一个 Authenticat
我要求使用 Azure AD 通过 OAuth 2.0 对我的 clinet 应用程序进行身份验证。 我们开始使用 Microsoft.IdentityModel.Clients.ActiveDire
TL;DR 使用 AuthenticationContext.AcquireTokenAsync() 和 MobileServiceClient.LoginAsync() 对用户进行身份验证有什么区别
我按照 Microsoft Hello Key Vault 中的示例在 ASP.Net MVC Web 应用程序上设置了 Azure Keyvault示例应用程序。 默认情况下,Azure KeyVa
问题陈述 我正在使用 .NET Core,并且正在尝试使 Web 应用程序与 Web API 通信。两者都需要使用 [Authorize] 进行身份验证属性在他们所有的类上。为了能够在它们之间进行服务
我是一名优秀的程序员,十分优秀!