最近,在做一个项目,需要把以前写的django项目统一到一个新的django项目中,并保持所有系统的登录状态,即单点登录。搜了一圈,方法很多,但要在其中,选择最快速上线的确实不简单。又说用SSO系统,有的说用CAS认证,有的说用jwt机密token。最后,我选择了共享session。
思路十分清晰,共享session就是把cookie存的session_id的session信息通过一个公共的媒介存储下来,所有系统统一读写。由于django有各种数据库引擎,可以借用其中一个,方便实现单点登录。
在3个Django 正常运行的情况下,我们需要安装nginx和redis服务。这里不展开说nginx和redis的安装。
(一)nginx服务配置(反向代理)
server {
listen 10011; #监听的端口
server_name xxx.xxx.com;#域名名称(这里做了脱敏)
#autoindex on;
charset utf-8;
client_max_body_size 10M;
location / {
proxy_redirect off; #关闭强制重定向(如果需要设置http跳https可以在这里设置)
uwsgi_pass 127.0.0.1:1234; #设置代理服务器和端口(这里使用了uwsgi服务)
#proxy_pass http://192.168.1.123;#不用uwsgi 的socket设置也可以直接代理http服务
include uwsgi_params;#uwsgi代理设置需要带上
proxy_cookie_path / /; #设置代理的cookie路径
fastcgi_buffer_size 64k;#如果返回数据过大需要设置代理的buffer大小
fastcgi_buffers 32 32k;
fastcgi_busy_buffers_size 128k;
proxy_set_header Host $host;#设置代理的header配置
proxy_set_header Referer $http_referer;
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
#proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
add_header Access-Control-Allow-Origin $http_origin; #允许跨域
add_header Access-Control-Allow-Methods *;
add_header Access-Control-Max-Age 3600;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers true;
}
}
反向代理设置后 如上配置,代理的路径为"/",则代理时只需要对应的ip或域名 以及端口,路径后的内容将自动代理。这时所有Django服务都设置再同一个nginx代理服务器下,即可完成一半的配置操作。
(二)Django setting配置
接下来配置Django的setting
有几个地方需要配置:
(1)SECRET_KEY
SECRET_KEY需要是每个Django服务都要相同,才能共享session。个人认为是Django的一个唯一加密串。配置如下:
加密字符串可以是任意字符串,但每个Django服务的该字符串要相同。
(2)redis缓存机制配置
一开始提到的DJango 缓存机制就是在setting的这里配置的
# redis配置
CACHES = {
"default": {#设置数据库名称
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://ip:6379/15",#ip为脱敏信息,设置redis的数据库位置为15号数据库
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "密码"#密码为脱敏信息
}
},
"session":{ #设置数据库名称
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://ip:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100},
"PASSWORD": "密码"#密码为脱敏信息
}
},
}
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' #这里只用到缓存 没有用到数据库,其他机制可以按需配置
SESSION_CACHE_ALIAS = 'session' #指定选择的缓存数据库
SESSION_COOKIE_AGE = 60*5 #设置cookie的有效时长
SESSION_COOKIE_NAME = 'session' #设置相同的session再cookie中的名称,默认是session_id
SESSION_COOKIE_HTTPONLY=False #设置是否httponly
#SESSION_COOKIE_DOMAIN = '.domain.com' #设置cookie的作用域
# Application definition
(3)Django 中间件配置
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',#配置session的中间件
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', #这里注释了csrf认证模块,怀疑可以不用关闭csrf,但未实际操作过
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
(三)实操排坑
(1)session冲突
配置完成后,出现某个Django登录后,再跳到另一个Django,前面的那个Django直接跳回登录页面。即两个Django的session发生冲突。
其他人的解决方法是:设置不同的sessionID在cookie中的key值或使用不同的域名。
但这就不能实现单点登录了。所以我排查了配置文件,发现原来有的Django服务设置了SSL,所以要统一所有django的SSL证书,不然就会出现上述的session冲突问题。