Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IdentityServer4 oidc w/ angular2 Guard Always False

I have identity successfully authenticating a user, it passes the user back to the main site which runs

<script src="https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.2.2/oidc-client.min.js"></script>
<h1 id="waiting">Waiting...</h1>
<div id="error"></div>
<script>
    new Oidc.UserManager().signinRedirectCallback().then(function (user) {
        if (user == null) {
            document.getElementById("waiting").style.display = "none";
            document.getElementById("error").innerText = "No sign-in request pending.";
        }
        else {
            window.location = "/";
        }
    })
    .catch(function (er) {
        document.getElementById("waiting").style.display = "none";
        document.getElementById("error").innerText = er.message;
    });
</script>

But when it its the home page "/" it keeps going back to unauthenticated because of

 import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { UniversalModule } from 'angular2-universal';

import { AppComponent } from './components/app/app.component';
import { HomeComponent } from './components/home/home.component';
import { UnauthorizedComponent } from './components/unauthorized/unauthorized.component';

import { AuthService } from './services/shared/auth.service';
import { AuthGuardService } from './services/shared/auth-guard.service';

@NgModule({
    bootstrap: [ AppComponent ],
    declarations: [
        AppComponent,
        HomeComponent, 
        UnauthorizedComponent
    ],
    imports: [
        UniversalModule, // Must be first import. This automatically imports          BrowserModule, HttpModule, and JsonpModule too.
        RouterModule.forRoot([
            {
                path: '', redirectTo: 'home', pathMatch: 'full'
            },
            {
                path: 'home',
                component: HomeComponent,
                canActivate: [AuthGuardService]
            },
            {
                path: 'unauthorized',
                component: UnauthorizedComponent
            }
        ])
    ],
    providers: [AuthService, AuthGuardService]
})
export class AppModule {
}

Where AuthGuard is

    import { Injectable } from '@angular/core';
import { CanActivate, Router } from '@angular/router';

import { AuthService } from './auth.service';

@Injectable()
export class AuthGuardService implements CanActivate {

    constructor(private authService: AuthService, private router: Router) {
    }
    canActivate() {
        if (this.authService.loggedIn)
        {
            alert("this"); //<--- never happens 
            return true;
        }
      alert(this.authService.loggedIn); //<---  always false, happens before everything else?
        this.router.navigate(['unauthorized']);

    }
}

And where AuthService is

    import { Injectable, EventEmitter } from '@angular/core';
import { Http, Headers, RequestOptions, Response } from '@angular/http';
import { Observable } from 'rxjs/Rx';

import { UserManager, Log, MetadataService, User } from 'oidc-client';

@Injectable()
export class AuthService {
    mgr: UserManager = new UserManager(settings);
    userLoadededEvent: EventEmitter<User> = new EventEmitter<User>();
    currentUser: User;
    loggedIn: boolean = false;

    authHeaders: Headers;


    constructor(private http: Http) {
        this.mgr.getUser()
            .then((user) => {
                if (user) {
                    this.loggedIn = true;
                    alert("loggedin"); //<--- Happens all the time
                    this.currentUser = user;
                    this.userLoadededEvent.emit(user);
                }
                else {
                    this.loggedIn = false;
                }
            })
            .catch((err) => {
                this.loggedIn = false;
            });
        this.mgr.events.addUserUnloaded((e) => {
            this.loggedIn = false;
        });
    }
    clearState() {
        this.mgr.clearStaleState().then(function () {
            console.log("clearStateState success");
        }).catch(function (e) {
            console.log("clearStateState error", e.message);
        });
    }

    getUser() {
        this.mgr.getUser().then((user) => {
            console.log("got user", user);
            this.userLoadededEvent.emit(user);
        }).catch(function (err) {
            console.log(err);
        });
    }

    removeUser() {
        this.mgr.removeUser().then(() => {
            this.userLoadededEvent.emit(null);
            console.log("user removed");
        }).catch(function (err) {
            console.log(err);
        });
    }

    startSigninMainWindow() {
        this.mgr.signinRedirect({ data: 'some data' }).then(function () {
            console.log("signinRedirect done");
        }).catch(function (err) {
            console.log(err);
        });
    }
    endSigninMainWindow() {
        this.mgr.signinRedirectCallback().then(function (user) {
            console.log("signed in", user);
        }).catch(function (err) {
            console.log(err);
        });
    }

