Shiro 权限管理

article/2025/9/19 20:17:18

一共5个表

  • 用户表
  • 角色表
  • 权限表
  • 用户角色中间表
  • 角色权限中间表

权限验证

  • 用户不跟权限直接关联, 可以给用户多个角色, 每个角色都有对应的权限,所以给用户加一个角色,就相当于,给用户赋了对应的权限。
  • 一个用户可以有多个角色, 一个角色可以有多个权限
  • 通过角色来判断有没有权限。 比如 用户,在用户角色中间表中有经理的角色, 就可以查看工资。这种判断比较笼统。适合实现不同的角色登录以后看到不同的菜单。
  • 通过权限标识来判断, 这个就需要查出用户拥有的具体权限。 这个权限控制比较细致。
    适合细致的,比如部门公司的管理员,只能修改该部门下的员工资料。

Shiro 要点

  • Subject:主体,代表了当前“用户
  • SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是Shiro的核心
  • Realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限)
  • 最简单的一个Shiro应用:

1、应用代码通过Subject来进行认证和授权,而Subject又委托给SecurityManager;

2、我们需要给Shiro的SecurityManager注入Realm,从而让SecurityManager能得到合法的用户及其权限进行判断。

Shiro 授权流程

  • 1、首先调用Subject.isPermitted接口

  • 2 调用相应的Realm获取主题相应的角色/权限;

  • 3、Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted会返回true,否则返回false表示授权失败。

架构图

在这里插入图片描述

实现代码

完整代码地址:https://gitee.com/bseaworkspace/springboot2all/tree/master/SpringBootShiroAuthorization

  • pom
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>SpringBoot2</artifactId><groupId>zz</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>SpringBootShiroAuthorization</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--目的:《可选》引入springboot 热启动,每次修改以后,会自动把改动加载,不需要重启服务了--><dependency> <groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><optional>true</optional></dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.15</version></dependency><!--  添加JPA的支持 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><!--  添加测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency><!-- shiro-spring --><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>1.4.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.6</version><scope>provided</scope></dependency></dependencies><repositories><repository><id>alimaven</id><name>aliyun maven</name><url>http://maven.aliyun.com/nexus/content/groups/public/</url></repository></repositories><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>

application.properties

server.port=9087
server.servlet.context-path=/r# 数据库的信息
spring.datasource.url = jdbc:mysql://localhost:3306/java10?useSSL=false&serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = Java20190713*yy
spring.datasource.driverClassName = com.mysql.cj.jdbc.Driver
spring.jpa.database = MYSQL
# spring.jpa.show-sql = true 表示会在控制台打印执行的sql语句
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update

三个实体类,
注意:

  • 不要放@Data在实体类上,会报死循环错误
  • 不要懒加载

权限实体类

