TIdHttp重定向时自定义Authorization头认证异常求助
从你提供的日志来看,问题的根源非常清晰:你的Authorization头被Indy自动带到了重定向后的Azure Blob存储请求中,但Blob服务并不接受Bearer Token认证。
问题分析
原API返回301重定向到Azure Blob的URL,这个URL已经包含了完整的SAS(Shared Access Signature)参数(就是URL里的sig=部分),这是Azure Blob合法的认证方式。但你的TIdHttp在重定向时,把原请求的Authorization: Bearer mysecrettoken头也一起发送给了Blob服务器,而Blob服务识别不了这种Bearer Token格式,于是返回InvalidAuthenticationInfo错误。
解决方案
你需要告诉TIdHttp:当重定向到不同主机时,不要携带Authorization头。这可以通过TIdHttp.OnRedirect事件来实现,在事件中检查目标URL的主机是否和原请求一致,不一致就移除Authorization头。
修改你的代码如下:
procedure APIRequest(const url, token: string; request, response: TStream); var http: TIdHttp; ssl: TIdSSLIOHandlerSocketOpenSSL; OriginalHost: string; begin http := TIdHttp.Create(nil); ssl := TIdSSLIOHandlerSocketOpenSSL.Create(http); try ssl.SSLOptions.SSLVersions := [sslvTLSv1_2]; http.IOHandler := ssl; http.HandleRedirects := true; http.Request.CustomHeaders.Clear; http.Request.Accept := 'application/json'; http.Request.CustomHeaders.FoldLines := false; http.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + token; // 获取原请求的主机名 OriginalHost := TIdURI.Create(url).Host; // 绑定重定向事件 http.OnRedirect := procedure(Sender: TObject; var dest: string; var NumRedirect: Integer; var Handled: Boolean; var VMethod: string) var RedirectURI: TIdURI; begin RedirectURI := TIdURI.Create(dest); try // 如果重定向目标主机和原主机不同,移除Authorization头 if RedirectURI.Host <> OriginalHost then begin (Sender as TIdHttp).Request.CustomHeaders.Values['Authorization'] := ''; end; finally RedirectURI.Free; end; end; try if request = nil then http.Get(url, response) else http.Post(url, request, response); except on e: EIdHTTPProtocolException do begin if response is TStringStream then (response as TStringStream).WriteString(e.ErrorMessage); end; end; finally http.Free; end; end;
补充说明
- 安全角度:跨主机携带Authorization头本身就是不安全的行为,可能导致敏感的Token泄露给第三方服务器,所以这个处理方式也符合安全最佳实践。
- Indy默认行为:Indy的
HandleRedirects默认会保留所有自定义头,包括Authorization,这在同主机重定向时是合理的,但跨主机时就会出问题。 - Azure Blob认证:Blob存储的认证要么用SAS参数,要么用Account Key生成的Authorization头(格式是
Authorization: SharedKey <account>:<signature>),绝对不会接受Bearer Token,所以必须移除原头。
这样修改后,重定向到Blob存储时就不会携带Bearer Token,而是使用URL中的SAS参数进行认证,就能正常获取到文件了。
内容的提问来源于stack exchange,提问作者complete_stranger
相关产品推荐
相关产品推荐

