spring boot 整合 shiro 框架
创始人
2024-01-19 08:09:51

1、整合shiro

1.1、创建spring boot项目

1.2、引入依赖

org.apache.shiroshiro-spring-boot-web-starter1.9.0

com.baomidoumybatis-plus-boot-starter3.0.5


mysqlmysql-connector-java5.1.46

org.projectlomboklombok

org.springframework.bootspring-boot-starter-thymeleaf

1.3、添加配置文件

mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImplmapper-locations: classpath:mapper/*.xml
spring:datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://localhost:3306/shirodb?characterEncoding=utf-8&useSSL=falseusername: rootpassword: zzybzbjackson:date-format: yyyy-MM-dd HH:mm:sstime-zone: GMT+8
shiro:loginUrl: /myController/login

1.4、启动类添加扫描包注解

在这里插入图片描述

2、登录认证实现

2.1、库表

2.1.1、建表
CREATE DATABASE IF NOT EXISTS `shirodb` CHARACTER SET utf8mb4;
USE `shirodb`;
CREATE TABLE `user` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',`name` VARCHAR(30) DEFAULT NULL COMMENT '用户名',`pwd` VARCHAR(50) DEFAULT NULL COMMENT '密码',`rid` BIGINT(20) DEFAULT NULL COMMENT '角色编号',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='用户表';
2.1.2、密码加密,添加几条数据
public class ShiroMD5 {public static void main(String[] args) {String password = "123456";//为了保证安全,避免被破解还可以多次迭代加密,保证数据安全Md5Hash md53 = new Md5Hash(password,"salt",3);System.out.println("md5带盐的3次加密:"+md53.toHex());}
}

在这里插入图片描述

2.2、创建实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {private Integer id;private String name;private String pwd;private Integer rid;
}

2.3、创建 mapper

@Mapper
public interface UserMapper extends BaseMapper {
}

2.4、创建 service

public interface UserService {//用户登录User getUserInfoByName(String name);
}
@Service
public class UserServiceImpl implements UserService {private UserMapper userMapper;@Autowiredpublic UserServiceImpl(UserMapper userMapper) {this.userMapper = userMapper;}//根据姓名查询@Overridepublic User getUserInfoByName(String name) {QueryWrapper wrapper = new QueryWrapper<>();wrapper.eq("name",name);User user = userMapper.selectOne(wrapper);return user;}
}

2.5、自定义realm

@Component
public class MyRealm extends AuthorizingRealm {private UserService userService;@Autowiredpublic MyRealm(UserService userService){this.userService = userService;}@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}//自定义登录认证方法@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {//1获取用户身份信息String username = authenticationToken.getPrincipal().toString();//2调用业务层获取用户信息(数据库)User user = userService.getUserInfoByName(username);//3非空判断,将数据封装返回if (user != null){AuthenticationInfo info = new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),user.getPwd(),ByteSource.Util.bytes("salt"),authenticationToken.getPrincipal().toString());return info;}return null;}
}

2.6、配置类

@Configuration
public class ShiroConfig {private MyRealm myRealm;@Autowiredpublic ShiroConfig(MyRealm myRealm){this.myRealm = myRealm;}//配置SecurityManager@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(){//1创建defaultWebSecurityManager 对象DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//2创建加密对象,设置相关属性HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();//2.1采用md5加密matcher.setHashAlgorithmName("MD5");//2.2迭代加密次数matcher.setHashIterations(3);//3将加密对象存储到myRealm中myRealm.setCredentialsMatcher(matcher);//4将myRealm存入defaultWebSecurityManager 对象defaultWebSecurityManager.setRealm(myRealm);return defaultWebSecurityManager;}//配置Shiro内置过滤器拦截范围@Beanpublic DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();//设置不认证可以访问的资源definition.addPathDefinition("/my/userLogin","anon");definition.addPathDefinition("/my/login","anon");//设置登出过滤器definition.addPathDefinition("/logout","logout");//设置需要进行登录认证的拦截范围definition.addPathDefinition("/**","authc");//添加存在用户的过滤器(rememberMe)definition.addPathDefinition("/**","user");return  definition;}
}

2.7、controller

@Controller
@RequestMapping("/my")
public class MyController {@RequestMapping("/userLogin")@ResponseBodypublic String login(String username,String password){//1获取subject对象Subject subject = SecurityUtils.getSubject();//2封装请求数据到tokenAuthenticationToken token = new UsernamePasswordToken(username,password);//3调用login方法进行登录认证try {subject.login(token);return "登录成功";} catch (AuthenticationException e) {e.printStackTrace();return "登录失败";}}
}

2.8、访问,测试

在这里插入图片描述在这里插入图片描述

2.9、实现前端页面

2.9.1、Thymeleaf依赖
dependency>org.springframework.bootspring-boot-starter-thymeleaf

2.9.2、login 页面


Title


Shiro登录认证


用户名:
密码:
2.9.3、添加 index 页面


Title

Shiro登录认证后主页面


登录用户为:
2.9.4、添加 controller 方法,改造认证方法
	//跳转登录页面@RequestMapping("/login")public String login(){return "login";}

在这里插入图片描述

2.9.5、修改配置文件

在这里插入图片描述

2.9.6、修改配置类

在这里插入图片描述

2.9.7、访问,测试

在这里插入图片描述
在这里插入图片描述

3、多个 realm 的认证策略设置

3.1、多个realm实现原理

当应用程序配置多个 Realm 时,例如:用户名密码校验、手机号验证码校验等等。
Shiro 的 ModularRealmAuthenticator 会使用内部的 AuthenticationStrategy 组件判断认证是成功还是失败。
AuthenticationStrategy 是一个无状态的组件,它在身份验证尝试中被询问 4 次(这4 次交互所需的任何必要的状态将被作为方法参数):

  1. 在所有 Realm 被调用之前
  2. 在调用 Realm 的 getAuthenticationInfo 方法之前
  3. 在调用 Realm 的 getAuthenticationInfo 方法之后
  4. 在所有 Realm 被调用之后

认证策略的另外一项工作就是聚合所有 Realm 的结果信息封装至一个
AuthenticationInfo 实例中,并将此信息返回,以此作为 Subject 的身份信息。

Shiro 中定义了 3 种认证策略的实现:

  • AtLeastOneSuccessfulStrategy
    只要有一个(或更多)的 Realm 验证成功,那么认证将视为成功。

  • FirstSuccessfulStrategy
    第一个 Realm 验证成功,整体认证将视为成功,且后续 Realm 将被忽略。

  • AllSuccessfulStrategy
    所有 Realm 成功,认证才视为成功。

ModularRealmAuthenticator 内置的认证策略默认实现是
AtLeastOneSuccessfulStrategy 方式。可以通过配置修改策略。

3.2、多个realm代码实现

//配置 SecurityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){//1 创建 defaultWebSecurityManager 对象DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();//2 创建认证对象,并设置认证策略ModularRealmAuthenticator modularRealmAuthenticator = new ModularRealmAuthenticator();modularRealmAuthenticator.setAuthenticationStrategy(new AllSuccessfulStrategy());defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);//3 封装 myRealm 集合List list = new ArrayList<>();list.add(myRealm);list.add(myRealm2);//4 将 myRealm 存入 defaultWebSecurityManager 对象defaultWebSecurityManager.setRealms(list);//5 返回return defaultWebSecurityManager;
}

4、remember me 功能

Shiro 提供了记住我(RememberMe)的功能,比如访问一些网站时,关闭了浏览器,下次再打开时还是能记住你是谁, 下次访问时无需再登录即可访问。

4.1、基本流程

  1. 首先在登录页面选中 RememberMe 然后登录成功;如果是浏览器登录,一般会 把 RememberMe 的 Cookie 写到客户端并保存下来。
  2. 关闭浏览器再重新打开;会发现浏览器还是记住你的。
  3. 访问一般的网页服务器端,仍然知道你是谁,且能正常访问。
  4. 但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还是需要再进行身份认证的,以确保当前用户还是你。

4.2、代码实现

4.2.1、修改配置类
 //cookie属性设置public SimpleCookie rememberMeCookie(){SimpleCookie cookie = new SimpleCookie("rememberMe");//设置跨域//cookie.setDomain(domain);cookie.setPath("/");cookie.setHttpOnly(true);cookie.setMaxAge(30*24*60*60);return cookie;}//创建Shiro的cookie管理对象public CookieRememberMeManager rememberMeManager(){CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();cookieRememberMeManager.setCookie(rememberMeCookie());cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());return cookieRememberMeManager;}
defaultWebSecurityManager.setRememberMeManager(rememberMeManager());

在这里插入图片描述
在这里插入图片描述

4.2.2、添加,修改 controller

添加

	//登录认证验证 rememberMe@GetMapping("userLoginRm")public String userLogin(HttpSession session) {session.setAttribute("user","rememberMe");return "index";}

修改
在这里插入图片描述

4.2.3、修改登录页面
记住用户:

在这里插入图片描述

4.3、访问测试

4.3.1、未勾选
  • 登录
    -
-

在这里插入图片描述

  • 访问userLoginRm
    在这里插入图片描述
  • 关掉浏览器后打开,重新访问
    在这里插入图片描述
4.3.2、勾选“记住我”
  • 登录

在这里插入图片描述
在这里插入图片描述

  • 关掉浏览器再访问
    在这里插入图片描述

5、退出

用户登录后,配套的有登出操作。直接通过Shiro过滤器即可实现登出。

5.1、index页面

登出

5.2、修改配置类

//设置登出过滤器
definition.addPathDefinition("/logout","logout");

在这里插入图片描述

5.3、测试

在这里插入图片描述在这里插入图片描述

6、授权、角色认证

6.1、授权

用户登录后,需要验证是否具有指定角色指定权限。Shiro也提供了方便的工具进行判断。这个工具就是Realm的doGetAuthorizationInfo方法进行判断。

触发权限判断的有两种方式

  1. 在页面中通过shiro:****属性判断
  2. 在接口服务中通过注解@Requires****进行判断

6.2、后端接口服务注解

通过给接口服务方法添加注解可以实现权限校验,可以加在控制器方法上,也可以加在业务方法上,一般加在控制器方法上。常用注解如下:

  • @RequiresAuthentication
    验证用户是否登录,等同于方法subject.isAuthenticated()

  • @RequiresUser
    验证用户是否被记忆:
    登录认证成功subject.isAuthenticated()为true。
    登录后被记忆subject.isRemembered()为true。

  • @RequiresGuest
    验证是否是一个guest的请求,是否是游客的请求。
    此时subject.getPrincipal()为null。

  • @RequiresRoles

    验证subject是否有相应角色,有角色访问方法,没有则会抛出异常AuthorizationException。
    例如:

@RequiresRoles(“aRoleName”)//只有subject有aRoleName角色才能访问方法someMethod()
void someMethod();
  • @RequiresPermissions
    验证subject是否有相应权限,有权限访问方法,没有则会抛出异常AuthorizationException。
    例如:
@RequiresPermissions ("file:read","wite:aFile.txt")//subject必须同时含有file:read和wite:aFile.txt权限才能访问方法someMethod()
void someMethod();

6.3、授权验证-没有角色无法访问

6.3.1、controller代码
	//登录认证验证角色@RequiresRoles("admin")@GetMapping("userLoginRoles")@ResponseBodypublic String userLoginRoles(){System.out.println("登录认证验证角色");return "验证角色成功";}
6.3.2、index页面
测试授权-角色验证
6.3.3、修改MyRealm类的doGetAuthorizationInfo方法

在这里插入图片描述

6.3.4、测试,没有admin角色,会报错

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.4、授权验证-获取角色进行验证

6.4.1、修改 MyRealm 方法

自定义授权方法:获取当前登录用户权限信息,返回给 Shiro 用来进行授权对比

SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//自定义添加角色
info.addRole("admin");

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

6.4.2、角色表,用户-角色中间表
CREATE TABLE `role` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',`name` VARCHAR(30) DEFAULT NULL COMMENT '角色名',`desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',`realname` VARCHAR(20) DEFAULT NULL COMMENT '角色显示名',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色表';CREATE TABLE `role_user` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',`uid` BIGINT(20) DEFAULT NULL COMMENT '用户 id',`rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色用户映射
表';

自定义数据–角色表
在这里插入图片描述

自定义数据–用户角色中间表
在这里插入图片描述

6.4.3、查询 sql

根据用户名查询对应角色信息

SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE 
uid=(SELECT id FROM USER WHERE NAME='zhangsan'));

在这里插入图片描述

6.4.4、mapper 方法
@Select("SELECT NAME FROM role WHERE id IN (SELECT rid FROM role_user WHERE uid=(SELECT id FROM USER WHERE NAME=#{principal}))")
List getUserRoleInfoMapper(@Param("principal")String principal );
6.4.5、service 方法
/**
* 根据用户查询角色
* @param principal
* @return
*/
@Override
public List getUserRoleInfo(String principal) {return userMapper.getUserRoleInfoMapper(principal);
}
6.4.6、MyRealm 方法改造
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {System.out.println("进入自定义授权方法");//1获取用户身份信息String principal = principalCollection.getPrimaryPrincipal().toString();//2调用业务层获取用户的角色信息(数据库)List roles = userService.getUserRoleInfo(principal);System.out.println("当前用户角色信息 = " + roles);//2.5调用业务层获取用户的权限信息(数据库)//3创建对象,封装当前登录用户的角色、权限信息SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//自定义添加角色info.addRoles(roles);//返回信息return info;
}
6.4.7、启动测试

