「Python 网络自动化」NETCONF —— Python 使用 NETCONF 管理配置 H3C 网络设备

article/2025/11/10 2:54:35

「Python 网络自动化」系列文章总目录

Nornir 中文手册——基于 Nornir3.0 官方文档的不完全翻译


文章目录

    • NETCONF 简单介绍
      • NETCONF 协议结构
      • NETCONF 报文结构
        • 请求报文格式
        • 报文回复格式
      • NETCONF 配置数据库
      • NETCONF 支持的操作
    • 实验操作
      • 基础环境配置
        • 网络环境
        • 设备配置
        • 代码环境
      • 使用 NETCONF 获取设备接口信息
        • 导入模块
        • 构建 XML
        • 连接设备,执行 XML
      • 使用 NETCONF 下发接口配置
        • 构建 XML
        • 连接设备,执行 XML
      • 使用 NETCONF 下发 BGP 配置
        • 构建 XML
        • 连接设备,执行 XML
    • 总结


上一篇文章 中简单介绍了 Python 针对 XML 文件的操作方式,XML 的诸多特性使得它非常适合程序之间的数据传输,NETCONF 就是采用 XML 来进行工作。

NETCONF 简单介绍

NETCONF(Network Configuration Protocol,网络配置协议)是一种基于 XML 的网络管理协议,它提供了一种可编程的、对网络设备进行配置和管理的方法。

NETCONF 报文使用 XML 格式,具有强大的过滤能力,而且每一个数据项都有一个固定的元素名称和位置,所以具有很强的兼容性,不同厂家不同设备可以通过 XML 得到相同的结果,便于混合不同厂商不同设备的为冷热软件开发。

NETCONF 协议结构

NETCONF 采用分层结构,分别为:

  • Content 内容层
  • Operations 操作层
  • RPC(Remote Procedure Call)远程调用层
  • Transport Protocol 通信协议层

XML 分层与 NETCONF 协议分层模型对应关系

NETCONF 分层XML 分层说明
Content
内容层
具体的配置数据、状态数据等信息被管理对象的信息,包括配置、状态等,如:
<Ifmgr><Interfaces><Interface><Name>G0/0</Name></Interface></Interfaces></Ifmgr>
这个 XML 就是一个简单的内容层,它表示了一个接口的名称信息:G0/0。
Operations
操作层
<get><get-config><edit-config>RPC 中的基本的原语操作集,NETCONF 对其进行扩展,全面定义了对被管理设备的各种基础操作,如getget-configget-bulkedit-config等。
RPC
远程调用层
<rpc>rpc-reply为 RPC 模块的编码提供了简单的、传输协议无关的机制,在 XML 中使用<rpc>rpc-reply对上层的请求和响应数据进行封装。
Transport Protocol
通信协议层
设备登录方式,支持 Console、SSH、HTTP、TLS、Telnet 等为 NETCONF 提供面向连接的、可靠的、顺序的数据链路。

可参考下图:
在这里插入图片描述

NETCONF 报文结构

NETCONF 命令必须符合 XML 语言的基本格式。NETCONF 报文格式遵循 RFC 4741/RFC 6241。

请求报文格式

对于 H3C 网络设备,请求报文分为两部分:协议定义部分、H3C 自有部分,格式如下:

<?xml version="1.0" encoding="utf-8"?> 
<rpc message-id ="101" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"> <operation> 
</rpc> 

协议定义部分:

  • encoding 表示使用的 XML 编码格式,默认使用 UTF-8。
  • message-id 表示消息 ID。客户端使用单调递增的整数来表示消息 ID。服务器端在应答中
    会使用相同的消息 ID 以表示应答对应的请求。
  • 协议定义部分的命名空间必须为 urn:ietf:params:xml:ns:netconf:base:1.0

H3C 自有部分:
对于 get 系列操作,filter 元素下的内容为 H3C 自有部分;对于 edit-config 系
列操作,config 元素下的内容为 H3C 自有部分。
H3C 自有部分需要使用H3C命名空间,H3C 命名空间又分为 base、config、data、action
命名空间。

  • Base 命名空间:http://www.h3c.com/netconf/base:1.0
  • Config 命名空间:http://www.h3c.com/netconf/config:1.0
  • Data 命名空间:http://www.h3c.com/netconf/data:1.0
  • Action 命名空间:http://www.h3c.com/netconf/action:1.0

具体使用哪个命名空间与操作类型和内容有关。

以为接口配置一个 IP 地址的消息为例,请求报文结构可以用下图来说明:

xml-layer

报文回复格式

报文回复格式统一使用协议定义的 <rpc-reply>

<?xml version="1.0" encoding="utf-8"?> 
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="101"> <ok/> 
</rpc-reply> 

NETCONF 配置数据库

NETCONF 有三个配置数据库,用来对设备的配置进行管理。

  • <running/>:存储正在运行的配置,等价于 show run / display cur,所有设备都具有该数据库。
  • <startup/>:存储下次启动时生效的配置,等价于show startup / display saved
  • <candidate/>:存储没有生效的候选配置,等价于一些设备需要commit来使配置生效,并不是所有设备都支持。

NETCONF 支持的操作

操作说明
<get-config>用来从<running/><candidate/><startup/>数据库中获取全部或部分配置数据。
<get>用来从<running/>数据库中获取全部或部分运行配置数据或设备的状态数据。
<edit-config>用来对<running/><candidate/>数据库新增、修改、删除配置数据。
<copy-config>用源数据库替换目标数据库。如果目标数据库没有创建,则直接创建数据库,然后进行拷贝。
<delete-config>用来删除一个数据库,但不能删除<running/>数据库。
<lock>用来锁定一个数据库,独占数据库的修改权限,防止多用户并行操作设备产生冲突。
<unlock>用来取消用户自己之前执行的<lock>操作,但不能取消其他用户的<lock>操作。
<close-session>用来正常关闭NETCONF会话。
<kill-session>用来强制关闭NETCONF会话,只有管理员用户才有权限执行<kill-session>操作。

实验操作

基础环境配置

网络环境

使用 HCL 模拟器,打开一台设备,连接到本地网络
在这里插入图片描述

设备配置

#
interface GigabitEthernet0/0port link-mode routeip address 192.168.56.20 255.255.255.0
#
local-user netdevopspassword simple netdevopsauthorization-attribute user-role network-adminservice-type ssh#ssh server enablenetconf ssh server enable#user-interface vty 0 63authentication-mode scheme#

代码环境

  • Python 3.8
  • ncclient 0.6.7

本次实验使用 ncclient 模块来操作网络设备,可以使用 pip install ncclient 来进行安装,可以先把 pip 下载源修改为国内的,否则下载速度会很慢,参考 pip 设置国内源。

使用 NETCONF 获取设备接口信息

导入模块

# 导入 lxml 相关模块,用于构建 xml
from lxml import etree
from lxml.builder import ElementMaker
# 导入 ncclient 相关模块,用于使用 NETCONF 协议连接设备
from ncclient import manager# 根据网络环境,构建包含设备信息的字典
host = {'host': '192.168.56.20','username': 'netdevops','password': 'netdevops','port': 830,'device_params': {'name': 'h3c'},
}

构建 XML

XML 信息可以使用纯文本格式手写,也可以使用 lxml 工具来构建,构建方式可以参考上一篇文章 。

上文请求报文格式中说明了,对于 get 操作,需要加入 H3C 自有部分的命名空间。
获取设备信息需要使用 data 命名空间。

# 构建 xml 请求文件,以下 xml 用于获取设备上所有的接口名称
get_all_iface = """
<top xmlns="http://www.h3c.com/netconf/data:1.0">
<Ifmgr>
<Interfaces>
<Interface>
<Name></Name>
<InetAddressIPV4></InetAddressIPV4>
<AdminStatus></AdminStatus>
</Interface>
</Interfaces>
</Ifmgr>
</top>
"""
# 可以使用 lxml 相关模块构建获取接口信息需要的 xml
# 以下 xml 用于获取设备上所有的接口名称
H3C_DATA_1_0 = "http://www.h3c.com/netconf/data:1.0"
H3C_DATA_1_0_C = '{' + H3C_DATA_1_0 + '}'
E = ElementMaker(namespace=H3C_DATA_1_0, nsmap={None: H3C_DATA_1_0})
top = E.top(E.Ifmgr(E.Interfaces(E.Interface(E.Name(),E.InetAddressIPV4(),E.AdminStatus()))
))

不论哪种方式构建,最终的内容都是一样的

连接设备,执行 XML

# 对于 ssh 协议,连接设备时会先保存对端的 key,并从本机查找并验证,使用以下两个 False 的参数来跳过检查
conn = manager.connect(**host, hostkey_verify=False, look_for_keys=False)
# 获取设备所有接口的名称、IP地址、状态
ret = conn.get(('subtree', top))
print(ret)

上面代码中使用了 ncclient 封装的 get 操作,我们只需要传入 Content 层的 XML 信息即可,实际上传递给网络设备完整的一个请求报文包含了协议定义的部分,这部分属于 Operation 层,具体的原始 XML 是:

<rpc message-id="ncclient 自动生成的 id" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><get>                         <!--- Operation 层,使用 get 操作 ---><filter type="subtree"><top>"构建的 xml 内容"</top></filter></get>
</rpc>

上述几段代码结合起来,执行结果如下:

<?xml version="1.0" encoding="UTF-8"?><rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:c2124ac3-2c72-4046-a575-de8ea8d151a7">
<data><top xmlns="http://www.h3c.com/netconf/data:1.0">
<Ifmgr><Interfaces><Interface>
<IfIndex>1</IfIndex><Name>GigabitEthernet0/0</Name><AdminStatus>1</AdminStatus><InetAddressIPV4>192.168.56.20</InetAddressIPV4></Interface><Interface>
<IfIndex>2</IfIndex><Name>GigabitEthernet0/1</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>3</IfIndex><Name>GigabitEthernet0/2</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>4</IfIndex><Name>Serial1/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>5</IfIndex><Name>Serial2/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>6</IfIndex><Name>Serial3/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>7</IfIndex><Name>Serial4/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>8</IfIndex><Name>GigabitEthernet5/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>9</IfIndex><Name>GigabitEthernet5/1</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>10</IfIndex><Name>GigabitEthernet6/0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>11</IfIndex><Name>GigabitEthernet6/1</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>129</IfIndex><Name>NULL0</Name><AdminStatus>1</AdminStatus></Interface><Interface>
<IfIndex>130</IfIndex><Name>InLoopBack0</Name><AdminStatus>1</AdminStatus><InetAddressIPV4>127.0.0.1</InetAddressIPV4></Interface><Interface>
<IfIndex>131</IfIndex><Name>Register-Tunnel0</Name><AdminStatus>1</AdminStatus></Interface></Interfaces>
</Ifmgr></top></data></rpc-reply>

可以看到,已经成功从设备中获取到了想要的接口信息,对于设备不存在的信息,返回值没有该标签;
之后对返回数据根据需要进行格式化即可,之后会介绍如何格式化该数据。

待续

使用 NETCONF 下发接口配置

构建 XML

以给 G0/1 接口配置 IP 地址为例,由于 NETCONF 只支持通过 IfIndex 来进行配置,如果实际使用中想要根据接口名称来进行配置,则需要对功能进行封装;
从上面的结果中可以看到 G0/1 的接口索引值为 2,所以构建以下 XML:

# 下发配置需要有 config 元素,且命名空间固定,之后再加入 top 元素及具体的配置信息元素
from lxml import ElementMaker, etreeBASE_NS_1_0 = "urn:ietf:params:xml:ns:netconf:base:1.0"
H3C_CONFIG_1_0 = "http://www.h3c.com/netconf/config:1.0"
C = ElementMaker(namespace=BASE_NS_1_0, nsmap={None: BASE_NS_1_0})
E = ElementMaker(namespace=H3C_CONFIG_1_0, nsmap={None: H3C_CONFIG_1_0})xml_ifcfg = C.config(E.top(E.Ifmgr(E.Interfaces(E.Interface(E.IfIndex("2"),E.Description("Configured by netconf"),E.InetAddressIPV4("1.1.1.1"),E.InetAddressIPV4Mask("24")))))
)
print(etree.tostring(xml_ifcfg))

