ASP.NET Web API и OpenID Connect: как получить токен доступа из кода авторизации
Я пытаюсь запустить OpenID Connect... Пользователю моего веб-API удалось получить код авторизации для поставщика OpenID Connect. Как я должен передать этот код в свой веб-API ASP.NET? Как мне настроить OWIN Middleware, чтобы я мог получить токен доступа с использованием кода авторизации?
UPDATE:
SPA использует AJAX для связи с моей веб-службой (ASP.NET Web API). В моей веб-службе используется промежуточное ПО OWIN. Я установил OpenIDConnect в качестве механизма аутентификации. Когда веб-служба вызывается в первый раз, она успешно перенаправляет пользователя на страницу входа в систему поставщика OpenID Connect. Пользователь смог войти в систему и получить в результате код авторизации. AFAIK этот код теперь можно использовать (через мой веб-сервис) для токена доступа. Однако я не знаю, как вернуть этот код в мой веб-сервис (это делается с помощью заголовка?), А затем, что настроить, чтобы получить токен доступа. Я предполагаю, что я мог бы вызывать конечную точку токена вручную, но я хотел бы использовать компонент OWIN.
Ответы
Ответ 1
Похоже, что рекомендуется использовать событие AuthorizationCodeReceived
для обмена кодом Auth для токена доступа. У Vittorio есть запись в блоге, которая описывает общий поток.
Вот пример из этого примера приложения на GitHub кода Startup.Auth.cs
, чтобы установить это:
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = Authority,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
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 signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantID), new EFADALTokenCache(signedInUserID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceID);
return Task.FromResult(0);
},
...
}
Примечание. Событие AuthorizationCodeReceived
вызывается только один раз, когда авторизация действительно имеет место. Если код аутентификации уже создан и сохранен, это событие не вызывается. Вы должны выйти или удалить файлы cookie, чтобы это событие произошло.
Ответ 2
BenV уже ответила на вопрос, но там больше, чтобы рассмотреть.
class partial Startup
{
public void ConfigureAuth(IAppBuilder app)
{
// ...
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
Notifications = new OpenIdConnectAuthenticationNotifications() {
AuthorizationCodeReceived = (context) => {
string authorizationCode = context.Code;
// (tricky) the authorizationCode is available here to use, but...
return Task.FromResult(0);
}
}
}
}
}
Две проблемы:
- Прежде всего,
authorizationCode
быстро истечет. Нет смысла хранить его.
- Вторая проблема заключается в том, что событие
AuthorizationCodeReceived
не будет запущено ни для одной из перезагрузок страниц, если срок действия authorizationCode не истек и сохранен внутри сеанса.
Что вам нужно сделать - вызывать AcquireTokenByAuthorizationCodeAsync
, который будет кэшировать его и правильно обрабатывать внутри TokenCache.DefaultShare
:
AuthorizationCodeReceived = (context) => {
string authorizationCode = context.Code;
AuthenticationResult tokenResult = await context.AcquireTokenByAuthorizationCodeAsync(authorizationCode, new Uri(redirectUri), credential);
return Task.FromResult(0);
}
Теперь, прежде чем каждый вызовет ресурс, вызовите AcquireTokenSilentAsync
, чтобы получить accessToken (он будет использовать TokenCache или молча использовать refreshToken). Если токен истек, он будет вызывать исключение AdalSilentTokenAcquisitionException
(вызвать процедуру продления кода доступа).
// currentUser for ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")
AuthenticationResult authResult = await context.AcquireTokenSilentAsync(resourceUri, credential, currentUser);
Вызов AcquireTokenSilentAsync
очень быстрый, если маркер кэширован.
Ответ 3
Чтобы выполнить пользовательскую авторизацию, вам необходимо обойти проверку подлинности owin по умолчанию:
new OpenIdConnectAuthenticationOptions
{
...,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false
},