简体   繁体   English

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

[英]Azure b2c Forgot password link sometimes redirect back to login

The Forgot password link of my Azure b2c login page sometimes redirect back to the login page. 我的Azure b2c登录页面的“忘记密码”链接有时会重定向回到登录页面。 It redirects back to the login page in about 75% of the times I click it, and otherwise successfully to the page for changing password. 单击它后,大约有75%的时间它会重定向回登录页面,否则会成功返回到用于更改密码的页面。

Here is my AuthenticationService: 这是我的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();
    }
}

Here is my AuthGuard: 这是我的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;
    }
}

The AuthGuard is used like this in the Routes in app.module: AuthGuard在app.module中的Routes中的用法如下:

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

Here is my configurations: 这是我的配置:

{
    "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"
}

I solved the issue. 我解决了这个问题。 Since the user is not loged in when changing the password, my AuthGuard will try to run the login function. 由于更改密码时用户未登录,因此我的AuthGuard将尝试运行登录功能。 To solve this I added a note into session storage when getting the reset password error code, like this: 为了解决这个问题,我在获取重置密码错误代码时在会话存储中添加了一条注释,如下所示:

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

Then I checked for this note in my AuthGuard. 然后,我在AuthGuard中检查了此注释。 If the note is set, then I do not want to run the login function, see below. 如果设置了注释,那么我不想运行登录功能,请参见下文。

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

if (changePassword == null)
  this.authenticationService.login();
else
  sessionStorage.removeItem("changePassword");

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM