我有一个带有 Ruby on Rails 3.2 后端的 ExtJS 4.1 应用程序,使用 Devise(启用了 Timeoutable)进行身份验证和 session 管理。
此问题发生在仅通过 SSL 提供应用程序的服务器上。 Nginx 将任何非安全请求重定向到 https url。
问题是,当 Devise session 超时时(在我的情况下是 15 分钟后),任何 AJAX 请求都会发送/重定向到 http://myapp.com/controller?params,而不是https://myapp.com/controller?params,就像通常那样。
我有客户端代码,在非 SSL 设置中可以很好地捕获潜在的 session 过期问题,并重定向到登录页面,并显示 session 已超时的消息。这是一种基于以下事实的黑客攻击:当 session 超时后发出请求时,会返回“无效的 JSON 字符串”错误消息。该错误包含登录页面的 HTML,因为用户登录时本应为 json 的响应变成了应用程序应在 session 超时时重定向到的登录页面。此代码块位于我的 Ext.application 的 launch 方法中:
launch: function () {
Ext.Error.handle = function (err) {
$.post('/logs', {message:err.msg});
if (err.msg.indexOf("invalid JSON String") != -1 && err.msg.indexOf("<!DOCTYPE html>") != -1) {
if (err.msg.indexOf("MyApp_Login") != -1)
document.location.href = "/logout?timeout=1";
else
document.location.href = "/logout?error=1";
} else {
gritter(3, "ERROR:", "A client-side error has occurred. If this issue persists, please contact your system administrator.");
if (Ext.isWebKit) console.log(err);
}
}
if (user_signed_in == true) {
Ext.require('MyDesktop.App');
Ext.require('Ext.tab.*');
_myDesktopApp = Ext.create('MyDesktop.App');
Ext.state.Manager.setProvider(Ext.create('Ext.state.CookieProvider'));
}
}
正如我上面所说,通过非安全套接字,应用程序会检测到指示 session 超时的 Controller 请求(或更准确地说响应),并采取适当的操作。但在我的服务器上,通过 SSL,由于某种原因,一旦 session 过期, Controller 调用最终会通过 http 而不是 https 进行。在 Chrome 中导致这样的错误:
The page at https://server.myapp.com/ displayed insecure content from http://server.app.com/campaign_components_contacts.json?authenticity_token=1vokGHUpsi5w3b3P8mrfUpEGx19hrHJpsCzPayofM7c%3D&campaign_id=2&component_id=2&contact_id=1536&format=json
这可能是 ExtJS 的一项功能吗?当通过 SSL 检测到问题时,它会尝试进行非安全调用?或者 Rails 的某些功能?我确信两者都不是,但只是扔掉我脑海中出现的一些事情。
编辑:
我已经能够通过使用 thin 和 --ssl 开关在开发环境中本地测试该场景。服务器启动后,我浏览到
https://localhost:3000
没有任何问题。一旦 Devise session 过期,任何 json 请求都会按预期触发登录重定向,并通过 http 进行工作。
因此,这个问题中描述的问题仅出现在我的服务器上,并且可能与我的 NGINX 配置的设置方式有关。
我还将在本地预编译应用程序并使用 prod 环境选项运行,只是为了确保它与 dev 和 prod 之间的差异无关。
最佳答案
哇,原来与 Devise session 超时、Rails 或 ExtJS 无关。
最终通过调整 NGINX 配置解决了这个问题,根据文档,这对于所使用的版本来说是正确的,但结果却导致了这个问题。
当前 ssl 服务器位:
server {
listen 443;
ssl on;
ssl_certificate /srv/ssl/server.myapp.com.combined.crt;
ssl_certificate_key /srv/ssl/server.myapp.com.key;
server_name server.myapp.com;
root /var/www/myapp/current/public;
passenger_enabled on;
rails_env myapp_staging;
}
在我之前:
server {
listen 443 ssl;
ssl_certificate /srv/ssl/server.myapp.com.combined.crt;
ssl_certificate_key /srv/ssl/server.myapp.com.key;
server_name server.myapp.com;
root /var/www/myapp/current/public;
passenger_enabled on;
rails_env myapp_staging;
}
差异在于 split
listen 443 ssl;
进入:
listen 443;
ssl on;
关于ssl - 意外的 302/从 HTTPS 重定向到 HTTP 导致 'insecure content' javascript 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13976313/