Перенаправление пользователя при входе с помощью Azure AD B2C из приложения Angular и msal.js

Я пытаюсь заставить приложение Angular 4 правильно выполнять неявную аутентификацию с помощью Azure AD B2C. Я использую msal.js, чтобы заставить его работать. Я проверил очень ограниченный официальный образец кода, но это бесполезно, так как для входа в систему используется всплывающее окно, а я хочу выполнить перенаправление.

Теперь у меня есть следующая служба аутентификации, которую я внедряю в свое приложение и которая должна позаботиться обо всей аутентификации.

import { Injectable } from '@angular/core';
import * as Msal from 'msal';

@Injectable()
export class AuthenticationService {

    private tenantConfig = {
        tenant: "example.onmicrosoft.com",
        clientID: "redacted (guid of the client)",
        signUpSignInPolicy: "b2c_1_signup",
        b2cScopes: ["https://example.onmicrosoft.com/demo/read", "openid"]
    }

    private authority = "https://login.microsoftonline.com/tfp/" + this.tenantConfig.tenant + "/" + this.tenantConfig.signUpSignInPolicy;

    private clientApplication: Msal.UserAgentApplication;

    constructor() {
        this.clientApplication = new Msal.UserAgentApplication(this.tenantConfig.clientID, this.authority, this.authCallback);
    }

    public login(): void {
        this.clientApplication.loginRedirect(this.tenantConfig.b2cScopes);
    }

    public logout(): void {
        this.clientApplication.logout();
    }

    public isOnline(): boolean {
        return this.clientApplication.getUser() != null;
    }

    public getUser(): Msal.User {
        return this.clientApplication.getUser();
    }

    public getAuthenticationToken(): Promise<string> {
        return this.clientApplication.acquireTokenSilent(this.tenantConfig.b2cScopes)
            .then(token => {
                console.log("Got silent access token: ", token);
                return token;
            }).catch(error => {
                console.log("Could not silently retrieve token from storage.", error);
                return this.clientApplication.acquireTokenPopup(this.tenantConfig.b2cScopes)
                    .then(token => {
                        console.log("Got popup access token: ", token);
                        return token;
                    }).catch(error => {
                        console.log("Could not retrieve token from popup.", error);
                        this.clientApplication.acquireTokenRedirect(this.tenantConfig.b2cScopes);
                        return Promise.resolve("");
                    });
            });
    }

    private authCallback(errorDesc: any, token: any, error: any, tokenType: any) {
        console.log("Callback")

        if (token) {
            console.log("Id token", token);
        }
        else {
            console.log(error + ":" + errorDesc);
        }

        this.getAuthenticationToken();
    }
}

Но это не работает. Я получаю токен ID правильно, и он действителен, поэтому токен Id действительно получает значение, которое я могу использовать, но в течение ограниченного времени.

Проблема в том, что я пытаюсь получить токен аутентификации. Первый вызов acquireTokenSilent возвращает ошибку: Token renewal operation failed due to timeout: null.

Затем я получаю всплывающее окно с запросом имени пользователя и пароля, которое через некоторое время исчезает, и я получаю сообщение об ошибке User does not have an existing session and request prompt parameter has a value of 'None'..

Изменить:

Итак, я думаю, что понимаю, что именно происходит, и воспроизведу проблему в примере приложения, которое вы можете получить здесь: https://github.com/Gimly/NetCoreAngularAzureB2CMsal

Если вы подключитесь с домашней страницы, а затем перейдете на страницу fetchData (ту, которая содержит прогноз погоды), вы увидите, что токен аутентификации правильно активирован acquireTokenSilent (откройте консоль браузера, чтобы получить все журналы). Но если вы обновите страницу непосредственно в fetchData, вы увидите то же поведение, что я описал, с acquireTokenSilent ошибкой с ошибкой о тайм-ауте.

Я могу предположить, что по какой-то причине, хотя getUser возвращает правильное значение, msal не инициализируется полностью до того, как я вызываю getAuthenticationToken, и это причина его полного отказа.

Теперь реальный вопрос ... Как мне убедиться, что он полностью инициализирован, прежде чем пытаться получить токен?


person Gimly    schedule 17.10.2017    source источник
comment
Интересно, что произойдет, , если вы попробуете localStorage?   -  person spottedmahn    schedule 17.10.2017
comment
@spottedmahn только что попробовал, и поведение то же самое.   -  person Gimly    schedule 17.10.2017
comment
@spottedmahn Я нашел немного больше информации о проблеме, не могли бы вы проверить мои правки?   -  person Gimly    schedule 19.10.2017
comment
У вас есть опечатка в вашем коде, значение clientId имеет одинарную кавычку, которая не закрывается   -  person Maverik    schedule 23.03.2021
comment
@Maverik спасибо, я отредактировал и исправил опечатку   -  person Gimly    schedule 24.03.2021