在这里插入图片描述在这里插入图片描述

6.5、授权验证-获取权限进行验证

6.5.1、权限表(菜单表),角色权限中间表
CREATE TABLE `permissions` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',`name` VARCHAR(30) DEFAULT NULL COMMENT '权限名',`info` VARCHAR(30) DEFAULT NULL COMMENT '权限信息',`desc` VARCHAR(50) DEFAULT NULL COMMENT '描述',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='权限表';CREATE TABLE `role_ps` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '编号',`rid` BIGINT(20) DEFAULT NULL COMMENT '角色 id',`pid` BIGINT(20) DEFAULT NULL COMMENT '权限 id',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='角色权限映射表';

自定义数据–权限表
在这里插入图片描述

自定义数据–角色权限表

在这里插入图片描述

6.5.2、查询 sql

根据角色名查询对应权限信息

SELECT info FROM permissions WHERE id IN (SELECT pid FROM role_ps WHERE rid 
IN (SELECT id FROM role WHERE NAME IN('admin','user')));
6.5.3、mapper 方法
    @Select({""})List getUserPermissionInfoMapper(@Param("roles")List roles);
6.5.4、service代码
/*** 根据角色查看权限* @param roles* @return*/@Overridepublic List getUserPermissionInfo(List roles) {return userMapper.getUserPermissionInfoMapper(roles);}
6.5.5、realm代码

