Python 未在浏览器中设置身份验证登录Cookies-Flask后端API+;角7前端

Python 未在浏览器中设置身份验证登录Cookies-Flask后端API+;角7前端,python,angular,flask,angular-httpclient,flask-jwt-extended,Python,Angular,Flask,Angular Httpclient,Flask Jwt Extended,我正在使用一个有角度前端的Flask后端api构建一个Web应用程序。API在上运行,前端在上运行 由于某些原因,浏览器中未设置Cookie。浏览器标题似乎是正确的,但在检查chrome devtools-->应用程序-->存储-->Cookies时,我看不到设置了任何cookie 我错过了什么 相关部分: from octowc.web_app.resources import ( Test, Refresh, Login, Logout ) from flask import

我正在使用一个有角度前端的Flask后端api构建一个Web应用程序。API在上运行,前端在上运行

由于某些原因,浏览器中未设置Cookie。浏览器标题似乎是正确的,但在检查chrome devtools-->应用程序-->存储-->Cookies时,我看不到设置了任何cookie

我错过了什么

相关部分:

from octowc.web_app.resources import (
    Test, Refresh, Login,
    Logout
)
from flask import (
    Flask, render_template
)
from flask_jwt_extended import JWTManager
from flask_sqlalchemy import SQLAlchemy, sqlalchemy
from octowc.config import Config
from flask_cors import CORS
from flask_restful import Api


