• Django的URL自主发现


    最近部门的领导们要对程序进行安全测试,让我们提供所有的URL,一个一个写太麻烦,因此总结为以下博文:

    1, 在django的项目同名的app中有个urls文件,是属于项目的根路由(也就是我本次做的入手点)

    2,ROOT_URLCONF = 'XXX.urls'

    在django的settings文件中会存在(这个是告诉Django根级路由配置的位置

    3, Django既然在settings文件中以字符串的形式来配置,那必然可以改变,或者我们也可以导入这些路由!

    问题是,咋办?

    道理都懂,问题是咋实现?

    4,Django的路由分发会有include,有可能会有namespace,有可能有name

        from django.conf import settings
        from django.utils.module_loading import import_string  # 帮助我们以字符串的形式导入模块
        port = import_string(settings.ROOT_URLCONF)
        print(port)
        print(dir(port))
    <module 'blog.urls' from 'C:\Users\lenovo\Desktop\blog\blog\urls.py'>
    # 能够使用的方法如下
    ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'admin', 'include', 'path', 're_path', 'serve', 'settings', 'urlpatterns', 'views']

    那既然有URL的方法

    port = import_string(settings.ROOT_URLCONF)
        for k in port.urlpatterns:
            print(k)
    
    #
    >>>
    <URLResolver <URLPattern list> (admin:admin) 'admin/'>
    <URLResolver <module 'cnblong.urls' from 'C:\Users\lenovo\Desktop\blog\cnblong\urls.py'> (cnblong:test) 'cnblog/'>
    <URLPattern 'login/' [name='login']>
    <URLPattern 'logout/' [name='logout']>
    <URLPattern '^$'>
    <URLPattern 'register/' [name='register']>
    <URLPattern 'get_valid_img/'>
    <URLPattern 'media/(?P<path>.*)$'>

    可以看到的是其中的类型有URLResolver, URLPattern

    其中路由分发就是URLResolver

    不是路由分发就是URLPattern

    def test(request):
        from collections import OrderedDict  # 用于保存路由
        from django.urls import URLPattern, URLResolver
        from django.conf import settings
        from django.utils.module_loading import import_string  # 帮助我们以字符串的形式导入模块
        port = import_string(settings.ROOT_URLCONF)
        for k in port.urlpatterns:
            if isinstance(k, URLResolver):  # 路由分发
                pass
            elif isinstance(k, URLPattern):  # 非路由分发
                if k.name:
                    print('1111', k, k.pattern)
                else:
                    print('2222', k, k.pattern)
    1111 <URLPattern 'login/' [name='login']> login/
    1111 <URLPattern 'logout/' [name='logout']> logout/
    2222 <URLPattern '^$'> ^$
    1111 <URLPattern 'register/' [name='register']> register/
    2222 <URLPattern 'get_valid_img/'> get_valid_img/
    2222 <URLPattern 'media/(?P<path>.*)$'> media/(?P<path>.*)$

    和非路由分发类似的

     if isinstance(k, URLResolver):  # 路由分发
         print('00000', k, k.namespace)
    
    >>>>
    00000 <URLResolver <URLPattern list> (admin:admin) 'admin/'> admin
    00000 <URLResolver <module 'cnblong.urls' from 'C:\Users\lenovo\Desktop\blog\cnblong\urls.py'> (cnblong:test) 'cnblog/'> test

    但是现在问题出现了,路由分发下有多个URL,所以我们得拼接URL,类似于有namespace的URL+分发的URL,那就需要重复调用这个方法进行递归操作

    所以,我们的单独写一个函数了,方便拼接

    from collections import OrderedDict
    from django.conf import settings
    from django.utils.module_loading import import_string
    from django.urls.resolvers import URLResolver, URLPattern
    
    
    def check_url_exclude(url):
        '''自定制,过滤一下。 以 xxx 为前缀的 url'''
        exclude_url = [
            "/admin/.*",
            "/login/",
        ]
        for regex in exclude_url:
            if re.match(regex, url):
                return True
    
    
    def recursion_urls(pre_namespace, pre_url, urlpatterns, url_ordered_dict):
        '''
        递归获取,所有的url
        :param pre_namespace:  namespace前缀,用于拼接name (namespace:name)
        :param pre_url:  url的前缀, 用于拼接url
        :param urlpatterns:  路由关系列表
        :param url_ordered_dict:  用于保存递归中获取的所有的路由
        :return:
        '''
        for item in urlpatterns:
            if isinstance(item, URLPattern):  # 表示一个 非路由分发。将路由添加到字典中
                if not item.name:  # 判断这个url 有没有,name别名
                    continue
    
           name = item.name
                if pre_namespace:  # 判断当前这个url是不是有namespace前缀。也就是:是否是某一个命名空间中的 name别名
                    name = "%s:%s" % (pre_namespace, item.name)
                url = (pre_url + str(item.pattern)).replace("^", "").replace("$", "")
                if check_url_exclude(url):  # 在这里进行自定制的过滤。 过露出我不想要的 哪些url
                    continue
                url_ordered_dict[name] = {"name": name, "url": url}
    
            elif isinstance(item, URLResolver):  # 表示这是一个路由分发。 这里就需要递归了
            namespace = pre_namespace
                if pre_namespace:  # 如果有前缀
                    if item.namespace:  # 自己有没有namespace
                        namespace = "%s:%s" % (pre_namespace, item.namespace)# 把之前的pre_namespace 和当前的 item.namespace 拼接。 传给下一次的递归函数。继续进行拼接
                else:
                    if item.namespace:
                        namespace = item.namespace
                recursion_urls(namespace, pre_url + str(item.pattern), item.url_patterns, url_ordered_dict)
            # 进入下一次循环之前,pre_url + str(item.pattern) 要拼接上这一次循环的 url。
            # item.url_patterns这一次是 URLResolver 对象的 url_patterns。 中间要加一个 _ 烦得很。 第一次是通过导入拿到的 模块对象。
            # 但是 递归中的不是 模块对象。是一个URLResolver对象。 所以要加一个 _ 。下划线
    
    def get_all_url_dict():
        '''
        获取项目中,所有的url 保存到字典(前提是,每个url必须有name别名)
        :return:
        '''
        url_ordered_dict = OrderedDict()
        md = import_string(settings.ROOT_URLCONF)
    
        recursion_urls(None, "/", md.urlpatterns, url_ordered_dict)
        # 递归的去获取所有的路由。
        # 第一次循环时,肯定是从 根路由开始, 所以没有前缀 传一个None.
        # "/" 也是因为,第一次循环时。 所有的url 都没有前导 的 "/" 手动的加上。
        # md.urlpatterns 要循环的这个列表。
        # url_ordered_dict 保存所有url 的字典。
        return url_ordered_dict
    
    
    def multi_permissions(request):
        '''
        批量操作权限
        :param request:
        :return:
        '''
        # 获取项目中,所有的URL
        all_url_dict = get_all_url_dict()
        print(all_url_dict)
        return HttpResponse("OK")
    View Code
  • 相关阅读:
    RNA velocity | RNA速率
    Dynamic networks | 动态网络
    Scale Free Network | 无标度网络
    GO | KEGG的注释是怎么来的?
    Nearest neighbor graph | 近邻图
    L0 Regularization
    Median absolute deviation | Singular Value Decomposition奇异值分解 | cumulative sums |
    Multivariate normal distribution | 多元正态分布
    相似性 similarity | Pearson | Spearman | p-value | 相关性 correlation | 距离 distance | distance measure
    Type I and type II errors | 第一类错误和第二类错误
  • 原文地址:https://www.cnblogs.com/zhoulixiansen/p/11530519.html
Copyright © 2020-2023  润新知