    startSignoutMainWindow() {
        this.mgr.signoutRedirect().then(function (resp) {
            console.log("signed out", resp);
            setTimeout(5000, () => {
                console.log("testing to see if fired...");

            })
        }).catch(function (err) {
            console.log(err);
        });
    };

    endSignoutMainWindow() {
        this.mgr.signoutRedirectCallback().then(function (resp) {
            console.log("signed out", resp);
        }).catch(function (err) {
            console.log(err);
        });
    };
    /**
     * Example of how you can make auth request using angulars http methods.
     * @param options if options are not supplied the default content type is application/json
     */
    AuthGet(url: string, options?: RequestOptions): Observable<Response> {

        if (options) {
            options = this._setRequestOptions(options);
        }
        else {
            options = this._setRequestOptions();
        }
        return this.http.get(url, options);
    }
    /**
     * @param options if options are not supplied the default content type is application/json
     */
    AuthPut(url: string, data: any, options?: RequestOptions): Observable<Response> {

        let body = JSON.stringify(data);

        if (options) {
            options = this._setRequestOptions(options);
        }
        else {
            options = this._setRequestOptions();
        }
        return this.http.put(url, body, options);
    }
    /**
     * @param options if options are not supplied the default content type is application/json
     */
    AuthDelete(url: string, options?: RequestOptions): Observable<Response> {

        if (options) {
            options = this._setRequestOptions(options);
        }
        else {
            options = this._setRequestOptions();
        }
        return this.http.delete(url, options);
    }
    /**
     * @param options if options are not supplied the default content type is application/json
     */
    AuthPost(url: string, data: any, options?: RequestOptions): Observable<Response> {

        let body = JSON.stringify(data);

        if (options) {
            options = this._setRequestOptions(options);
        }
        else {
            options = this._setRequestOptions();
        }
        return this.http.post(url, body, options);
    }


    private _setAuthHeaders(user: any) {
        this.authHeaders = new Headers();
        this.authHeaders.append('Authorization', user.token_type + " " + user.access_token);
        this.authHeaders.append('Content-Type', 'application/json');
    }
    private _setRequestOptions(options?: RequestOptions) {

        if (options) {
            options.headers.append(this.authHeaders.keys[0], this.authHeaders.values[0]);
        }
        else {
            options = new RequestOptions({ headers: this.authHeaders, body: "" });
        }

        return options;
    }

}

const settings: any = {
    authority: 'http://localhost:5000/',
    client_id: 'js',
    redirect_uri: 'http://localhost:38881/auth',
    post_logout_redirect_uri: 'http://localhost:38881/',
    response_type: 'id_token token',
    scope: 'openid profile api',

    silent_redirect_uri: 'http://localhost:38881',
    automaticSilentRenew: true,
    //silentRequestTimeout:10000,

    filterProtocolClaims: true,
    loadUserInfo: true
};

The problem is that any attempt to go to home or / results in going to unauthorized even though alert("loggedin"); happens

It seems like
alert(this.authService.loggedIn); //<--- always false, happens before everything else, which is the issue why is canactive going even though the result from authservice hasn't returned

like image 436
Ya Wang Avatar asked May 26 '26 04:05

Ya Wang


1 Answers

I had the same issue. The problem is that the Promise in the AuthService constructor is resolved after AuthGuardService checks whether the user is logged in. To fix this I created a new function in the AuthService:

isLoggedIn(): Observable<boolean> {
  return Observable.fromPromise(this.mgr.getUser()).map<User, boolean>((user) => {
    if (user) return true;
    else return false;
  });
}

Then, rewrite the canActivate function of the AuthGuardService to use the isLoggedIn() function instead of relying on the AuthService constructor:

canActivate() {
    let self = this;
    let isloggedIn = this.authService.isLoggedIn();
    isloggedIn.subscribe((loggedin) => {
        if(!loggedin){
            self.router.navigate(['unauthorized']);
        }
    });
    return isloggedIn;
}

This canActivate implementation returns an Observable instead of a boolean, to let it wait for the Promise in the AuthService to complete. There is also a subscription so we can decide whether to redirect to unauthorized or not.

Also see this issue: https://github.com/jmurphzyo/Angular2OidcClient/issues/21

like image 149
Sigge Avatar answered May 28 '26 17:05

Sigge



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!