app = Flask(__name__)
api = Api(app)
jwt = JWTManager(app)
CORS(app, origins=['http://localhost:4200']

# JWT token configuration
app.config['JWT_SECRET_KEY'] = conf.jwt_secret_key
app.config['JWT_TOKEN_LOCATION'] = ['cookies']
app.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
app.config['JWT_REFRESH_COOKIE_PATH'] = '/token'
app.config['JWT_COOKIE_CSRF_PROTECT'] = True
app.config['JWT_COOKIE-DOMAIN'] = 'localhost'
app.config['JWT_COOKIE_SECURE'] = False
app.config['CSRF_IN_COOKIES'] = False

api.add_resource(Refresh, '/token/refresh')
api.add_resource(Test, '/api/test')
api.add_resource(Login, '/login')
api.add_resource(Logout, '/logout')


class Refresh(Resource):
    @jwt_refresh_token_required
    def post(self):
        user = get_jwt_identity()
        refresh_token = create_access_token(identity=user)
        resp = jsonify({'refresh': True})
        set_access_cookies(resp, refresh_token)
        return resp


class Test(Resource):
    @jwt_required
    def get(self):
        resp = {'Test': 'Successfull!'}
        return resp

    @jwt_required
    def post(self):
        resp = {'Test': 'Successfull!'}
        return resp


class Logout(Resource):
    def post(self):
        resp = jsonify({'Logout:': True})
        unset_jwt_cookies(resp)
        return resp


class Login(Resource):

    parser = reqparse.RequestParser()
    parser.add_argument(
        'username',
        type=str,
        required=True
    )
    parser.add_argument(
        'password',
        type=str,
        required=True
    )

    def post(self):
        try:
            data = Login.parser.parse_args()
        except BadRequest as _:
            return {'Error': 'Bad request'}, 400

        username = data['username']
        password = data['password']
        if username != 'test' or password != 'test':
            return {'Error': 'Credentials incorrect'}, 401

        access_token = create_access_token(identity=username)
        refresh_token = create_refresh_token(identity=username)
        resp = jsonify({'Login': True})
        set_access_cookies(resp, access_token)
        set_refresh_cookies(resp, refresh_token)
        return resp
相关角部:

auth.service.ts

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie-service';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
import { JwtHelperService } from '@auth0/angular-jwt';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    withCredentials: 'true'
  })
};

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  baseUrl = environment.apiUrl;
  jwtHelper = new JwtHelperService();
  decodedToken: any;

  constructor(
    private http: HttpClient,
    private cookieService: CookieService,
    private router: Router) { }

  login(model: any) {
    return this.http.post(this.baseUrl + 'login', model, httpOptions);
      .pipe(
        map((response: any) => {
          console.log(response);
  }))};

  logOut() {
    this.cookieService.deleteAll('/', 'localhost');
  }

  isLoggedIn() {
    const cookie = this.cookieService.get('access_token');
    return !!cookie;
  }

  getCSRFToken(type: string) {
    return this.cookieService.get(`csrf_${type}_token`);
  }

  getCookie(type: string) {
    return this.cookieService.get(`${type}_token`);
  }
}
Request URL: http://localhost:5000/login
Request Method: POST
Status Code: 200 OK
Remote Address: 127.0.0.1:5000
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: http://localhost:4200
Content-Length: 20
Content-Type: application/json
Date: Sat, 04 May 2019 08:09:48 GMT
Server: Werkzeug/0.15.2 Python/3.7.3
Set-Cookie: access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTY5NTczODgsIm5iZiI6MTU1Njk1NzM4OCwianRpIjoiMTRhZGFkNjEtMTdjYi00NGMwLTg4NjctNGJiOTZiZmY0OGY2IiwiZXhwIjoxNTU2OTU4Mjg4LCJpZGVudGl0eSI6InRlc3QiLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MiLCJjc3JmIjoiODFlNjYxZmYtZTcxNy00ZmY0LTkxNGItN2EzZWZjZTE5MmM2In0.TV7K2RXDMQsmmmrsmaFiLv6CwmB-Wg5DIdkWfv3IEMI; HttpOnly; Path=/api/
Set-Cookie: csrf_access_token=81e661ff-e717-4ff4-914b-7a3efce192c6; Path=/
Set-Cookie: refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTY5NTczODgsIm5iZiI6MTU1Njk1NzM4OCwianRpIjoiOGVhNWVjNWItMDg5Ny00ZTA2LWIxYWItYjkxNGVhZjI4MjE2IiwiZXhwIjoxNTU5NTQ5Mzg4LCJpZGVudGl0eSI6InRlc3QiLCJ0eXBlIjoicmVmcmVzaCIsImNzcmYiOiJlYzYyMDBkYi1lNmJkLTQ4MDktOTM5Yi01YWZjMWZiZjBlZjAifQ.1kt9N4DTBGH27eBDiz8fiLAiiWPNiEN9q2ddpgCkMw0; HttpOnly; Path=/token
Set-Cookie: csrf_refresh_token=ec6200db-e6bd-4809-939b-5afc1fbf0ef0; Path=/
Vary: Origin
POST /login HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Content-Length: 37
Accept: application/json, text/plain, */*
Origin: http://localhost:4200
withCredentials: true
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.59
Content-Type: application/json
Referer: http://localhost:4200/login?returnUrl=%2Fhome
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
{username: "test", password: "test"}
password: "test"
username: "test"
浏览器标题

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { CookieService } from 'ngx-cookie-service';
import { Router } from '@angular/router';
import { environment } from 'src/environments/environment';
import { JwtHelperService } from '@auth0/angular-jwt';

const httpOptions = {
  headers: new HttpHeaders({
    'Content-Type': 'application/json',
    withCredentials: 'true'
  })
};

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  baseUrl = environment.apiUrl;
  jwtHelper = new JwtHelperService();
  decodedToken: any;

  constructor(
    private http: HttpClient,
    private cookieService: CookieService,
    private router: Router) { }

  login(model: any) {
    return this.http.post(this.baseUrl + 'login', model, httpOptions);
      .pipe(
        map((response: any) => {
          console.log(response);
  }))};

  logOut() {
    this.cookieService.deleteAll('/', 'localhost');
  }

  isLoggedIn() {
    const cookie = this.cookieService.get('access_token');
    return !!cookie;
  }

  getCSRFToken(type: string) {
    return this.cookieService.get(`csrf_${type}_token`);
  }

  getCookie(type: string) {
    return this.cookieService.get(`${type}_token`);
  }
}
Request URL: http://localhost:5000/login
Request Method: POST
Status Code: 200 OK
Remote Address: 127.0.0.1:5000
Referrer Policy: no-referrer-when-downgrade
Access-Control-Allow-Origin: http://localhost:4200
Content-Length: 20
Content-Type: application/json
Date: Sat, 04 May 2019 08:09:48 GMT
Server: Werkzeug/0.15.2 Python/3.7.3
Set-Cookie: access_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTY5NTczODgsIm5iZiI6MTU1Njk1NzM4OCwianRpIjoiMTRhZGFkNjEtMTdjYi00NGMwLTg4NjctNGJiOTZiZmY0OGY2IiwiZXhwIjoxNTU2OTU4Mjg4LCJpZGVudGl0eSI6InRlc3QiLCJmcmVzaCI6ZmFsc2UsInR5cGUiOiJhY2Nlc3MiLCJjc3JmIjoiODFlNjYxZmYtZTcxNy00ZmY0LTkxNGItN2EzZWZjZTE5MmM2In0.TV7K2RXDMQsmmmrsmaFiLv6CwmB-Wg5DIdkWfv3IEMI; HttpOnly; Path=/api/
Set-Cookie: csrf_access_token=81e661ff-e717-4ff4-914b-7a3efce192c6; Path=/
Set-Cookie: refresh_token_cookie=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NTY5NTczODgsIm5iZiI6MTU1Njk1NzM4OCwianRpIjoiOGVhNWVjNWItMDg5Ny00ZTA2LWIxYWItYjkxNGVhZjI4MjE2IiwiZXhwIjoxNTU5NTQ5Mzg4LCJpZGVudGl0eSI6InRlc3QiLCJ0eXBlIjoicmVmcmVzaCIsImNzcmYiOiJlYzYyMDBkYi1lNmJkLTQ4MDktOTM5Yi01YWZjMWZiZjBlZjAifQ.1kt9N4DTBGH27eBDiz8fiLAiiWPNiEN9q2ddpgCkMw0; HttpOnly; Path=/token
Set-Cookie: csrf_refresh_token=ec6200db-e6bd-4809-939b-5afc1fbf0ef0; Path=/
Vary: Origin
POST /login HTTP/1.1
Host: localhost:5000
Connection: keep-alive
Content-Length: 37
Accept: application/json, text/plain, */*
Origin: http://localhost:4200
withCredentials: true
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36 OPR/60.0.3255.59
Content-Type: application/json
Referer: http://localhost:4200/login?returnUrl=%2Fhome
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
{username: "test", password: "test"}
password: "test"
username: "test"

我认为前端和后端需要由同一主机提供服务 和Cookie工作的端口。我认为有一个网页包代理插件 为了解决这个问题——vimalloc 22小时前 webpack.js.org/configuration/dev server/#devserver proxy–vimalloc 22 几小时前

谢谢你给我指明了正确的方向!设置代理成功了。事实证明,您还可以使用Angular CLI设置一个

谢谢大家!


我认为前端和后端需要由同一主机提供服务 和Cookie工作的端口。我认为有一个网页包代理插件 为了解决这个问题——vimalloc 22小时前 webpack.js.org/configuration/dev server/#devserver proxy–vimalloc 22 几小时前

谢谢你给我指明了正确的方向!设置代理成功了。事实证明,您还可以使用Angular CLI设置一个


谢谢大家!

请尝试通过以下命令在https中为您的应用程序提供服务
ng serve--ssl true
,并检查我认为前端和后端需要从同一主机和端口提供服务,才能使Cookie正常工作。我认为有一个webpack代理插件可以处理这个问题。请尝试通过以下命令使用https为您的应用程序提供服务
ng serve--ssl true
,然后检查我认为前端和后端需要从同一主机和端口提供服务,cookie才能工作。我认为有一个网页包代理插件来处理这个问题。