token失效后再次请求获取新token


在neutron日志中发现经常有认证失败warning,但是认证失败并不会导致服务请求报错,这是什么原因呢?

在keystonemiddleware中打印认证的token,发现认证失败的token都是已经过期的token,这些过期的token认证时肯定是失败的,所以返回认证失败。在认证失败后,服务会再次请求获取新的token,再用新的token进行验证,这样验证就可以通过了,也就不影响服务的正常运行了。代码分析如下:

在上一篇中blog《rest api请求时token的注入》介绍了neutronclient发起http请求的过程。httpclient实际上是SessionClient,因为创建client时传进的session总不是为None,是 keystoneclient.session.Session,所以调用的do_request函数是SessionClient的do_request函数。

class SessionClient(adapter.Adapter):

    def request(self, *args, **kwargs):
        kwargs.setdefault('authenticated', False)
        kwargs.setdefault('raise_exc', False)

        content_type = kwargs.pop('content_type', None) or 'application/json'

        headers = kwargs.setdefault('headers', {})
        headers.setdefault('Accept', content_type)

        try:
            kwargs.setdefault('data', kwargs.pop('body'))
        except KeyError:
            pass

        if kwargs.get('data'):
            headers.setdefault('Content-Type', content_type)

        resp = super(SessionClient, self).request(*args, **kwargs)
        return resp, resp.text

    def do_request(self, url, method, **kwargs):
        kwargs.setdefault('authenticated', True)
        self._check_uri_length(url)
        return self.request(url, method, **kwargs)
do_request函数调用request函数,request函数又调用父类的request函数,父类为adapter.Adapter,其request函数为:

class Adapter(object):
    def request(self, url, method, **kwargs):
        endpoint_filter = kwargs.setdefault('endpoint_filter', {})
        self._set_endpoint_filter_kwargs(endpoint_filter)

        if self.endpoint_override:
            kwargs.setdefault('endpoint_override', self.endpoint_override)

        if self.auth:
            kwargs.setdefault('auth', self.auth)
        if self.user_agent:
            kwargs.setdefault('user_agent', self.user_agent)
        if self.connect_retries is not None:
            kwargs.setdefault('connect_retries', self.connect_retries)
        if self.logger:
            kwargs.setdefault('logger', self.logger)

        return self.session.request(url, method, **kwargs)

在Adapter函数中,又调用session.request函数,此处session和SessionClient的session是一样的,为keystoneclient.session.Session。其request函数为:

class Session(object):
    @utils.positional(enforcement=utils.positional.WARN)
    def request(self, url, method, json=None, original_ip=None,
                user_agent=None, redirect=None, authenticated=None,
                endpoint_filter=None, auth=None, requests_auth=None,
                raise_exc=True, allow_reauth=True, log=True,
                endpoint_override=None, connect_retries=0, logger=_logger,
                **kwargs):
        ........
        send = functools.partial(self._send_request,
                                 url, method, redirect, log, logger,
                                 connect_retries)
        
        resp = send(**kwargs)

        # handle getting a 401 Unauthorized response by invalidating the plugin
        # and then retrying the request. This is only tried once.
        if resp.status_code == 401 and authenticated and allow_reauth:            
            if self.invalidate(auth):
                auth_headers = self.get_auth_headers(auth)
                if auth_headers is not None:
                    headers.update(auth_headers)                    
                    resp = send(**kwargs)

        if raise_exc and resp.status_code >= 400:
            logger.debug('Request returned failure status: %s',
                         resp.status_code)
            raise exceptions.from_response(resp, method, url)

        return resp
从request函数可以看到在第一次send后获取返回的response(resp),如果返回的代码为401,并且authenticated,允许重新认证,则就会进行第二次认证,在发起第二次请求处理,如果第二次请求失败,则就再返回失败结果。












你可能感兴趣的:(openstack)