我有一个带有Ruby on Rails 3.2后端的ExtJS 4.1应用程序,使用Devise(启用了Timeoutable)进行身份验证,会话管理。
此问题发生在服务器上,其中应用程序仅通过SSL提供。 Nginx将任何非安全请求重定向到https网址。
问题在于,当Devise会话超时时,在我的情况下,15分钟后,任何AJAX请求被发送/重定向到 http ://myapp.com/controller?params,而不是 https ://myapp.com/controller?params,就像通常那样。
我有客户端代码,在非SSL设置中可以很好地捕获潜在的会话过期问题,并重定向到登录页面,并显示会话已超时的消息。这是一种基于以下事实的黑客:当会话超时后发出请求时,会返回“无效的JSON字符串”错误消息。该错误包含“登录”页面的HTML,因为当用户登录时应该是json的响应成为应用程序应在会话超时时重定向到的“登录”页面。这段代码在我的 Ext.application 的启动方法中:
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'));
}
}
正如我上面所说,通过非安全套接字,应用程序会检测到指示会话超时的控制器请求(或更精确的响应),并采取适当的措施。但是在我的服务器上,通过SSL,由于某种原因,一旦会话过期,控制器调用最终会超过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的一些功能?我敢肯定它不是,但只是抛弃了我头脑中的一些东西。
编辑:
我已经能够在开发环境中使用瘦和 - ssl 开关在本地测试场景。启动服务器后,我浏览到
https://localhost:3000
没有问题。一旦Devise会话到期,任何json请求都会按预期触发重定向登录,并通过http工作。
因此,此问题中描述的问题仅出现在我的服务器上,可能与我的NGINX配置设置方式有关。
我还会在本地预编译应用程序并使用prod环境选项运行,只是为了确保它与dev和prod之间的区别无关。
答案 0 :(得分:2)
最后通过调整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;
}
区别在于分裂
listen 443 ssl;
成:
listen 443;
ssl on;