Azure b2c忘记密码链接有时会重定向回登录

时间:2018-11-01 19:00:36

标签: javascript angular azure azure-ad-b2c

我的Azure b2c登录页面的“忘记密码”链接有时会重定向回到登录页面。单击该按钮后,大约有75%的时间它将重定向到登录页面,否则将成功重定向到用于更改密码的页面。

这是我的AuthenticationService:

export class AuthenticationService {
    private id_token: string;
    private access_token: string;
    private applicationSettings: ApplicationSettings;
    private authority: string;

    clientApplication: UserAgentApplication;
    jwtHelper: JwtHelper;

    constructor(private settingsProvider: SettingsProvider) {
        this.applicationSettings = settingsProvider.configuration;
        this.authority = this.getAuthority();
        this.jwtHelper = new JwtHelper();
        this.clientApplication = new Msal.UserAgentApplication(
            this.applicationSettings.clientID,
            this.authority,
            (errorDesc: any, token: any, error: any, tokenType: any) => {
                this.logonCallback.call(this, errorDesc, token, error, tokenType);
            },
            this.applicationSettings.clientOptions
        );
    }

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

    loginPopup(): void {
        var storedThis = this;
        this.clientApplication.loginPopup(this.applicationSettings.b2cScopes)
        .then((idToken) => {
            this.id_token = idToken;
            console.log("ID token:", idToken);
            this.getAccessToken(this.applicationSettings.b2cScopes)
            .catch((reason) => {
                console.log('Unable to acquire token after login:', reason);
                storedThis.logout();
            });
        }, function (error) {
            console.log(error);
        });
    }

    getAccessToken(scopes: string[]): Promise<string> {
        var storedThis = this;
        if(this.access_token) {
            return new Promise((resolve, reject) => {
                resolve(this.access_token)
            });
        }

        let tokenPromise = this.clientApplication.acquireTokenSilent(scopes);
        tokenPromise.then((token) => {
            this.access_token = token;
            console.log("Access token:", token);
        });
        tokenPromise.catch((reason) => {
            this.clientApplication.acquireTokenPopup(scopes)
                .then((token) => {
                    this.access_token = token;
                    console.log("Access token:", token);
                }, function (error) {
                    console.log('Unable to acquire token using popup:', error);
                  storedThis.logout();
            });
        });
        return tokenPromise;
    }

    logout(): void {
        sessionStorage.removeItem('customerId');
        sessionStorage.removeItem('customerIsActive');
        this.clientApplication.logout();
    };

    isAuthenticated(): boolean  {
        let user = this.clientApplication.getUser();
        return user !== null;
    }

    getUser() {
        let user = this.clientApplication.getUser();
        return user;
    }

    getB2cScopes() {
        return this.applicationSettings.b2cScopes;
    }

    // Called after loginRedirect or acquireTokenPopup
    private logonCallback(errorDesc: any, token: any, error: any, tokenType: any) {
        // Password reset functionality
        if (errorDesc) {
            if (errorDesc.indexOf('AADB2C90118') > -1) {
                localStorage.removeItem('theme');
                this.clientApplication = new Msal.UserAgentApplication(
                    this.applicationSettings.clientID,
                    this.getPasswordResetAuthority(),
                    this.passwordResetCallback,
                    {
                        "redirectUri": this.applicationSettings.baseUrl + "/login"
                    }
                );
                this.login();
            }
        }

        // Redirect to previous page functionality
        var loginRedirectPath = sessionStorage.getItem('loginRedirectPath');
        if (loginRedirectPath != null) {
            sessionStorage.removeItem('loginRedirectPath');
            window.location.replace(
                this.settingsProvider.configuration.clientOptions.redirectUri + loginRedirectPath);
            return;
        }
        // Get access token
        if (!errorDesc || errorDesc.indexOf('AADB2C90118') == -1) {
            console.log("ErrorNr: AADB2C90118");
            this.getAccessToken(this.applicationSettings.b2cScopes)
            .catch((reason) => {
                console.log('Unable to acquire token after login:', reason);
            });
        }
    }

    getAuthority() {
        return this.applicationSettings.b2cDomain + "/tfp/" + 
        this.applicationSettings.tenant + "/" + 
        this.applicationSettings.signUpSignInPolicy;
    }

    getPasswordResetAuthority() {
        return this.applicationSettings.b2cDomain + "/tfp/" + 
        this.applicationSettings.tenant + "/" + 
        this.applicationSettings.passwordResetPolicy;
    }

    passwordResetCallback() {
        this.logout();
    }
}

这是我的AuthGuard:

export class AuthGuard implements CanActivate {
    constructor(private authenticationService: AuthenticationService, private router: Router, private themeProvider: ThemeProvider) { }

    canActivate(): any {
        console.log('auth gaurd');
        let userIsAuthenticated = this.authenticationService.isAuthenticated();
        if (userIsAuthenticated) {
            return true;
        }

        this.authenticationService.login();
        return false;
    }
}

在app.module中的路由中,AuthGuard的用法如下:

{ path: '', canActivate: [AuthGuard],  children: [ ...

这是我的配置:

{
    "tenant": "XXXXX.onmicrosoft.com",
    "clientID": "XXXXX",
    "signUpSignInPolicy": "B2C_1_Sign_Up_or_In",
    "passwordResetPolicy": "B2C_1_Password_Reset_Policy",
    "baseUrl": "http://localhost:4200",
    "b2cScopes": [
        "XXXXX"
    ],
    "clientOptions": {
        "redirectUri": "http://localhost:4200",
        "postLogoutRedirectUri": "http://localhost:4200",
        "validateAuthority": true,
        "cacheLocation": "sessionStorage"
    },
    "b2cDomain": "https://login.microsoftonline.com"
}

1 个答案:

答案 0 :(得分:0)

我解决了这个问题。由于更改密码时用户未登录,因此我的AuthGuard将尝试运行登录功能。为了解决这个问题,我在获取重置密码错误代码时在会话存储中添加了一条注释,如下所示:

if (errorDesc.indexOf('AADB2C90118') > -1) {
    ...
    sessionStorage.setItem('changePassword', 'true'); // Added this line
    ...

然后,我在AuthGuard中检查了此注释。如果已设置注释,那么我不想运行登录功能,请参见下文。

var changePassword = sessionStorage.getItem("changePassword");

if (changePassword == null)
  this.authenticationService.login();
else
  sessionStorage.removeItem("changePassword");
相关问题