package com.zz.entity;import lombok.Data;
import org.hibernate.annotations.Proxy;import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;/*** @Description: java类作用描述* @Author: Bsea* @CreateDate: 2019/8/31$ 15:54$*/
@Entity
@Table(name="T_PERMISSION")
@Proxy(lazy = false)
public class Permission implements Serializable {final static long serialVersionUID=23434243325424l;@Id@Column(length = 50)private String id;//url地址private String url;//url描述private String name;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String getName() {return name;}public void setName(String name) {this.name = name;}}

角色实体类

package com.zz.entity;import lombok.Data;
import org.hibernate.annotations.Proxy;import javax.persistence.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;/*** @Description: java类作用描述* @Author: Bsea* @CreateDate: 2019/8/31$ 15:54$*/
@Entity
@Table(name="T_ROLE")@Proxy(lazy = false)
public class Role implements Serializable {final static long serialVersionUID=234345424l;@Id@Column(length = 50)private String id;//角色描述private String detail;//角色名称private String name;// @ManyToMany注释表示Teacher是多对多关系的一端。// @JoinTable描述了多对多关系的数据表关系。name属性指定中间表名称,joinColumns定义中间表与Teacher表的外键关系。// 中间表Teacher_Student的Teacher_ID列是Teacher表的主键列对应的外键列,inverseJoinColumns属性定义了中间表与另外一端(Student)的外键关系。@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)@JoinTable(name = "T_ROLE_PERMISSION", joinColumns = { @JoinColumn(name = "r_id") }, inverseJoinColumns = {@JoinColumn(name = "p_id") })private Set<Permission> permissions = new HashSet<Permission>();public String getId() {return id;}public void setId(String id) {this.id = id;}public String getDetail() {return detail;}public void setDetail(String detail) {this.detail = detail;}public String getName() {return name;}public void setName(String name) {this.name = name;}public Set<Permission> getPermissions() {return permissions;}public void setPermissions(Set<Permission> permissions) {this.permissions = permissions;}}

用户实体类

package com.zz.entity;import lombok.Data;
import org.hibernate.annotations.Proxy;import java.io.Serializable;
import java.sql.Date;
import java.util.HashSet;
import java.util.Set;import javax.persistence.*;@Entity
@Table(name="T_USER")@Proxy(lazy = false)
public class User implements Serializable{final static long serialVersionUID=23424l;@Id@Column(length = 50)private String id;//用户名private String username;private String passwd;//是否有效 1:有效  0:锁定private String status;//创建时间private Date createTime;//使用 @ManyToMany 注解来映射多对多关联关系//使用 @JoinTable 来映射中间表//1. name 指向中间表的名字//2. joinColumns 映射当前类所在的表在中间表中的外键//2.1 name 指定外键列的列名//2.2 referencedColumnName 指定外键列关联当前表的哪一列//3. inverseJoinColumns 映射关联的类所在中间表的外键// @ManyToMany注释表示Teacher是多对多关系的一端。// @JoinTable描述了多对多关系的数据表关系。name属性指定中间表名称,joinColumns定义中间表与Teacher表的外键关系。// 中间表Teacher_Student的Teacher_ID列是Teacher表的主键列对应的外键列,inverseJoinColumns属性定义了中间表与另外一端(Student)的外键关系。@ManyToMany(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)@JoinTable(name = "T_USER_ROLE", joinColumns = { @JoinColumn(name = "u_id") },inverseJoinColumns = {@JoinColumn(name = "r_id") })private Set<Role> roles = new HashSet<Role>();public String getId() {return id;}public void setId(String id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPasswd() {return passwd;}public void setPasswd(String passwd) {this.passwd = passwd;}public String getStatus() {return status;}public void setStatus(String status) {this.status = status;}public Date getCreateTime() {return createTime;}public void setCreateTime(Date createTime) {this.createTime = createTime;}public Set<Role> getRoles() {return roles;}public void setRoles(Set<Role> roles) {this.roles = roles;}
}

Shiro

package com.zz.config;import java.util.LinkedHashMap;import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class ShiroConfig {@Beanpublic ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);shiroFilterFactoryBean.setLoginUrl("/login");shiroFilterFactoryBean.setSuccessUrl("/index");shiroFilterFactoryBean.setUnauthorizedUrl("/403");LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();filterChainDefinitionMap.put("/css/**", "anon");filterChainDefinitionMap.put("/js/**", "anon");filterChainDefinitionMap.put("/register.html", "anon");filterChainDefinitionMap.put("/fonts/**", "anon");filterChainDefinitionMap.put("/img/**", "anon");filterChainDefinitionMap.put("/druid/**", "anon");filterChainDefinitionMap.put("/logout", "logout");filterChainDefinitionMap.put("/user/register", "anon");filterChainDefinitionMap.put("/", "anon");filterChainDefinitionMap.put("/**", "user");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;}@Bean  public SecurityManager securityManager(){  DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();securityManager.setRealm(shiroRealm());securityManager.setRememberMeManager(rememberMeManager());return securityManager;  }  @Bean(name = "lifecycleBeanPostProcessor")public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {return new LifecycleBeanPostProcessor();}@Bean  public ShiroRealm shiroRealm(){  ShiroRealm shiroRealm = new ShiroRealm();  return shiroRealm;  }  /*** cookie对象* @return*/public SimpleCookie rememberMeCookie() {// 设置cookie名称,对应login.html页面的<input type="checkbox" name="rememberMe"/>SimpleCookie cookie = new SimpleCookie("rememberMe");// 设置cookie的过期时间,单位为秒,这里为一天cookie.setMaxAge(86400);return cookie;}/*** cookie管理对象* @return*/public CookieRememberMeManager rememberMeManager() {//Cookie 数据存在客户端的浏览器CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());// rememberMe cookie加密的密钥 cookieRememberMeManager.setCipherKey(Base64.decode("3AvVhmFLUs0KTA3Kprsdag=="));return cookieRememberMeManager;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);return authorizationAttributeSourceAdvisor;}}
  • ShiroRealm
package com.zz.config;import javax.annotation.Resource;import com.zz.entity.Permission;
import com.zz.entity.Role;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;import com.zz.entity.User;
import com.zz.repository.UserRepository;import java.util.HashSet;
import java.util.List;
import java.util.Set;//import com.springboot.dao.UserMapper;
//import com.springboot.pojo.User;
@Slf4j
public class ShiroRealm extends AuthorizingRealm {@Resourceprivate UserRepository userRepository;/*** 获取用户角色和权限*/@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {User user = (User) SecurityUtils.getSubject().getPrincipal();String userName = user.getUsername();System.out.println("用户" + userName + "获取权限-----ShiroRealm.doGetAuthorizationInfo");SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();// 获取用户角色集Set<String> roleSet = new HashSet<String>();Set<Permission> permissionList= new HashSet<Permission>();Set<Role> roles=user.getRoles();for (Role r : roles) {roleSet.add(r.getName());permissionList.addAll(r.getPermissions());}simpleAuthorizationInfo.setRoles(roleSet);// 获取用户权限集Set<String> permissionSet = new HashSet<String>();for (Permission p : permissionList) {permissionSet.add(p.getName());}simpleAuthorizationInfo.setStringPermissions(permissionSet);return simpleAuthorizationInfo;}/*** 登录认证*/@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {String userName = (String) token.getPrincipal();String password = new String((char[]) token.getCredentials());System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo");
//		User user = userMapper.findByUserName(userName);User user = userRepository.findByUsername(userName);
//		User user=new User();if (user == null) {throw new UnknownAccountException("用户名错误!");}//1. MD5加密不可以破解//2. 登录比较的是,两个密文if (!password.equals(user.getPasswd())) {throw new IncorrectCredentialsException("密码错误!");}if (user.getStatus().equals("0")) {throw new LockedAccountException("账号已被锁定,请联系管理员!");}SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());return info;}}

Controller

package com.zz.controller;import javax.annotation.Resource;import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import com.zz.entity.User;
import com.zz.pojo.ResponseBo;
import com.zz.service.UserService;
import com.zz.util.KeyUtil;
import com.zz.util.MD5Utils;@Controller
@RequestMapping("/user")
public class UserController {@RequiresPermissions("user:user")@RequestMapping("list")public String userList() {return "/index1.html";}@RequiresPermissions("user:add")@RequestMapping("add")public String userAdd(Model model) {model.addAttribute("value", "新增用户");return "/index1.html";}@RequiresPermissions("user:delete")@RequestMapping("delete")public String userDelete(Model model) {model.addAttribute("value", "删除用户");return "/index1.html";}@ResourceUserService userService;@GetMapping("/register")public String login() {return "register.html";}@PostMapping("/register")@ResponseBodypublic ResponseBo register(User user) {String password = MD5Utils.encrypt(user.getUsername(), user.getPasswd());user.setPasswd(password);user.setId(KeyUtil.genUniqueKey());userService.save(user);return ResponseBo.ok();}@RequestMapping("/")public String redirectIndex() {return "redirect:/index";}@RequestMapping("/index")public String index(Model model) {User user = (User) SecurityUtils.getSubject().getPrincipal();model.addAttribute("user", user);return "index1.html";}@PostMapping("/getlogin")@ResponseBodypublic User getLoginUser(){return (User) SecurityUtils.getSubject().getPrincipal();}
}

http://chatgpt.dhexx.cn/article/hK5aM87R.shtml

相关文章

Shiro: 权限管理

一、权限管理 1、什么是权限管理 权限管理属于系统安全的范畴&#xff0c;权限管理实现对用户访问系统的控制&#xff0c;按照安全规则或者安全策略控制用户可以访问且只能访问自己被授权的资源。   权限管理包括用户身份认证和授权两部分&#xff0c;简称认证授权。对于需要…

【权限管理框架】一文看懂Shiro权限管理框架!

文章目录 1.JavaWeb中的权限控制2.权限框架核心知识ACL和RBAC2.1.ACL和RBAC简介2.2主流权限框架介绍 3.Shiro架构和基本概念3.1.Shiro的4大核心模块3.2.Shiro权限控制运行流程 4.Shiro简单API案例4.1.项目搭建所需依赖4.2.Shiro认证简单实操4.3.Shiro授权简单实操 5.安全数据来…

【端口扫描工具】nmap核心使用方法

目录 nmap的基础使用&#xff1a; 1.1、常用命令参数&#xff1a; 命令格式&#xff1a; 主机发现&#xff1a; 扫描 扫描速度 扫描端口 1.2、基本扫描 1.3、自定义端口扫描 1.4、Ping扫描 1.5、路由追踪 1.6、扫描网段,C段 1.7、操作系统类型的探测 1.8、nmap万能…

【安全工具】Nmap基本使用方法

Nmap工具介绍 Nmap是一款开放源代码的网络探测和安全审核工具&#xff0c;它被设计用来快速扫描大型网络、包括主机探测与发现、开放的端口情况、操作系统与应用服务指纹、WAF识别及常见安全漏洞。 它的图形化界面是 Zenmap、分布式框架为 Dnmap Nmap功能 主机探测&#xf…

nmap工具使用方法

nmap工具使用方法 简介 Nmap&#xff08;网络映射器&#xff09;是一个用于网络探索和安全审计的开源工具 常用扫描端口命令 <nmap -sV 192.168.204.64> -sV&#xff1a;探测端口服务版本<nmap -T4 -A -v 192.168.204.64> -T4&#xff1a; 指定扫描过程使用的时…

nmap使用方法--方便自己查

在侦查期间&#xff0c;扫描一直是信息收集的初始阶段。 什么是侦查 侦查是尽可能多收集关于目标网络的信息。从黑客的角度来看&#xff0c;信息收集对于一次攻击非常有用&#xff0c;所以为了封锁恶意的企图&#xff0c;渗透测试者通常尽力查找这些信息&#xff0c;发现后修复…

端口扫描工具Nmap使用方法 day02

nmap是一个网络端口扫描软件&#xff0c;用来扫描网上电脑开放的网络连接端口&#xff0c;确定哪些服务运行在哪些端口&#xff0c;并且推断计算机运行哪个os。它是网络管理员必用的软件之一&#xff0c;渗透测试人员也可以用它评估网络系统安全。下面介绍kali linux中nmap的用…

nmap详细使用教程

目录 nmap简介 nmap常用命令 实例演示-发现主机 实例演示-端口发现 实例演示-获得服务版本详细信息 实例演示-确定主机操作系统 nmap简介 nmap是一款非常强大的主机发现和端口扫描工具&#xff0c;而且nmap运用自带的脚本&#xff0c;还能完成漏洞检测&#xff0c;同时支…

nmap常见使用方法

基础使用&#xff1a; 1.nmap ip 探测目标ip1-10000范围内所有开放端口 比如&#xff1a;扫描192.168.91.1 可以看见&#xff0c;已经扫描出目标IP对应的一些信息了 2.nmap -vv ip 简单扫描&#xff0c;输出详细结果&#xff08;一般没什么用&#xff09; nmap -p port ip …

Nmap 基本使用方法

一、下载工具包 进入官网下载安装包Download the Free Nmap Security Scanner for Linux/Mac/Windows 二、安装zenmap 工具 点击“下一步”安装完成。Zenmap 界面如下 三、Nmap使用 Nmap是主机扫描工具,他的图形化界面是Zenmap,分布式框架为Dnamp。 Nmap可以完成以下任务…

nmap 使用方法详细介绍

nmap的使用 前言nmap 作用Nmap使用教程nmap的基本输入&#xff1a;扫描参数&#xff1a;端口扫描&#xff1a;端口状态扫描&#xff1a;UDP扫描协议扫描 总结Nmap的基础知识Nmap的扫描技术Nmap的OS检测&#xff08;O&#xff09;Nmap的操作系统指纹识别技术&#xff1a; 前言 …

Nmap使用方法及常用命令学习

本文为学习笔记&#xff0c;仅限学习交流。不得利用、从事危害国家或人民安全、荣誉和利益等活动。 请参阅《中华人民共和国网络安全法》 7-30作业 —Nmap 练习 Nmap 是Network Mapper&#xff0c;中文为“网络映射器”。 Nmap 是一款开源的网络探测和安全审核的工具&#xff…

Nmap使用方法简析

NMAP 引子&#xff1a; Nmap&#xff0c; 是 Network Mapper 的缩写&#xff0c;由 Gordon Lyon 维护(更多关于 Mr. Lyon 的信息在这里: http://insecure.org/fyodor/) &#xff0c;并被世界各地许多的安全专业人员使用。 这个工具在 Linux 和 Windows 下都能使用&#xff0…

nmap使用方法详解

Nmap详解 Nmap&#xff08;网络映射器&#xff09;是一款开放源代码的网络探测和安全审核工具&#xff0c;它被设计用来快速扫描大型网络&#xff0c;包括主机探测与发现、开放的端口情况、操作系统与应用服务指纹识别、WAF识别及常见安全漏洞。 Nmap的特点&#xff1a; - 主机…

Nmap的使用方法总结

文章目录 Nmap的使用方法总结一&#xff1a;各种参数的使用1&#xff1a;ping扫描 —— nmap < 要扫描的目标ip地址>2&#xff1a;TCP SYN Ping扫描3&#xff1a;-PA TCP ACK Ping扫描4&#xff1a;半开扫描5&#xff1a;自定义端口扫描 nmap -P&#xff08;扫描范围&…

nmap使用方法

目录 第一、nmap使用 第一、nmap使用 1、nmap扫描一台服务器&#xff0c;默认扫描1000个最有可能开放的TCP端口。 2、-v显示详细信息 3、-p表示端口扫描。 扫描全部端口&#xff0c;查看开放了那些。 4、查看端口正在被那个进程使用 查看22端口正在被那个进程使用。 查看s…

Nmap使用教程图文教程(超详细)

kali的命令行中可以直接使用 nmap 命令&#xff0c;打开一个「终端」&#xff0c;输入 nmap 后回车&#xff0c;可以看到 nmap 的版本&#xff0c;证明 nmap 可用。 Nmap有四种基本功能&#xff1a;「端口扫描」、「主机探测」、「服务识别」和「系统识别」。 一、端口扫描 扫…

诗词——人间绝句

人生若只如初见&#xff0c;何事秋风悲画扇。 ——纳兰性德《木兰花令拟古决绝词谏友》 花自飘零水自流&#xff0c;一种相思&#xff0c;两处闲愁。 ——李清照《一剪梅红藕香残玉覃秋》 最是人间留不住&#xff0c;朱颜辞镜花辞树。 ——王国维《蝶恋花》 金风玉露一相逢&…

[《雪的散文诗》小个子的诗集]2012年8月28日

雪花吟 雪是冬的姑娘&#xff0c;冬把雪孕育。 什么时候起&#xff0c;没有了天朗气清。 沉寂灰朦&#xff0c;是天&#xff0c;是云&#xff0c;是气&#xff1f; 凝固最后一颗秋露&#xff0c;冰封最后一处溪流。 天动了&#xff0c;或者是云动了&#xff0c;亦或是气动了…

正版四字梅花诗:小户人家 梅花诗:怒发冲冠

正版四字梅花诗&#xff1a;小户人家 梅花诗&#xff1a;怒发冲冠 为您解答&#xff08;免费分享-2宵&#xff09;等待您的加入&#xff01; 107为您解答&#xff01;请威-芯 创建 Html 的时候报错