在这里插入图片描述

6.5.6、controller 方法
	//登录认证验证权限@RequiresPermissions("user:del")@GetMapping("userPermissions")@ResponseBodypublic String userLoginPermissions(){System.out.println("登录认证验证权限");return "验证权限成功";}
6.5.7、index页面
测试授权-权限验证
6.5.8、测试

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

6.6、授权验证-异常处理

创建认证异常处理类,使用@ControllerAdvice 加@ExceptionHandler 实现特殊异常处理。

package com.bz.shiro.controller;import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
public class PermissionsException {@ResponseBody@ExceptionHandler(UnauthorizedException.class)public String unauthorizedException(Exception e){return "无权限";}@ResponseBody@ExceptionHandler(AuthorizationException.class)public String authorizationException(Exception e){return "权限认证失败";}}

lisi账号登录
在这里插入图片描述在这里插入图片描述

6.7、前页面授权验证

6.7.1、引入依赖

com.github.theborakompanionithymeleaf-extras-shiro2.0.0

6.7.2、配置类添加新配置
	@Beanpublic ShiroDialect shiroDialect(){return new ShiroDialect();}
6.7.3、Thymeleaf 中常用的 shiro:属性
  • guest 标签
    用户没有身份验证时显示相应信息,即游客访问信息。

  • user 标签
    用户已经身份验证/记住我登录后显示相应的信息。

  • authenticated 标签
    用户已经身份验证通过,即 Subject.login 登录成功,不是记住我登录的。

  • notAuthenticated 标签
    用户已经身份验证通过,即没有调用 Subject.login 进行登录,包括记住我自动登录的也属于未进行身份验证。

  • principal 标签
    相当于((User)Subject.getPrincipals()).getUsername()。

  • lacksPermission 标签
    如果当前 Subject 没有权限将显示 body 体内容。

  • hasRole 标签
    如果当前 Subject 有角色将显示 body 体内容。

  • hasAnyRoles 标签
    如果当前 Subject 有任意一个角色(或的关系)将显示 body 体内容。

  • lacksRole 标签
    如果当前 Subject 没有角色将显示 body 体内容。

  • hasPermission 标签
    如果当前 Subject 有权限将显示 body 体内容