Ответы (2)


Итак, проблема, с которой я столкнулся, была вызвана двумя причинами:

1) ошибка в msal.js, из-за которой процесс инициализации не был полностью завершен в конце вызова конструктора, и я вызывал acquireTokenSilent() до того, как он полностью инициализировался. Это было исправлено в последней версии (на момент написания, все еще в ветке разработки проекта). Дополнительную информацию см. в этой проблеме GitHub.

2) Я не исправил URI перенаправления, из-за чего библиотека приняла текущий URL-адрес в качестве URI перенаправления, который завершился ошибкой, потому что его не было в списке разрешенных URI перенаправления.

После устранения этих двух проблем код, который я опубликовал в моем вопросе, работает должным образом.

person Gimly    schedule 23.10.2017
comment
можешь ли ты источник №1? у вас есть проблема с github, на которую вы можете связать? - person spottedmahn; 27.10.2017
comment
@spottedmahn Обновил ответ с проблемой GitHub. - person Gimly; 28.10.2017
comment
@Gimly Не могли бы вы добавить свой импорт в пример, я пытаюсь следовать примеру, который использует более старую версию msal (0.1.1), которая ссылается на файлы в каталоге out в службе аутентификации. Кажется, этого больше не существует, поэтому мой импорт не работает? - person mbx-mbx; 13.11.2017
comment
@Magrangs Я не уверен, что понимаю, о чем вы спрашиваете. Вы имеете в виду пример приложения NetCoreAngularAzureB2CMsal? Я обновил его, чтобы использовать MSAL 0.1.3, и он должен работать правильно. - person Gimly; 13.11.2017
comment
@Gimly Я перешел по ссылке на образец приложения и обнаружил обновленный импорт (с использованием * из msal), более старая версия, за которой я следил, была здесь: github.com/sunilbandla/msal-angular-sample/blob/master/src/app/, который использует какой-то выходной каталог. Может быть, стоит просто добавить импорт в AuthenticationService в вопросе, чтобы нам, возможно, не нужно было переходить по ссылке? - person mbx-mbx; 13.11.2017
comment
Ах, хорошо, да, это была старая версия, которую я действительно не собирался загружать, получая вещи из внешней библиотеки, я использовал ее до того, как 0.1.3 msal стала официальной. В любом случае, да, я обновлю вопрос, чтобы добавить импорт. - person Gimly; 13.11.2017
comment
@Gimly Я просто добавил несколько правок, чтобы он скомпилировался сразу (удалил Msal на Msal.User и удалил console.log (Callback ')) - person mbx-mbx; 13.11.2017
comment
@Gimly p.s. Большое спасибо за ваш образец, очень помог. Официальная документация такая скудная! - person mbx-mbx; 13.11.2017
comment
@Magrangs, пожалуйста, не стесняйтесь добавлять туда вопросы, если столкнетесь с трудностями. Я собираюсь написать об этом сообщение в блоге, чтобы было немного понятнее. Я предложил добавить его в официальную документацию MSAL, они сказали, что изучат его, но пока не получили отзывов. Пожалуйста, также проголосуйте за вопрос и ответ, если вы еще этого не сделали :). - person Gimly; 13.11.2017
comment
Просто важный момент для всех, кто это читает. Если вы используете azure b2c с openid connect, передайте [ваш идентификатор клиента] INSTEAD OF THE SCOPES в качестве первого параметра в acquTokenSilent или acquTokenPopup, чтобы вернуть токен id, иначе могут возникнуть проблемы с областями действия. ie..acquireTokenSilent ([environment.clientId]) - person mbx-mbx; 14.11.2017

Глядя на для MSAL js, вы должны иметь возможность использовать acquTokenRedirect вместо acquTokenPopup.

person Parakh    schedule 18.10.2017
comment
Если у меня есть действующий id_token, почему я не могу позвонить acquireTokenSilent()? Я только что перенаправил пользователя для входа в систему, зачем мне перенаправлять его снова? - person spottedmahn; 18.10.2017
comment
Что ж, acquTokenRedirect, похоже, тоже работает не намного лучше. И это создает двойное перенаправление, как сказал @spottedmahn. - person Gimly; 18.10.2017
comment
@parakh Я обновил свой вопрос, добавив дополнительную информацию и проект, в котором проблема может быть воспроизведена. - person Gimly; 19.10.2017
comment
частично не реализовано, но @parakh я не могу обновить свой токен, я использую userAgentApplication.acquireTokenSilent(b2cScope, 'https://login.microsoftonline.com/tfp/{{clientDomain}}.onmicrosoft.com/B2C_1_SignIn', user), но получаю сообщение об ошибке. Я также попытался присвоить Authority нулевое значение, но все равно возникает ошибка. - person Chaitanya Chauhan; 02.01.2018