Apache HUE REST API登录后请求被重定向至登录页问题求助
Troubleshooting Django CSRF/Session Issues with Apache Hue REST API
看起来你碰到了我之前也踩过的坑——明明登录请求显示成功,但后续所有请求都被判定为匿名用户,直接重定向到登录页。结合你的代码、日志和Hue的Django底层逻辑,我帮你拆解几个核心排查点和修复方案:
1. 先解决Session ID的核心问题
日志里的-anon-是关键信号:后端完全没识别到你的会话,大概率是sessionid cookie没被正确传递或者后端没接收。你需要检查这几点:
- 登录响应里的
sessionid是否被正确提取到accessToken中?在getAccessToken里打印所有返回的cookie,确认sessionid存在且值正确。 - 后续请求中,
sessionid的Domain、Path、HttpOnly属性必须和登录响应里的完全一致!比如Hue默认设置SESSION_COOKIE_PATH=/,你的请求不能私自改Path;如果是容器部署(比如日志里的172.17.0.1是容器网关),要确保Cookie的Domain匹配Hue的实际访问域名/IP。 - 确认代码里
cookie(accessToken.sessionid)的调用逻辑:有些HTTP客户端库需要显式指定cookie名称和值,比如要写成cookie("sessionid", accessToken.sessionid.getValue)这种形式,而不是直接传对象。
2. 调整CSRF Token的使用逻辑
Django的CSRF保护是和Session绑定的,光传对token还不够:
- 登录成功后,Django可能会刷新CSRF token!你现在用的是登录前从登录页获取的token,后续请求应该用登录响应里返回的新token,而不是旧的。
- 确保
X-CSRFToken头的值和csrftokencookie的值完全一致,大小写、空格都不能错。 - 注意:你访问的
/filebrowser/view=是GET请求,Django默认对GET不做CSRF验证,所以这个问题更可能是Session导致的,而非CSRF直接触发,但token绑定Session的逻辑还是要做对。
3. 修正请求头的细节错误
你复制了Chrome的请求头,但有几个容易忽略的坑:
- Host头:必须和Hue配置的
ALLOWED_HOSTS匹配!如果Hue部署在容器里,ALLOWED_HOSTS要包含172.17.0.1或者*(测试环境),否则Django会拒绝会话。 - X-Requested-With:你加了
XMLHttpRequest,但浏览器访问普通HTML页面时不会带这个头,后端可能会把它当成AJAX请求处理,导致会话逻辑异常,建议去掉这个头。 - *Sec-Fetch-系列头:浏览器访问页面时,
Sec-Fetch-Dest是document、Sec-Fetch-Mode是navigate,而不是你写的empty和cors,这些头会影响后端的请求识别。
4. 检查Hue的配置陷阱
Hue的几个配置会直接影响会话和CSRF:
- 确认
desktop.ini里的SESSION_COOKIE_SECURE是否为false(如果用HTTP访问),设置为true会让浏览器拒绝发送session cookie。 - 同理,
CSRF_COOKIE_SECURE也要对应HTTP/HTTPS场景调整。 - 查看
SESSION_EXPIRE_AT_BROWSER_CLOSE,不过这个应该不会影响刚登录后的请求。
修复后的代码示例参考
调整登录和请求逻辑,确保会话和token正确传递:
// 登录方法:正确提取登录后的session和新CSRF token def login(): AccessToken = { // 1. 获取登录页的初始CSRF token val loginPageResp = Http(s"$baseUrl/accounts/login/?next=/").asString val initialCsrf = loginPageResp.cookies.find(_.name == "csrftoken").get // 2. 提交登录表单 val loginPostResp = Http(s"$baseUrl/accounts/login/") .postForm(Seq( "username" -> username, "password" -> password, "csrfmiddlewaretoken" -> initialCsrf.value, "next" -> "/" )) .cookie(initialCsrf) .asString // 3. 提取登录后返回的sessionid和新CSRF token val sessionId = loginPostResp.cookies.find(_.name == "sessionid").get val newCsrf = loginPostResp.cookies.find(_.name == "csrftoken").getOrElse(initialCsrf) AccessToken(newCsrf, sessionId) } // 访问受保护页面的调整 def getDir(hdfsPathDirParent: String): Unit = { val accessToken = login() val response = Http(s"$baseUrl/filebrowser/view=$hdfsPathDirParent") // 按浏览器顺序传递cookie:先sessionid,后csrftoken .cookie("sessionid", accessToken.sessionid.value) .cookie("csrftoken", accessToken.csrftoken.value) .header("X-CSRFToken", accessToken.csrftoken.value) .header("Host", "localhost:8888") // 确保和Hue的ALLOWED_HOSTS匹配 .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9") .header("Connection", "keep-alive") .header("Sec-Fetch-Dest", "document") .header("Sec-Fetch-Mode", "navigate") .header("Sec-Fetch-Site", "same-origin") .header("Upgrade-Insecure-Requests", "1") .header("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36") .header("Accept-Encoding", "gzip, deflate, br") .header("Accept-Language", "en,en-US;q=0.9,ru;q=0.8") .header("Cache-Control", "max-age=0") .asString // 处理响应逻辑... }
额外排查技巧
- 用浏览器开发者工具对比你的请求和正常请求的所有Cookie,看看有没有遗漏Hue的自定义cookie。
- 开启Hue的
DEBUG=true,查看后端日志里的request.COOKIES和request.session内容,确认sessionid是否被正确解析。 - 用curl手动模拟请求,排除代码库的问题:
# 获取CSRF token并保存cookie curl -c cookies.txt $baseUrl/accounts/login/?next=/ # 登录,更新cookie curl -b cookies.txt -c cookies.txt -d "username=test_user&password=xxx&csrfmiddlewaretoken=$(grep csrftoken cookies.txt | awk '{print $7}')&next=/" $baseUrl/accounts/login/ # 访问页面 curl -b cookies.txt $baseUrl/filebrowser/view=/user/test_user
如果curl能成功,那问题肯定出在Scala HTTP客户端的cookie处理上。
内容的提问来源于stack exchange,提问作者Capacytron
相关产品推荐
相关产品推荐

