2

I've been looking all around for session based authentication with Angular 2.

I'm building an application that has Django on backend and Angular 2 on the frontend. To keep the process simple I'm trying to implement Django session authentication.

// Angular 2 authentication service
import { Injectable } from "@angular/core";
import { Headers, Http, Response } from "@angular/http";

import "rxjs/add/operator/toPromise";
import 'rxjs/add/operator/map'

import { AppSettings } from "../../app.settings";

@Injectable()
export class UserAuthService {
    private headers = new Headers({'Content-Type': 'application/json'});

    private loginUrl = `${AppSettings.BACKEND_URL}` + '/api/v1/users/login/';

    constructor(
        private http: Http
    ) { }

    login(username, password) {
        let data = {
            username: username,
            password: password
        };
        return this.http.post(this.loginUrl, data, this.headers)
            .map((response: Response) => response.json());
    }
}

# Django Login view
def login(self, request):
        username = request.data['username']
        password = request.data['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            login(request, user)
            serializer = self.serializer_class(user)
            return Response(serializer.data, status=status.HTTP_200_OK)
        raise AuthenticationFailed

I'm successfully calling backend API and my login view returns the successful response.

Also request.user gets updated after the login but when I try to call the other APIs using Angular or directly browse Django rest API user is not logged in.

Marcs
  • 3,768
  • 5
  • 33
  • 42
Sadan A.
  • 1,017
  • 1
  • 10
  • 28
  • Where do you store login status? how do you let know other components/services about login status? do you set header or send token back to api? Please edit your question and add related code. – Sefa Nov 02 '16 at 13:35
  • I don't want to use tokens here. I've added my component where i am storing user (response of login API) in localStorage. – Sadan A. Nov 02 '16 at 13:44
  • i guess angular 2 can't see the cookies because they are not on the same domain (or port). for instance, maybe you can have your api on example.com and angular 2 on example.com/frontend, and change the base attribute in angular's index.html to "/frontend" or whatever the name you used. – shehata Dec 04 '16 at 13:03
  • Did you ever solve this? – user2061057 Mar 20 '17 at 17:11
  • Yes, look at my answer. – Sadan A. Mar 22 '17 at 04:43

1 Answers1

0

The answer to this question is to append CSRF token to the X-CSRF header, because django uses X-CSRF token header to verify the sessions.

I don't exactly remember where I saw this but Iachieved this by using angular2-cookie and writing a custom request options service like this

// Custom request options service
import { CookieService } from "angular2-cookie/services/cookies.service";
import { Headers, RequestOptions } from "@angular/http";
import { Injectable } from "@angular/core";

@Injectable()
export class CustomRequestOptionsService {

    constructor(
        private cookieService: CookieService
    ) { }

    defaultRequestOptions() {
        return new RequestOptions({
            headers: new Headers({
                'Content-Type': 'application/json',
            }),
            withCredentials: true
        });
    }

    authorizationRequestOptions() {
        return new RequestOptions({
            headers: new Headers({
                'Content-Type': 'application/json',
                'X-CSRFToken': this.cookieService.get('csrftoken')
            }),
            withCredentials: true
        });
    }
}

and then in your service where you hit secure APIs use it like this

// Officer service
import { Http, Response} from "@angular/http";
import { Injectable } from "@angular/core";
import "rxjs/add/operator/map";

// Services
import { CustomRequestOptionsService } from "../shared/custom-request-options.service";

@Injectable()
export class OfficerService {
    private officerDashboardUrl = `http://${process.env.API_URL}` + '/api/v1/officers/detail';

    constructor(
        private http: Http,
        private customRequestOptionService: CustomRequestOptionsService
    ) { }

    getOfficer(officerId: number) {
        return this.http.get(`${this.officerDashboardUrl}/${officerId}/`,
            this.customRequestOptionService.authorizationRequestOptions())
                   .toPromise()
                   .then((response: Response) => {
                       return response.json();
                   })
                   .catch((error: any) => {
                       return Promise.reject(error.message || error)
                   });
    }
}
Sadan A.
  • 1,017
  • 1
  • 10
  • 28
  • For this to work both Django and your Angular 5 app have to be running on the same domain, right? – NotSimon Apr 14 '18 at 19:45
  • I think this should work when you run both on different server as well, but i was running both on the same server. – Sadan A. Apr 16 '18 at 17:32