6.7.4、修改index页面

在这里插入图片描述在这里插入图片描述

  • zhangsan登录

在这里插入图片描述
在这里插入图片描述

  • lisi登录
    在这里插入图片描述在这里插入图片描述

7、实现缓存

7.1、缓存工具EhCache

EhCache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。可以和大部分Java项目无缝整合,例如:Hibernate中的缓存就是基于EhCache实现的。

EhCache支持内存和磁盘存储,默认存储在内存中,如内存不够时把缓存数据同步到磁盘中。EhCache支持基于Filter的Cache实现,也支持Gzip压缩算法。

EhCache直接在JVM虚拟机中缓存,速度快,效率高;
EhCache缺点是缓存共享麻烦,集群分布式应用使用不方便。

7.2、新建项目

7.2.1、引入依赖
net.sf.ehcacheehcache2.6.11pom

7.2.2、添加配置文件 ehcache.xml


7.2.3、测试类
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;import java.io.InputStream;public class TestEH {public static void main(String[] args) {//获取编译目录下的资源的流对象InputStream input =TestEH.class.getClassLoader().getResourceAsStream("ehcache.xml");//获取EhCache的缓存管理对象CacheManager cacheManager = new CacheManager(input);//获取缓存对象Cache cache = cacheManager.getCache("HelloWorldCache");//创建缓存数据Element element = new Element("name","zhang3");//存入缓存cache.put(element);//从缓存中取出数据输出Element element1 = cache.get("name");System.out.println("缓存中数据 = " + element1.getObjectValue());}
}
7.2.4、启动

在这里插入图片描述

7.3、Shiro整合EhCache

Shiro官方提供了shiro-ehcache,实现了整合EhCache作为Shiro的缓存工具。可以缓存认证执行的Realm方法,减少对数据库的访问,提高认证效率。

7.3.1、引入依赖
 
org.apache.shiroshiro-ehcache1.4.2

commons-iocommons-io2.6

7.3.2、在 resources 下添加配置文件 ehcache/ehcache-shiro.xml


7.3.3、修改配置类 ShiroConfig
	//缓存管理器public EhCacheManager getEhCacheManager(){EhCacheManager ehCacheManager = new EhCacheManager();InputStream is =null;try {is = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");} catch (IOException e) {e.printStackTrace();}CacheManager cacheManager = new CacheManager(is);ehCacheManager.setCacheManager(cacheManager);return ehCacheManager;}

在这里插入图片描述在这里插入图片描述

7.3.4、测试
  • 第一次登录可以看到查询角色、权限信息
    在这里插入图片描述

在这里插入图片描述在这里插入图片描述在这里插入图片描述

  • 先清除日志,再点击角色认证、权限认证,查看日志,没有查询数据库

    在这里插入图片描述 在这里插入图片描述

8、会话管理

8.1、SessionManager

会话管理器,负责创建和管理用户的会话(Session)生命周期,它能够在任何环境中在本地管理用户会话,即使没有Web/Servlet/EJB容器,也一样可以保存会话。默认情况下,Shiro会检测当前环境中现有的会话机制(比如Servlet容器)进行适配,如果没有(比如独立应用程序或者非Web环境),它将会使用内置的企业会话管理器来提供相应的会话管理服务,其中还涉及一个名为SessionDAO的对象。SessionDAO负责Session的持久化操作(CRUD),允许Session数据写入到后端持久化数据库。

8.2、会话管理实现

SessionManager由SecurityManager管理。
Shiro提供了三种实现
在这里插入图片描述

  1. DefaultSessionManager:用于JavaSE环境
  2. ServletContainerSessionManager:用于web环境,直接使用Servlet容器的会话
  3. DefaultWebSessionManager:用于web环境,自己维护会话(不使用Servlet容器的 会话管理)。

8.3、获得session方式

  1. 实现
Session session = SecurityUtils.getSubject().getSession();
session.setAttribute(“key”,”value”)
  1. 说明

    Controller 中的 request,在 shiro 过滤器中的 doFilerInternal 方法,被包装成ShiroHttpServletRequest。

    SecurityManager 和 SessionManager 会话管理器决定 session 来源于 ServletRequest还是由 Shiro 管理的会话。

    无论是通过 request.getSession 或 subject.getSession 获取到 session,操作session,两者都是等价的。

结束!!!

							人应尊敬他自己,并应自视能配得上最高尚的东西。——黑格尔

上一篇:麦德龙

下一篇:龙州十首之三

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
苁蓉的食用方法 鲜苁蓉的吃法有... 肉苁蓉号称“温而不热,补而不峻,暖而不燥,滑而不泄,故有从容之名。”历来也是传统药食同源的滋补佳品。...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...