def has_role(self, principal, role, object=None):
        """True if `principal` has `role` (either globally, if `object` is
        None, or on the specific `object`).

        :param:role: can be a list or tuple of strings or a :class:`Role`
            instance

        `object` can be an :class:`Entity`, a string, or `None`.

        Note: we're using a cache for efficiency here. TODO: check that we're not
        over-caching.

        Note2: caching could also be moved upfront to when the user is loaded.
        """
        if not principal:
            return False

        principal = unwrap(principal)
        if not self.running:
            return True

        if isinstance(role, (Role, (str,))):
            role = (role,)

        # admin & manager always have role
        valid_roles = frozenset((Admin, Manager) + tuple(role))

        if AnonymousRole in valid_roles:
            # everybody has the role 'Anonymous'
            return True

        if (
            Authenticated in valid_roles
            and isinstance(principal, User)
            and not principal.is_anonymous
        ):
            return True

        if principal is AnonymousRole or (
            hasattr(principal, "is_anonymous") and principal.is_anonymous
        ):
            # anonymous user, and anonymous role isn't in valid_roles
            return False

        # root always have any role
        if isinstance(principal, User) and principal.id == 0:
            return True

        if object:
            assert isinstance(object, Entity)
            object_key = "{}:{}".format(object.object_type, str(object.id))
            if Creator in role:
                if object.creator == principal:
                    return True
            if Owner in role:
                if object.owner == principal:
                    return True

        else:
            object_key = None

        all_roles = (
            self._fill_role_cache(principal)
            if self.app_state.use_cache
            else self._all_roles(principal)
        )
        roles = set()
        roles |= all_roles.get(None, set())
        roles |= all_roles.get(object_key, set())
        return len(valid_roles & roles) > 0
True if `principal` has `role` (either globally, if `object` is
        None, or on the specific `object`).

        :param:role: can be a list or tuple of strings or a :class:`Role`
            instance

        `object` can be an :class:`Entity`, a string, or `None`.

        Note: we're using a cache for efficiency here. TODO: check that we're not
        over-caching.

        Note2: caching could also be moved upfront to when the user is loaded.