Openstack Keystone 认证流程(五)

1. 路由实现

在上一章中, 我们一起过了admin_api的所有流水线的处理, 其中有好几个点是用来添加路由信息的。这一章我们来详细看看路由的具体实现。

路由是MVC架构中非常重要的一个关键节点, 可以说, 如果没有路由,就不可能去实现一个很好的MVC架构, 路由也是整个系统中最先处理的节点。如果想弄清楚Keystone的整体架构, 路由是必须先搞清楚的。

看具体实现之前, 我们先看看路由的具体用法。比如说有如下一条路由:

import routes.middleware…::ec2_controller = controllers.Ec2Controller()# validationmapper.connect(‘/ec2tokens’,controller=ec2_controller,action=’authenticate’,conditions=dict(method=[‘POST’]))

假设Keystone的服务器为127.0.0.1:35357, 那么如果我们访问如下地址时: :35357/ec2tokens 经过路由分发, 代码就会跑到类ec2_controller的authenticate方法中。

知道了怎么使用之后, 我们再来看看它的具体实现。我们找到Ec2Extension的路由父类:

::if mapper is None:mapper = routes.Mapper()self.application = applicationself.add_routes(mapper)mapper.connect(‘{path_info:.*}’, controller=self.application)super(ExtensionRouter, self).__init__(mapper):::conf = global_config.copy()conf.update(local_config)return cls(app, **local_config)return _factory

在ExtensionRouter的__init__ 方法中, routes.Mapper创建了一个Mappper对象。这是一个实际完成路由功能的模块, 这里我们不去管里面的具体实现,, 有兴趣的可以参考routes – Route and Mapper core classes。 至此,可以看到, 在ExtensionRouter的factory方法中,创建一个ExtensionRouter的一个实例, 并在其它构造方法中,创建Mapper对象,并把所有的路由信息全部增加到Mapper对象中,然后调用其它父类的构造方法。继续看看Router类的构造方法。

::if CONF.debug:logging.getLogger(‘routes.middleware’)self.map = mapperself._router = routes.middleware.RoutesMiddleware(self._dispatch,self.map):return self._router:match = req.environ[‘wsgiorg.routing_args’][1]if not match:return render_exception(exception.NotFound(_(‘The resource could not be found.’)),user_locale=req.best_match_language())app = match[‘controller’]return app

在Route类的__init__ 中使用, 使用Router._dispath方法作为一个中间件的应用程序初始化一个中间件。找到这个中间件的实现方法。在routes.middleware.py 中, 其实现如下:

:self.app = wsgi_appself.mapper = mapperself.singleton = singletonself.use_method_override = use_method_overrideself.path_info = path_infoself.log_debug = logging.DEBUG >= log.getEffectiveLevel()if self.log_debug:log.debug(“Initialized with method overriding = %s, and path “”info altering = %s”, use_method_override, path_info):”””Resolves the URL in PATH_INFO, and uses wsgi.routing_argsto pass on URL resolver results.”””old_method = Noneif self.use_method_override:req = :qs = environ[‘QUERY_STRING’]except KeyError:qs = qs:req = Request(environ)req.errors = req.GET:old_method = environ[‘REQUEST_METHOD’]environ[‘REQUEST_METHOD’] = req.GET[‘_method’].upper()if self.log_debug:log.debug(“_method found in QUERY_STRING, altering “”request method to %s”,environ[‘REQUEST_METHOD’])elif environ[‘REQUEST_METHOD’] == ‘POST’ and is_form_post(environ):if req is None:req = Request(environ)req.errors = req.POST:old_method = environ[‘REQUEST_METHOD’]environ[‘REQUEST_METHOD’] = req.POST[‘_method’].upper()if self.log_debug:log.debug(“_method found in POST data, altering “”request method to %s”,environ[‘REQUEST_METHOD’])self.singleton:config = request_config()config.mapper = self.mapperconfig.environ = environmatch = config.mapper_dictroute = config.routeelse:results = self.mapper.routematch(environ=environ)if results:match, route = results[0], results[1]else:match = route = Noneif old_method:environ[‘REQUEST_METHOD’] = old_methodif not match:match = {}if self.log_debug:urlinfo = “%s %s” % (environ[‘REQUEST_METHOD’],environ[‘PATH_INFO’])log.debug(“No route matched for %s”, urlinfo)elif self.log_debug:urlinfo = “%s %s” % (environ[‘REQUEST_METHOD’],environ[‘PATH_INFO’])log.debug(“Matched %s”, urlinfo)log.debug(“Route path: ‘%s’, defaults: %s”, route.routepath,route.defaults)log.debug(“Match dict: %s”, match)url = URLGenerator(self.mapper, environ)environ[‘wsgiorg.routing_args’] = ((url), match)environ[‘routes.route’] = routeenviron[‘routes.url’] = urlif route and route.redirect:route_name = ‘_redirect_%s’ % id(route)location = url(route_name, **match)log.debug(“Using redirect route, redirect to ‘%s’ with status””code: %s”, location, route.redirect_status)start_response(route.redirect_status,[(‘Content-Type’, ‘text/plain; charset=utf8’),(‘Location’, location)])return []self.path_info match:oldpath = environ[‘PATH_INFO’]newpath = match.get(‘path_info’) or ”environ[‘PATH_INFO’] = newpathif not environ[‘PATH_INFO’].startswith(‘/’):environ[‘PATH_INFO’] = ‘/’ + environ[‘PATH_INFO’]environ[‘SCRIPT_NAME’] += re.sub(r’^(.*?)/’ + re.escape(newpath) + ‘$’, r’\1′, oldpath)response = self.app(environ, start_response)# Wrapped in try as in rare cases the attribute will be gone alreadytry:del self.mapper.environexcept AttributeError:passreturn response人生难免有挫折,但你是逃避不了的,一定要去面对它

Openstack Keystone 认证流程(五)

相关文章:

你感兴趣的文章:

标签云: