2

I have an Angular 2 service that has a logout function. When the function is called from the app component it cause a full page refresh. When using angular 1 projects I haven't experienced this behavior. If I call my logout endpoint with postman the session cookie is deleted. It is not deleted if I use my angular 2 authentication service.

Service

import {Injectable} from 'angular2/core';
import {User} from './user';
import {Headers, RequestOptions, Http, Response} from 'angular2/http';
import {Observable} from 'rxjs/Observable';
import {Cookie} from '../extensions/cookies';

@Injectable()
export class AuthenticationService {

    constructor (private http: Http) {}

    private _prepTestHost = 'http://localhost:8000/';
    private _prepTestLoginUrl = this._prepTestHost + 'login/';
    private _prepTestLogoutUrl = this._prepTestHost + 'logout/';

    private _authenticated: boolean;

    getUser() {}

    isAuthenticated() {
        return this._authenticated;
    }

    setAuthenticated() {
        this._authenticated = true;
    }

    loginUser(username, password) : Observable<User> {
        let body = JSON.stringify({username, password});
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });

        return this.http.post(this._prepTestLoginUrl, body, options)
                                .map(res => <User> res.json(), this.setAuthenticated())
                                .catch(this.handleError)
    }

    logoutUser() : Observable<void> {
        let body = JSON.stringify({});
        let csrfcookie = Cookie.getCookie('csrftoken');
        let headers = new Headers({
            'X-CSRFToken': csrfcookie,
            'Content-Type': 'application/json'
        });
        let options = new RequestOptions({ headers: headers});
        return this.http.post(this._prepTestLogoutUrl, body, options)
                        .map(res => <void> res.json())
                        .catch(this.handleError);

    }

    private handleError (error: Response) {
        // in a real world app, we may send the server to some remote      logging infrastructure
        // instead of just logging it to the console
        console.error(error);
        return Observable.throw(error.json().error || 'Server error');
    }
}

App Component

import {Component} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';

import {WelcomeCenterComponent} from './welcome-center/welcome-center.component';
import {AuthenticationService} from './authentication/authentication.service';
import {LoginModalComponent} from './authentication/login-modal.component';
import {BrowserXhr, HTTP_PROVIDERS} from "angular2/http";
import {CORSBrowserXHR} from './extensions/corsbrowserxhr';
import {provide} from "angular2/core";

@Component({
    selector: 'my-app',
    template: `
    <nav class="navbar navbar-default">
      <div class="container-fluid">
        <div class="navbar-header">
          <a class="navbar-brand" href="#" [routerLink]="['WelcomeCenter']">Brand</a>
        </div>
        <ul class="nav navbar-nav navbar-right">
          <li *ngIf="!authenticated()">
            <a href="#" data-toggle="modal" data-target="#myModal">Login</a>
          </li>
          <li *ngIf="authenticated()">
            <a href="#" data-dismiss="modal" (click)="logout()">Logout</a>
          </li>
        </ul>
      </div>
    </nav>
    <router-outlet></router-outlet>
    <login-modal></login-modal>
    `,
    directives: [ROUTER_DIRECTIVES, LoginModalComponent],
    providers: [HTTP_PROVIDERS,
        provide(BrowserXhr, {useClass: CORSBrowserXHR}),
        AuthenticationService]
})
@RouteConfig([
    {
        path: '/welcome-center/...',
        name: 'WelcomeCenter',
        component: WelcomeCenterComponent,
        useAsDefault: true
    }
])
export class AppComponent {

    constructor(private _authenticationService: AuthenticationService) {}

    authenticated() {
        return this._authenticationService.isAuthenticated();
    }

    logout() {
        console.log("Logout button pressed");
        this._authenticationService.logoutUser().subscribe();
    }
}

Setting withCredentials attribute:

import {BrowserXhr, HTTP_PROVIDERS} from "angular2/http";
import {Injectable, provide} from "angular2/core";

@Injectable()
export class CORSBrowserXHR extends BrowserXhr{
    build(): any{
        var xhr:any = super.build();
        xhr.withCredentials = true;
        return xhr;
    }
}
3
  • is angular throw any error on page refresh ? if yes please post seems same problem i had faced may be ill help you. Commented Feb 13, 2016 at 6:50
  • @PardeepJain There doesn't seem to be an error. My server responds with status 200 and the session is destroyed on the server. Commented Feb 13, 2016 at 15:16
  • ohh okay...i think one more error is there in your logoutUser you .map the observable that return null or void and you subscribe to null. may be this one too produce affect upto some extent chk it again. Commented Feb 13, 2016 at 15:40

2 Answers 2

2

I think that the page reload is due to the fact that you don't prevent event propagation when blocking on the layout button (you an 'a' HTML element with an 'href' attribute). You could use 'return false' at the end of your logout function or '$event.stopPropagation()'.

See the question for more details:

Regarding the cookie problem, I these that you use cross domain requests (CORS). I think that you should try to set to true the 'withCredentials' attribute on the underlying XHR object. See this question for more details:

Sign up to request clarification or add additional context in comments.

2 Comments

it was the href="#" that was causing the page reload. That was masking an error being thrown that I am looking into now.
I was already setting the withCredentials attribute, I've added the code above. `
0

You could do something kind of hacky but I can't think of another way.

Cookie.setCookie(nameOfCookie, "", -1);

This would effectively delete the cookie on logout. I'd love to know if there was a better way though!

I also am not sure why you are getting any kind of page reload at all, I have yet to experience that on anything I've done yet, hopefully someone else will know.

4 Comments

may i know the syntax you posted is javascript's syntax to remove cookie ?
@PardeepJain it comes from an extension in angular2 npmjs.com/package/ng2-cookies, I assumed he was using it as well as he has the same syntax.
@MorganG Removing the href="#" also appears to have let the code that handles clearing the sessionid cookie execute, and correctly remove the cookie. I've never had to manually remove sessionid cookies with angular 1 applications, and now it appears to be the same in angular 2. Thank you for you help. Thierry Templier's answer was correct.
@MichaelB no problem! Thierry usually is correct and has better solutions. Glad he was able to answer your question!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.