Токен доступа пользователя Azure AD запрашивается библиотекой angular MSAL и подтверждается WEB API с помощью django_auth_adfs
Я пытаюсь настроить одностраничное приложение Angular с использованием библиотеки MS MSAL Angular для запроса Access token для получения данных пользователя из Microsoft Graph API и для аутентификации в пользовательском WEB API, построенном с помощью DJango Python Framework. Я использую библиотеки django_auth_adfs и rest_framework для создания этого API. Для настройки окружения я использовал следующие руководства :
- https://docs.microsoft.com/en-US/azure/active-directory/develop/tutorial-v2-angular-auth-code и https://azuread.github.io/microsoft-authentication-library-for-js/ref/msal-angular/ для угловой стороны
- https://django-auth-adfs.readthedocs.io/en/latest/rest_framework.html для стороны DJango
В моем приложении Angular App я могу войти в систему с помощью учетных данных Azure AD. Я вижу, что маркеры доступа для MS Graph и для моего API получены, но последний не принимается моим WEB API.
На Azure AD я настроил два приложения. Одно для Angular frontend и одно для django backend. Вот мои конфигурации:
- Для бэкенда DJango:
- Аутентификация с использованием веб-конфигурации с перенаправлением URI на http://localhost:8000/oauth2/callback и только учетных записей организационного каталога (без неявного потока).
- Пробовали без и с секретом клиента (тот же результат).
- Без конфигурации токенов
- Разрешения на MS Ggaph без согласия администратора требуются и предоставлены для моей организации как статус.
- Определена область для раскрытия API: api://xxxxxxxx-32d5-4175-9b05-xxxxxxxxxxxxx/access_as_user (согласие администраторов и пользователей включено) и мой фронтенд добавлен как авторизованное клиентское приложение.
- Для Angular App:
- Аутентификация с использованием одностраничного приложения с URI перенаправления на http://localhost:4200/ и только учетных записей организационного каталога.
- Нет секрета .
- Нет конфигурации токенов
- API разрешение на MS Graph User.Read и на мой бэкенд API (доступ как пользователь). Оба разрешения подтверждены администратором.
Вот мои конфигурации django в settings.py:
INSTALLED_APPS = [
...
"django_auth_adfs",
"rest_framework",
...
]
MIDDLEWARE = [
...
"django_auth_adfs.middleware.LoginRequiredMiddleware",
"corsheaders.middleware.CorsMiddleware",
]
AUTHENTICATION_BACKENDS = (
"django_auth_adfs.backend.AdfsAuthCodeBackend",
"django_auth_adfs.backend.AdfsAccessTokenBackend",
)
AUTH_ADFS = {
"TENANT_ID": AZURE_AD_TENANT_ID,
"CLIENT_ID": AZURE_CLIENT_ID,
"RELYING_PARTY_ID": AZURE_CLIENT_ID,
"AUDIENCE": AZURE_CLIENT_ID,
# "CLIENT_SECRET": AZURE_CLIENT_SECRET, # Tried with or without it
"CLAIM_MAPPING": {
"first_name": "given_name",
"last_name": "family_name",
"email": "upn",
},
"GROUPS_CLAIM": "roles",
"MIRROR_GROUPS": True,
"USERNAME_CLAIM": "upn",
"LOGIN_EXEMPT_URLS": [
"^api/v0/", # Prevent API from triggering a login redirect
],
}
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"django_auth_adfs.rest_framework.AdfsAccessTokenAuthentication",
"rest_framework.authentication.SessionAuthentication",
],
"DEFAULT_RENDERER_CLASSES": [
"rest_framework.renderers.JSONRenderer",
],
"DEFAULT_PERMISSION_CLASSES": [
# Restrict API access for authenticated user by default
"rest_framework.permissions.IsAuthenticated",
],
}
Вот мои конфигурации приложения angular: В app.module.ts:
export function MSALInstanceFactory(): IPublicClientApplication {
return new PublicClientApplication({
auth: {
clientId: environment.azure.client_app_id,
authority: environment.azure.authority,
redirectUri: environment.azure.redirectUri,
postLogoutRedirectUri: environment.azure.redirectUri,
navigateToLoginRequestUrl: true
},
cache: {
cacheLocation: BrowserCacheLocation.LocalStorage,
storeAuthStateInCookie: isIE, // set to true for IE 11
},
system: {
loggerOptions: {
loggerCallback: () => { },
logLevel: LogLevel.Info,
piiLoggingEnabled: false
}
}
});
}
export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
const protectedResourceMap = new Map<string, Array<string> | null>();
protectedResourceMap.set('https://graph.microsoft.com/v1.0/me', ['user.read']);
protectedResourceMap.set('http://localhost:8000/api/v0/', ['api://xxxxxxxx-32d5-4175-9b05-xxxxxxxxxxxx/access_as_user']);
return {
interactionType: InteractionType.Redirect,
protectedResourceMap,
};
}
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: [
'user.read',
'openid',
'profile',
'api://xxxxxxxx-32d5-4175-9b05-xxxxxxxxxxxx/access_as_user'
]
},
loginFailedRoute: "/"
};
}
В сетевом шпионе браузера я вижу, что запросы токена доступа хорошо выполняются библиотекой Angular MSAL для обоих защищенных ресурсов (MS graph и мой DJango API), но тот, который вводится в качестве Bearer при взаимодействии с моим API, получает 401 ошибку.
Кто-нибудь видит, что я упускаю? Заранее благодарю за помощь.
Я наконец-то нашел ответ самостоятельно! В конфигурации Django, конфигурация AUDIENCE была неправильной:
"AUDIENCE": AZURE_CLIENT_ID,
должно быть "AUDIENCE": "api://" + AZURE_CLIENT_ID,
После этого исправления маркер доступа подтвержден.