实际生成的 XML 内容打印如下:

<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0"><top xmlns="http://www.h3c.com/netconf/config:1.0"><IPV4ADDRESS><Ipv4Addresses><Ipv4Address><IfIndex>2</IfIndex><Ipv4Address>1.1.1.1</Ipv4Address><Ipv4Mask>255.255.255.0</Ipv4Mask></Ipv4Address></Ipv4Addresses></IPV4ADDRESS></top>
</config>'

连接设备,执行 XML

# 将接口配置下发到 running 配置库中
conn = manager.connect(**host, hostkey_verify=False, look_for_keys=False)
ret = conn.edit_config(target="running", config=xml_ifcfg)
print(ret)

返回值为 ok,说明配置下发成功,打印执行结果如下:

<?xml version="1.0" encoding="UTF-8"?>
<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:67ad766a-83de-45ba-a575-95059a6cfce6">
<ok/>
</rpc-reply>

到设备上检查配置下发成功:
ip配置

使用 NETCONF 下发 BGP 配置

构建 XML

为设备配置 ASNumber 为 62333,并宣告 G1/0 的接口地址。
根据一般的 BGP 配置逻辑,应该:

  1. 配置 ASN,即启动 BGP 进程
  2. 配置地址族,表明配置生效的范围,如单播 IPv4,带有 VPN Instance 的单播 IPv4 等,并配置相关属性,如本地优先级、等价路由数目等
  3. 配置宣告路由等

对应的在 NETCONF 中下发配置时,操作逻辑也是一样的。
根据需要进行的配置构建以下 XML:

# 配置 asn
xml_bgp_asn_cfg = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<top xmlns="http://www.h3c.com/netconf/config:1.0">
<BGP><Instances><Instance><Name></Name><ASNumber>62333</ASNumber></Instance></Instances>
</BGP>
</top>
</config>"""
# 配置单播 ipv4 地址族
xml_bgp_familys_cfg="""
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<top xmlns="http://www.h3c.com/netconf/config:1.0">
<BGP>
<Familys>
<Family>
<Name></Name>
<VRF></VRF>
<Type>1</Type>
</Family>
</Familys>
</BGP>
</top>
</config>
"""
# 在单播 ipv4 地址族中宣告网段
xml_bgp_net_cfg = """
<config xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<top xmlns="http://www.h3c.com/netconf/config:1.0">
<BGP><Networks><Network><Name></Name><VRF></VRF><Family>1</Family><IpAddress>1.1.1.1</IpAddress><Mask>24</Mask></Network></Networks>
</BGP>
</top>
</config>
"""

连接设备,执行 XML

conn = manager.connect(**host, hostkey_verify=False, look_for_keys=False)
conn.edit_config(target="running", config=xml_bgp_net_cfg)
conn.edit_config(target="running", config=xml_bgp_net_cfg)
conn.edit_config(target="running", config=xml_bgp_net_cfg)

依次执行三项配置并返回成功后,可以在设备上看到相关的配置:
在这里插入图片描述

总结

这篇文章简单介绍了 NETCONF 协议,并结合上篇文章中关于 XML 的知识,进行了三个实际的操作案例。

乍一看,你可能会想:用 NETCONF 下发配置和我用命令行差不多啊,而且看起来好复杂啊,用命令行三下五除二就配置完成了。

NETCONF 的好处在于,如果将日常运维的操作封装为接口进行调用,并且以 WEB 的方式显示出来或者进行配置操作,会方便许多,而且可以做成标准化、流程化的操作进行变更,且返回的数据都是 XML 格式,可以很轻松的转换成 JSON,与其他平台进行联动,这些都是命令行操作不可控的(命令行的操作逻辑及返回数据处理不如 NETCONF 方便)。

问:你怎么知道获取接口信息、配置 BGP 的 XML 怎么写?
答:参考官方的 NETCONF API 开发手册。华为的可以在官网直接找到,华三的可以点击链接进行下载(官方资料)~


http://chatgpt.dhexx.cn/article/4l0IwXw4.shtml

相关文章

OF-CONFIG和NETCONF协议

一、OF-CONFIG协议 1.1 OF-CONFIG设计需求 1.1.1 实现对OF v1.3.1协议设备进行配置的设计需求 1.1.2 实现操作运维的设计需求 1.1.3交换机管理协议需求 1.2 OF-CONFIG协议的数据模型 1.3 OF-CONFIG的传输协议 二、NETCONF协议 2.1 NETCONF协议相对SNMP协议的优点 2.2 …

netconf是啥

netconf是啥 1 历史路由器配置方法&#xff1a;2 问题来了3 解决4 Netconf 是什么参考 1 历史路由器配置方法&#xff1a; 传统路由器配置方法中&#xff0c;以路由器来看&#xff0c;那就要去官网上查看文档&#xff0c;学习产品文档&#xff0c;然后在交换机上输入命令&…

从NETCONF/YANG看网络配置自动化

阅读冗长的NETCONF/YANG的RFC文档是相当乏味枯燥的&#xff0c;结合开发实践&#xff0c;本文试图删其繁&#xff0c;撮其要&#xff0c;给出NETCONF/YANG的轮廓和要点。 引子 NETCONF和YANG的目的是以可编程的方式实现网络配置的自动化&#xff0c;从而简化和加快网络设备和服…

SDN之NETCONF Call Home

本文主要内容都来自于今年二月发布的RFC8071 - NETCONF Call Home and RESTCONF Call Home&#xff0c;该RFC从2015年4月提出到最终发布一共修改了17个版本&#xff0c;其间修改内容可以点击查看详细内容。 介绍 NETCONF Call Home支持两种安全传输网络配置协议分别是Secure …

NETCONF原理

NETCONF简介 网络配置协议NETCONF&#xff08;Network Configuration Protocol&#xff09;提供一套管理网络设备的机制&#xff0c;用户可以使用这套机制增加、修改、删除网络设备的配置&#xff0c;获取网络设备的配置和状态信息。通过NETCONF协议&#xff0c;网络设备可以提…

NETCONF YANG原理

NETCONF YANG原理 网络管理技术背景NETCONF协议介绍YAGN建模语言介绍RESTCONF协议 网络管理技术背景 前言 对于设备的配置管理&#xff0c;工程师更习惯使用CLI命令行的方式与设备交互。该方式简单直接&#xff0c;便于理解。但是在网络自动化领域&#xff0c;CLI方式与设备交…

NetConf Brower使用

1.下载MG-SOFT NETCONF Browser Professional Edition 官方地址 2. 安装MG-SOFT NETCONF Browser 下一步下一步操作即可。 3.连接设备 打开的时候选择Continue即可&#xff0c;无须license。 点击File->Connect ,如下&#xff1a; 输入设备用户名称&#xff1a; 这…

Netconf协议学习笔记

Netconf简介 网络配置协议NETCONF&#xff08;Network Configuration Protocol&#xff09;提供一套管理网络设备的机制&#xff0c;用户可以使用这套机制增加、修改、删除网络设备的配置&#xff0c;获取网络设备的配置和状态信息。通过NETCONF协议&#xff0c;网络设备可以提…

NETCONF、RESTCONF和YANG

目录 一、NETCONF、RESTCONF和YANG是之间什么关系&#xff1f; 二、Netconf简介 2.1、一般使用工具&#xff1a;MG-Soft 简介 三、Netconf YANG 原理与实践 3.1、NETCONF协议 3.2、YANG建模语言 3.3、RESTCONF协议 网管协议&#xff1a; SNMP&#xff08;基于UDP&#…

NETCONF--从NETCONF/YANG看网络配置自动化

阅读冗长的NETCONF/YANG的RFC文档是相当乏味枯燥的&#xff0c;结合开发实践&#xff0c;本文试图删其繁&#xff0c;撮其要&#xff0c;给出NETCONF/YANG的轮廓和要点。 引子 NETCONF和YANG的目的是以可编程的方式实现网络配置的自动化&#xff0c;从而简化和加快网络设备和服…

Netconf

Netconf属于软件定义网络的管理和控制协议。 ETCONF协议&#xff0c;由RFC 6241定义&#xff0c;用以替代命令行界面(command line interface, CLI)、简单网络管理协议(Simple Network Management Protocol, SNMP)以及其它专有配置机制。管理软件可以使用NETCONF协议将配置数据…

NetConf简介之一篇文章读懂NetConf

一、背景 有的人早上不起床刷手机&#xff0c;有的人起床之后再卫生间刷手机&#xff0c;有的人在上班的地铁上刷手机&#xff0c;有的人在下班之后的班车上刷手机&#xff0c;有的人在晚上不睡觉刷手机。这其中有许多离不开技术&#xff0c;其中有一个技术就是网络。 网络互…

NETCONF协议详解

目录 目录概述NETCONF11协议详解 1 安全传输层2 消息层 21 hello 211 几种常用的能力 22 rpc和rpc-reply23 notification 3 操作层 31 get32 get-config33 edit-config34 copy-config35 delete-config36 lock37 unlock38 close-session39 kill-session 4 内容层 标准地图相关网…

netconf简介

简介 根据rfc6241 Network Configuration Protocol (NETCONF)介绍&#xff0c;netconf协议提供一种简单的机制&#xff0c;通过该机制网络设备进行管理。协议可以是设备对外提供一套完整并且规范的配置接口&#xff0c;管理者可以通过这些标准接口对设备进行配置操作。 netconf…

五、南向接口协议(四)——NetConf协议

文章目录 1 什么是NetConf协议2 NetConf协议的其他特点3 NETCONF协议框架3.1 NETCONF传输层3.2 NETCONF消息层&#xff08;采用RPC协议&#xff09;3.3 NETCONF操作层&#xff08;NETCONF核心&#xff09;3.4 NETCONF内容层 4 操作举例4.1 <get-config>4.2 <edit-conf…

Netconf网络配置协议讲解

目录 什么是Netconf 为什么要提出Netconf 数据的类别 传统网络配置协议 Netconf配置协议 Netconf协议架构 安全传输层 消息层 操作层 内容层 Netconf配置设备流程 通过Python进行Netconf配置 Restconf 什么是Netconf NETCONF&#xff08;Network Configuration Pr…

netconf协议

最近项目中要用到netconf协议也和设备之间进行连接&#xff0c;学习一下netconf协议并且记录下来 一&#xff1a;什么是netconf netconf协议也可以叫做网络配置协议&#xff0c;它提供了一套管理网络设备的机制&#xff0c;用户可以使用这套机制增加&#xff0c;修改&#xff0…

neq的问题

最近做一个项目&#xff0c;用的tp5&#xff0c;刚开始上手&#xff0c;就给我出现了一个莫名其妙的问题&#xff1b; 也不算是错误&#xff0c;看代码 我根据这个条件去用select查询数据库的数据&#xff0c;然后居然只给我返回一条数据&#xff0c;我以为是我的查询语句写错…

php条件判断结构一个嵌套,thinkphp:html中的if condition 嵌套写法、条件判断的各种情况(eq、neq、gt、lt、or、and) - 猫扑天空...

伪代码 术语符号 大于 gt 小于 lt 等于 eq 不等于 neq 或者 or 并且 and 变量start_time代表的含义是活动的开始时间,变量start_time代表的含义是活动的结束时间。两个变量都是时间戳的格式。下面就将显示状态一列的数据&#xff0c;各种情况下的判断条件列举出来。 等于 eq 进…

前端模板标签eq与neq的使用,以及管理系统模块权限控制

1&#xff09;方法一&#xff1a; 在超级管理员登录情况下显示 1.当前登录用户只能修改自己 2.超级管理员admin拥有查看普通用户和删除其他用户的权限&#xff0c;但删除不了自己 {volist name"userList" id"user" empty"$empty"}<tr><…