我有一个使用 Flask-Security 扩展的 Flask 应用程序。以下是我的应用程序的初始化方式:
app = Flask(__name__)
app.config['DEBUG'] = True
CORS(app)
CSRFProtect(app)
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'pf9Wkove4IKEAXvy-cQkeDPhv9Cb3Ag-wyJILbq_dFw')
app.config['SECURITY_PASSWORD_SALT'] = os.environ.get("SECURITY_PASSWORD_SALT", '146585145368132386173505678016728509634')
app.config["SECURITY_EMAIL_VALIDATOR_ARGS"] = {"check_deliverability": False}
app.teardown_appcontext(lambda exc: db_session.close())
# Setup Flask-Security
user_datastore = SQLAlchemySessionUserDatastore(db_session, User, Role)
app.security = Security(app, user_datastore)
我还有另一个基于 Angular 的应用程序与 Flask 应用程序进行通信。在
OnInit
函数中,我确保提供了 CSRF 令牌:
this.http.get("http://localhost:5000/login")
.subscribe({
next: (response: any) => {
let crsftoken = response.response.csrf_token;
console.log("CRFS TOKEN aus GET" + crsftoken);
localStorage.setItem("crsftoken", crsftoken);
},
// ...
});
这工作正常,但是当我尝试使用登录表单登录用户时,CSRF 令牌似乎没有包含在请求中。这是提交表单时执行的代码:
const formData = new FormData();
formData.append('email', this.loginForm.controls.username.value || "");
formData.append('password', this.loginForm.controls.password.value || "");
this.http.post("http://localhost:5000/login", formData)
.subscribe({
next: (response: any) => {
console.log(response);
},
// ...
});
当我执行此代码时,我收到“错误请求”响应,其中包含消息“CSRF 会话令牌丢失”。会话令牌似乎没有随请求一起发送,但我不确定为什么。
在第一次调用“http://localhost:5000/login”的
GET
方法期间,我可以在响应和 Set-Cookie
标头中看到会话。但是,它似乎没有存储在浏览器中。因此,它不会随后续请求一起发送。
添加:当然,我使用 HTTP 拦截器将 Csrf-Token 放入每个请求的标头中,请参阅:
@Injectable()
export class AuthInterceptor implements HttpInterceptor {
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let crsftoken = localStorage.getItem('crsftoken');
let headers = request.headers;
headers = headers.set("X-CSRF-TOKEN", crsftoken || "");
request = request.clone({
headers : headers
});
return next.handle(request);
}
}
我做错了什么?也许我误解了 CSRF 令牌和 CSRF 会话令牌之间的区别? 任何见解或建议将不胜感激。谢谢!
关于执行此操作的方法有相当完整的文章:https://flask-security-too.readthedocs.io/en/stable/patterns.html#csrf
一种方法 - 获取您收到的 CSRF 令牌并将其作为“X-CSRF-Token”发送。 会话 cookie 确实需要发送 - 但我会确保首先正确发送您的 CSRF 令牌。
引用的文档还解释了如何使用 cookie 来执行此操作 - Angular (httpclient) 内置了对此的支持。