使用nginx搭建多台虚拟主机模拟统一验证(共享cookie的方式)
写博客的原因:太晚了,而舍友的呼噜声惊天动地,无法入睡。
环境:tornado,linux(linux mint 类ubuntu),nginx, python2.7
首先是讲一下nginx搭建多台虚拟主机的过程,大致的步骤如下:
这里我配置了三个网站他们分别是:
#new host for distribute course experience
172.18.43.223 www.auth.my.com(端口为8000)
172.18.43.223 www.a1.my.com(端口为8010)
172.18.43.223 www.a2.my.com(端口为8020)
172.18.43.223为我的电脑在互联网上的ip地址,你可以通过在终端下执行ifconfig命令查看你当前的电脑的ip地址
同时需要将这些网站的配置信息添加到/etc/hosts文件中,如图:
至于/ect/hosts文件是干什么用的,可以看这里
- 在nginx(ubuntu下为/etc/nginx.conf)的配置文件里面配置多台虚拟主机(server),形如:
server {
配置信息
}
里面server_name项就是你要在浏览器输入的网址,proxy_pass为你指定哪个upstream给这台虚拟主机,这里为frontends - 然后就是配置真正能够提供服务的地方了,那就是配置upstream了,其配置如下:
前面的www.auth.my.com代理的upstream就是frontends里面的127.0.0.1:8000(真正提供服务的网站)了
总结一下,先是访问nginx的某个虚拟主机,虚拟主机(上例子就是www.auth.my.com,由于是网址,不是ip地址,所以这个时候nginx先是到/etc/hosts里面找www.auth.my.com的ip地址,如果没有找到则是向dns服务器求助,因为我们之前已经在/etc/hosts里面规定了www.auth.my.com的ip地址,所以我们就有了www.auth.my.com对应的ip地址为172.18.43.223 )就会根据配置文件(/etc/nginx.conf)里面的配置信息来寻找真正提供服务的服务器(上例就是127.0.0.1:8000了),同样方法可以配置www.a1.my.com和www.a2.my.com.这样之后就是配置好虚拟主机了。
2.模拟统一验证平台
关于什么是统一验证和单点登录及其原理,可以看这里
这里我讲一下我的实现,我这里的www.a1.my.com和www.a2.my.com对应的是应用系统1和应用系统2,www.auth.my.com对应的是认证系统,以cookie共享的方式实现统一是这样子的,假设用户不能直接访问认证系统,如果用户访问应用系统,不管是应用系统1还是应用系统2,如果应用系统木有用户的cookie,那么用户会被当前的应用系统重定向到认整系统网站,有两种情况:
第一种:如果这个时候认证系统木有用户的cookie,那么就会展示登录界面给用户,让用户输入账号和密码进行认证,认证成功后会设置用户cookie,然后将用户重定向到了原来的应用系统,同时携带了用户cookie给应用系统,当请求再次来到的时候,应用系统发现请求由认证系统重定向过来的,这个时候就会找到了用户的cookie,并为自己设置用户cookie,这个时候应用系统知道了用户已经登录(认证)过了,然后就展示相应的页面给用户。
第二种:如果这个时候认证系统有用户的cookie的话,代表用户之前已经登录(认证)过了,认证系统就会将用户重定向到了原来的应用系统,同时携带了用户cookie给应用系统,当请求再次来到的时候,应用系统发现请求由认证系统重定向过来的,这个时候就会找到了用户的cookie,并为自己设置用户cookie,这个时候应用系统知道了用户已经登录(认证)过了,然后就展示相应的页面给用户。
下面是我使用tornadao在linux模拟了一下统一验证,代码风格略差,勿喷!仅供参考。
# -*- coding: utf-8 -*- # my ip is 172.18.43.233 # hosts # 172.18.43.223 www.auth.my.com # 172.18.43.223 www.a1.my.com # 172.18.43.223 www.a2.my.com # ports # ww.auth.my.com -> 8000 # www.a1.my.com -> 8010 # www.a2.my.com -> 8020 import tornado.httpserver import tornado.ioloop import tornado.web import tornado.options import os.path import base64 import urllib from tornado.options import define, options from urllib import urlencode define("port", default=8000, help="run on the given port", type=int) # def get_login_url(self): # """Override to customize the login URL based on the request. # By default, we use the ``login_url`` application setting. # """ # print self.get_argument # self.require_setting("login_url", "@tornado.web.authenticated") # return self.application.settings["login_url"] class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): return self.get_cookie("username") class LoginHandler(BaseHandler): def get(self): if not self.get_argument("ticket", None): if not self.get_argument("refer", None): currentPort = options.port if self.get_cookie("username"): self.redirect("/") elif currentPort == 8000: self.render('login.html') elif currentPort == 8010: refer = urllib.quote('http://www.a1.my.com/') self.redirect("http://www.auth.my.com/login?refer=" + refer) elif currentPort == 8020: refer = urllib.quote('http://www.a2.my.com/') self.redirect("http://www.auth.my.com/login?refer=" + refer) else: raise HTTPError(403) else: if self.get_current_user(): refer = self.get_argument("refer") ticket = base64.urlsafe_b64encode(self.current_user) self.redirect(refer + "login?ticket=" + ticket) else: self.render("login.html") else: ticket = base64.urlsafe_b64decode(str(self.get_argument("ticket"))) self.set_cookie("username", ticket) self.redirect("/") def post(self): self.set_cookie("username", self.get_argument("username")) if not self.get_argument("refer", None): self.redirect("/") else: refer = self.get_argument("refer") ticket = base64.urlsafe_b64encode(self.current_user) self.redirect(refer + "login?ticket=" + ticket) class WelcomeHandler(BaseHandler): @tornado.web.authenticated def get(self): self.render('index.html', user=self.current_user) class LogoutHandler(BaseHandler): def get(self): self.clear_cookie("username") if self.get_argument("auth", None): self.redirect("/") else: self.redirect("http://www.auth.my.com/logout?auth=yes") if __name__ == "__main__": tornado.options.parse_command_line() settings = { "template_path": os.path.join(os.path.dirname(__file__), "templates"), "login_url": "/login" } application = tornado.web.Application([ (r'/', WelcomeHandler), (r'/login', LoginHandler), (r'/logout', LogoutHandler) ], **settings) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()