Angular is not sending the Cookie received in Set-Cookie even if withCredentials is true

前端 未结 3 2151
南笙
南笙 2020-12-13 09:07

For cookie based authentication, my server sends Set-Cookie to my Angular application. However, the application doesn\'t send the value back in further requests

相关标签:
3条回答
  • 2020-12-13 09:35

    "Set-Cookie" with a flag "HttpOnly" means you can not read the cookie from the client-side.

    0 讨论(0)
  • 2020-12-13 09:40

    Finally I was able to find the issue. The journey was more satisfying than the result so let me break it down into the steps I took to solve my problem.

    In summary, This wansn't an issue with Angular. The cookie I was sending had secureCookie flag on. As I was testing my application without https, it seems that the angular application was not using (or getting access to) the Set-Cookie header received in 200 OK.

    My initial code to send the sign in request to the server and handling its response was

      return this.http.post(this.SIGNIN_USER_URL,body,httpOptions)
          .map(response=>{
            console.log('response from backend service',response);
            let result= <ServerResponse>response; 
            console.log("result is "+result.result+' with additional information '+result.additionalInformation)
            return result;
          })
          .catch(this.handleError);
    

    I wasn't using observe: 'response' option which meant that the response would only contain body, not headers. I changed the code to following so that I could see which headers are being received.

    const httpOptions = {
      headers: new HttpHeaders({ 'Content-Type': 'application/json' }),
     
    withCredentials: true, 
    observe: 'response' as 'response'
    };  
    
    public signinUser(user:UserSigninInfo):any{
        console.log('contacting server at '+this.API_URL +this.SIGNIN_USER_URL +" with user data "+user+ " with httpOptions "+httpOptions.withCredentials + ","+httpOptions.headers ); 
    
        let signinInfo= new UserSignin(user);
        let body = JSON.stringify(signinInfo);
        return this.http.post(this.SIGNIN_USER_URL,body,httpOptions)
          .catch(this.handleError);
      }
    

    The above code was being called as follows. I change that to get the headers in the response

    return this.bs.signinUser(user).subscribe((res:HttpResponse<any>)=>{console.log('response from server:',res);
      console.log('response headers',res.headers.keys())
    } );
    

    I also created an intercepter to print the incoming and outgoing messages (copied from SO)

    import {HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse} from "@angular/common/http";
    import {Injectable} from "@angular/core";
    import {Observable} from "rxjs/Observable";
    import 'rxjs/add/operator/do';
    
    @Injectable()
    export class CustomInterceptor implements HttpInterceptor {
    
      constructor() {
      }
    
      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    
        console.log("outgoing request",request);
        request = request.clone({
          withCredentials: true
        });
        console.log("new outgoing request",request);
    
        return next
          .handle(request)
          .do((ev: HttpEvent<any>) => {
            console.log("got an event",ev)
            if (ev instanceof HttpResponse) {
              console.log('event of type response', ev);
            }
          });
      }
    }
    

    When I started debugging, I noticed that though the server was sending 10 headers, only 9 were getting printed

    headers from server

    Print message on console (Set-Cookie was missing! The header my application needed to get authentication cookie)

    0: "Content-Length"
    ​
    1: "Content-Security-Policy"
    ​
    2: "Content-Type"
    ​
    3: "Date"
    ​
    4: "Referrer-Policy"
    ​
    5: "X-Content-Type-Options"
    ​
    6: "X-Frame-Options"
    ​
    7: "X-Permitted-Cross-Domain-Policies"
    ​
    8: "X-XSS-Protection"
    ​
    length: 9
    

    This gave me a direction that the application is not seeing Set-Cookie header. I thought I'll be able to resolve it by adding CORS policy in play framework exposedHeaders = ["Set-Cookie"] but that didnt work. Later I looked closer at the cookie and noticed secureCookie setting

    Set-Cookie: id=...Secure; HTTPOnly
    

    This made me think that maybe my cookie settings are wrong for my environment (localhost, no HTTPS). I changed the cookie settings in Silhoutte

    val config =  CookieAuthenticatorSettings(secureCookie=false)
    

    And it worked!

    Though I'll make the above code work for secureCookie and this wasn't an issue with Angular, I hope that some folks might find the approach helpful

    0 讨论(0)
  • 2020-12-13 09:52

    i assume you using nodejs and express-session for manage session then in express-session httpOnly are by default enabled so you have to change httpOnly for console sever sent cookie

    const app = require('express')();
    var session = require('express-session');
    var cookieParser = require('cookie-parser');

    app.use(session( { secret:'hello world',
    store:SessionStore,
    resave:false,
    cookie:{
    secure:false,
    httpOnly:false // by default it's boolean value true }
    }));

    in the below image httpOnly are true, so you can't be console this cookie.

    in the below image httpOnly are false , so you can console this cookie.

    0 讨论(0)
提交回复
热议问题