Flask中重定向时如何携带JWT认证头访问受保护路由?
问题分析与解决方案
你当前的核心问题是:redirect函数的headers参数是用来设置响应的HTTP头,而非浏览器发起重定向请求时携带的请求头。浏览器执行重定向时,只会自动携带Cookie这类同源凭证,不会将响应头中的Authorization信息传递到新请求里。
以下是几种可行的解决方案:
方案一:将JWT存入HttpOnly Cookie(推荐)
利用浏览器自动携带Cookie的特性,将token存入HttpOnly Cookie(可避免XSS攻击),再让受保护路由从Cookie中提取token完成验证。
修改登录路由
@app.route('/login', methods=['GET', 'POST']) def login(): form = TestLogin() if form.is_submitted(): req = requests.post('http://127.0.0.1:5000/login', json={"email": form.login.data, "senha": form.senha.data}) if req.json()['auth'] == True: token = create_access_token(identity=form.login.data) # 生成重定向响应并设置安全Cookie response = redirect(url_for('membros')) response.set_cookie( 'access_token', value=f'Bearer {token}', httponly=True, # 禁止JS读取,防XSS secure=True, # 生产环境开启,仅HTTPS传输 samesite='Lax' # 降低CSRF风险 ) return response return render_template('test.html', form=form)
自定义JWT验证装饰器
让原@jwt_required()能从Cookie中读取token:
from functools import wraps from flask_jwt_extended import verify_jwt_in_request, get_jwt_identity from flask import request def jwt_required_from_cookie(): def wrapper(fn): @wraps(fn) def decorator(*args, **kwargs): # 从Cookie取token并注入请求头,适配原JWT验证逻辑 token = request.cookies.get('access_token') if token: request.headers['Authorization'] = token verify_jwt_in_request() return fn(*args, **kwargs) return decorator return wrapper # 用自定义装饰器保护路由 @app.route('/membros') @jwt_required_from_cookie() def membros(): current_user = get_jwt_identity() return f"欢迎访问受保护页面,{current_user}!"
方案二:URL参数传递(仅测试用,禁止生产环境使用)
将token作为URL参数传递,受保护路由从参数中提取验证。但此方法会导致token暴露在地址栏、历史记录中,存在严重安全风险。
修改登录路由
@app.route('/login', methods=['GET', 'POST']) def login(): form = TestLogin() if form.is_submitted(): req = requests.post('http://127.0.0.1:5000/login', json={"email": form.login.data, "senha": form.senha.data}) if req.json()['auth'] == True: token = f'Bearer {create_access_token(identity=form.login.data)}' return redirect(url_for('membros', token=token)) return render_template('test.html', form=form)
修改受保护路由
from flask_jwt_extended import decode_token, get_jwt_identity @app.route('/membros') def membros(): token = request.args.get('token') if not token: return redirect(url_for('login')) # 手动验证token try: decode_token(token.replace('Bearer ', '')) current_user = get_jwt_identity() return f"欢迎访问受保护页面,{current_user}!" except: return redirect(url_for('login'))
方案三:前端存储token并发起AJAX请求
若页面需要动态加载内容,可将token注入页面JS,通过AJAX请求受保护API时携带Authorization头:
修改登录路由
@app.route('/login', methods=['GET', 'POST']) def login(): form = TestLogin() if form.is_submitted(): req = requests.post('http://127.0.0.1:5000/login', json={"email": form.login.data, "senha": form.senha.data}) if req.json()['auth'] == True: token = f'Bearer {create_access_token(identity=form.login.data)}' # 将token传入模板 return render_template('membros.html', token=token) return render_template('test.html', form=form)
在membros.html中添加JS
<script> const token = "{{ token }}"; // 发起AJAX请求获取受保护数据 fetch('/api/membros', { headers: { 'Authorization': token } }) .then(res => res.json()) .then(data => { // 处理并渲染数据 console.log(data); }); </script>
内容的提问来源于stack exchange,提问作者Gustavo Nunes
相关产品推荐
相关产品推荐

