Flask+Keycloak:如何让浏览器请求自动携带Bearer认证头
我正在用Flask和Keycloak实现认证,目前通过代码里的resp.set_cookie('jwt_token', jwt_token)把JWT令牌存在Cookie中,浏览器每次请求都会自动携带这个Cookie。但我需要将令牌以Bearer Token的形式放在Authorization请求头里,请问有没有办法像Cookie那样让浏览器后续请求自动携带这个认证头?注:我没有使用前端应用,仅通过浏览器直接访问站点。
我的回调路由代码如下:
@app.route(f'/{url}/callback') def callback(): auth_code = request.args.get('code') token_params = { 'grant_type': 'authorization_code', 'code': auth_code, 'client_id': keycloak_client_id, 'client_secret': keycloak_client_secret, 'redirect_uri': keycloak_redirect_uri.format(rd=request.args.get('rd').replace('/', '%2F')) } response = requests.post(keycloak_token_endpoint, data=token_params) if response.status_code == 200: token_data = response.json() print(token_data) token_data = response.json() jwt_token = token_data.get('access_token') resp = redirect(f'{redirect_host}/{request.args.get("rd").replace("%2F", "/")}') resp.set_cookie('jwt_token', jwt_token) return resp else: return "Authentifizierung fehlgeschlagen"
浏览器默认只会自动携带Cookie,不会主动添加自定义的Authorization请求头。不过可以通过以下几种方式实现类似效果:
1. 服务器端中转:Cookie转Bearer头
如果你的后端接口期望接收Bearer Token,最稳妥的方式是在Flask层做中转:在每个需要认证的请求到达时,从Cookie中取出jwt_token,自动添加到Authorization头里,再转发给业务逻辑(或直接在业务代码中读取Cookie处理)。
示例代码:
from functools import wraps from flask import request # 定义装饰器,自动将Cookie中的令牌转为Bearer头 def cookie_to_bearer(f): @wraps(f) def decorated_function(*args, **kwargs): jwt_token = request.cookies.get('jwt_token') if jwt_token: request.headers['Authorization'] = f'Bearer {jwt_token}' return f(*args, **kwargs) return decorated_function # 在需要认证的路由上使用该装饰器 @app.route('/protected') @cookie_to_bearer def protected_route(): auth_header = request.headers.get('Authorization') return f"已通过认证:{auth_header}"
这种方式对浏览器完全透明,用户正常访问站点即可,浏览器自动携带Cookie,服务器内部完成头信息转换,无需前端介入。
2. 嵌入JavaScript自动添加请求头
如果必须让浏览器主动发送Authorization头,可以在跳转后的HTML页面中嵌入脚本,读取Cookie中的令牌,拦截后续AJAX请求并自动添加请求头。
示例脚本(嵌入到页面的<script>标签中):
<script> // 从Cookie中提取令牌 function getCookie(name) { let value = "; " + document.cookie; let parts = value.split("; " + name + "="); if (parts.length === 2) return parts.pop().split(";").shift(); } const jwtToken = getCookie('jwt_token'); // 拦截fetch请求,添加Authorization头 const originalFetch = window.fetch; window.fetch = function(resource, options = {}) { if (jwtToken) { options.headers = { ...options.headers, 'Authorization': `Bearer ${jwtToken}` }; } return originalFetch(resource, options); }; // 拦截XMLHttpRequest请求 const originalXhrOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { originalXhrOpen.call(this, method, url); if (jwtToken) { this.setRequestHeader('Authorization', `Bearer ${jwtToken}`); } }; </script>
注意:这种方式仅能处理页面内的AJAX请求,无法拦截浏览器原生的页面跳转请求(比如用户点击链接)。
3. 浏览器扩展辅助(开发测试场景)
如果是开发测试阶段需要该功能,可以使用浏览器扩展(如ModHeader)手动配置,让浏览器自动在所有请求中添加Authorization: Bearer <令牌>头。但该方式需要用户手动配置,不适合生产环境的普通用户。
内容的提问来源于stack exchange,提问作者Meeresgott

