幼儿饰品瑜伽美体用品微软
投稿投诉
微软创意
爱情通信
用品婚姻
爱好看病
美体软件
影音星座
瑜伽周边
星座办公
饰品塑形
搞笑减肥
幼儿两性
智家潮品

告别session,还是这个认证方案优秀

  大家好,我是杰哥
  互联网系统,几乎都离不开认证
  一个系统中的大部分功能只能有认证信息的用户访问,但是总不可能每次请求都要求客户端专门认证一次吧,要是那样的话,用户每点一次鼠标,就得输入一次用户名密码,那可真是太麻烦了
  那么,如何解决这种情况呢?一如何实现认证?(一)session机制
  一种解决方案是由服务器将session数据保存至数据库(mysql、reids等)中。服务收到请求后,都向持久层请求数据进行认证操作。也就是我们最初学习WEB项目时比较简单直观的CookiesSession机制,相对于其他方案,常被叫做Session机制
  Session机制的流程如下:
  1、用户输入登录信息(比如用户名密码),由客户端传递至服务端
  2、服务端验证无误之后,将Session存储至持久层
  3、服务端,返回带有sessionID的Cookie(头部SetCookie)
  4、客户端,保存Cookie信息。将JSESSIONID保存至Cookie中
  5、客户端请求服务端时,携带着Cookie
  6、服务端检查是否存在对应的sessionID
  7、若存在,则通过认证,服务端返回响应内容;否则,则返回403禁止访问
  这种机制,其实架构还是比较清晰的。但是会存在以下几个缺点:开销大。session保存在服务器,随着注册用户的增加,必然会引起服务器更大的开销扩展能力受限。对于分布式环境,如果采用Session机制进行认证,那么,就需要每台服务器保存或者共享所有用户的session信息。有时候为了解决这种session共享的问题,会采用redis集群存储session的方式来解决。但是这样相对来说复杂度会随之增大CSRF危险。Session是基于Cookie来进行用户识别的,Cookie如果被截获,用户就会很容易受到跨站请求伪造(CSRF)的攻击于是便出现了另一种解决方案
  于是,便渐渐衍生出另一种解决方案:JWT机制(二)JWT机制
  1认证流程
  通俗来讲,JSONWebToken(JWT)是一个含签名并携带用户相关信息的加密串,页面请求校验登录接口时,请求头中携带JWT串到后端服务,后端通过签名加密串匹配校验,保证信息未被篡改。校验通过则认为是可靠的请求,将正常返回数据
  相较于Session机制来说,JWT机制,服务器干脆不保存session数据了,所有认证信息只存储在客户端
  服务器端只保留一个秘钥,每次进行认证时,只需要通过这个秘钥,重新加密签名之后,与客户端所传递的token信息进行对比即可
  因此,其流程与Session机制差不多,只是少了服务器存储token信息的步骤,并且校验token时,是服务端重新加密生成之后与所收到的token值进行对比的,而不是通过查询持久层获得
  流程如下:
  1)用户输入登录信息(比如用户名密码)来请求服务器
  2)服务器验证用户的信息
  3)通过验证之后,服务器会返回一个token
  4)客户端存储token(可以选择存储在Cookie中,也可以选择存储在localStorage中)
  5)客户端在请求时一般会通过请求头,携带这个token值
  6)服务端会使用秘钥以及用户的相关信息重新计算生成一个token,然后验证所传递的这个token值
  7)若验证成功,则返回数据;否则,返回403禁止访问
  2token的样子
  了解了JWT的流程,我们来看下JWT生成的token长什么样
  杰哥项目中刚才生成的token字符串如下:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9。eyJwYXNzd29yZCI6IjUzYjQzMmU2MTMxNGUwMGJjYzk5Mjg3YWY5NTM3ZGM0IiwiaXNzIjoiamllZ2UiLCJleHAiOjE2NTk0NjM4ODUsImlhdCI6MTY1OTQyNzg4NSwidXNlcm5hbWUiOiJhZG1pbiJ9。z4NFlH92V0fzOxWmxfrsxBb6dIfkMUOdj9slINKVPu8
  乍一看,好像是一堆乱码,其实是由三部分组成:header(头部)、payload(载荷)、signature(签名),以。进行分割,
  即:
  header。payload。signature
  Header
  header用来声明类型(typ)和算法(alg){typ:JWT,alg:HS256}
  alg属性表示签名的算法(algorithm),默认是HMACSHA256(写成HS256)
  typ属性表示这个令牌(token)的类型(type),JWT令牌统一写为JWT。
  这个JSON对象使用Base64URL算法转成字符串,就变成上面token字符串的第一部分了
  Payload
  payload一般存放一些不敏感的信息,比如用户名、权限、角色等。{iss:jiege,exp:1659463885,iat:1659427885,username:admin}
  除了传递用户信息以外,payload也可以传递JWT所规定的7个官方字段:iss(issuer):签发人exp(expirationtime):过期时间sub(subject):主题aud(audience):受众nbf(NotBefore):生效时间iat(IssuedAt):签发时间jti(JWTID):编号
  这个JSON对象使用Base64URL算法转成字符串,就变成上面token字符串的第二部分了
  Signature
  signature则是将header和payload对应的JSON结构进行base64url编码之后得到的两个串用英文句点号拼接起来,然后根据header里面alg指定的签名算法生成出来的
  HMACSHA256(
  base64UrlEncode(header)。
  base64UrlEncode(payload),
  )secretbase64encoded
  注意:前面提到,Header和Payload串型化的算法是Base64URL。这个算法跟Base64算法基本类似,但有一些小的不同。
  JWT作为一个令牌(token),有些场合可能会放到URL(比如api。example。com?tokenxxx)。Base64有三个字符、和,在URL里面有特殊含义,所以要被替换掉:被省略、替换成,替换成二JWT实战
  好了,认识了JWT以后,我们趁热打铁,进入实战环节,通过一个简单的例子,来进一步认识JWT
  1引入依赖dependencygroupIdcom。auth0groupIdjavajwtartifactIdversion3。7。0versiondependency
  引入javajwt的依赖
  2配置文件application。ymlserver:port:8086spring:datasource:url:jdbc:mysql:localhost:3306jwtdemo?serverTimezoneUTCuseUnicodetruecharacterEncodingUTF8autoReconnecttrueuseSSLfalseusername:rootpassword:123456profiles:默认配置为dev,会在开发调试时跳过token的校验,提高调试效率active:prod
  分别配置数据库的连接信息和环境信息
  这里的环境信息配置为dev,只是为了在项目中的开发环境中,避免进行每次发起请求时token的校验,从而提高调试效率
  3访问资源定义
  访问资源:UserControllerRestControllerRequestMapping(user)publicclassUserController{GetMapping(common)publicStringcommon(){returnhellocommon;}GetMapping(admin)publicStringadmin(){returnhelloadmin;}}
  分别定义usercommon和useradmin两个接口作为后续的测试访问资源
  4User类DataBuilderpublicclassUser{privateLongid;privateStringusername;privateStringpassword;privateStringtoken;刷新tokenprivateStringrefreshToken;}
  定义User类,分别包含用户名、密码、token以及refreshToken
  5JWT的工具类JwtServiceSlf4jServicepublicclassJwtService{加密秘钥privatestaticfinalStringSECRETKEYwangjienihao;签发人privatestaticfinalStringISSUERjiege;token过期时间publicstaticfinalLongTOKENEXSPIRETIME1000606010L;生成tokenparamuserVo用户信息returnpublicStringtoken(UserVouserVo){1确定加密算法AlgorithmalgorithmAlgorithm。HMAC256(SECRETKEY);DatenownewDate();2开始创建和生成tokenreturnJWT。create()。withIssuedAt(now)。withIssuer(ISSUER)。withExpiresAt(newDate(now。getTime()TOKENEXSPIRETIME))token的过期时间。withClaim(username,userVo。getUsername())。withClaim(password,userVo。getPassword())。sign(algorithm);}校验用户名paramtokentokenparamusername用户名returnpublicResponseResultverifyUsername(Stringtoken,Stringusername){log。info(verifyjwtusername{},username);ResponseResultresponseResultnewResponseResult();try{1定义算法AlgorithmalgorithmAlgorithm。HMAC256(SECRETKEY);2进行校验JWTVerifierjwtVerifierJWT。require(algorithm)。withIssuer(ISSUER)。withClaim(username,username)。build();jwtVerifier。verify(token);}catch(Exceptionex){responseResult。setStatus(1);responseResult。setMessage(失败!);log。error(authverifyfail:{},ex。getMessage());}returnresponseResult;}}
  分别包括生成token方法和校验用户名的方法
  1)生成token生成tokenparamuserVo用户信息returnpublicStringtoken(UserVouserVo){1确定加密算法AlgorithmalgorithmAlgorithm。HMAC256(SECRETKEY);DatenownewDate();2开始创建和生成tokenreturnJWT。create()payload信息开始。withIssuedAt(now)。withIssuer(ISSUER)。withExpiresAt(newDate(now。getTime()TOKENEXSPIRETIME))token的过期时间。withClaim(username,userVo。getUsername())。withClaim(password,userVo。getPassword())payload信息结束签名。sign(algorithm);}
  预先定义一个加密秘钥SECRETKEY:wangjienihao,并确定加密算法为HMAC256
  采用JWT。create()方法,分别添加了签发时间、签发人、token有效期、用户名、密码这几个信息作为payload,然后采用加密算法进行加密,从而生成token
  这里的head定义为了:{typ:JWT,alg:HS256}
  Payload定义为了:{password:53b432e61314e00bcc99287af9537dc4,iss:jiege,exp:1659463885,iat:1659427885,username:admin}
  而其签名Signature则为:HMACSHA256(base64UrlEncode(header)。base64UrlEncode(payload),)secretbase64encoded
  2)验证token
  一般服务端需要校验客户端请求时所携带的token是否正确或者是否过期,就需要以下的方法进行校验校验用户名paramtokentokenparamusername用户名returnpublicResponseResultverifyUsername(Stringtoken,Stringusername){log。info(verifyjwtusername{},username);ResponseResultresponseResultnewResponseResult();try{1定义算法AlgorithmalgorithmAlgorithm。HMAC256(SECRETKEY);2进行校验JWTVerifierjwtVerifierJWT。require(algorithm)。withIssuer(ISSUER)。withClaim(username,username)。build();jwtVerifier。verify(token);}catch(Exceptionex){responseResult。setStatus(1);responseResult。setMessage(失败!);log。error(authverifyfail:{},ex。getMessage());}returnresponseResult;}
  首先,依旧是根据已知的秘钥与加密算法,获得加密算法对象algorithm;
  然后采用该算法对象、签发人、用户名等信息生成JWTVerifier对象;
  接着,调用JWTVerifier的verify()方法,进行用户名的校验
  verify()方法,会根据token,解密出token中的三部分信息,如官网中解析出来的样子
  而我们添加了一个当前的用户名:admin,它会将这个用户名与解密出的payload中的用户名进行比较,如果一致,则表示验证成功,否则验证失败
  可以顺便来看下JWTVerifier的verify()方法:
  1)首先根据token,采用parser生成一个JWTDecoder对象
  2)进入JWTDecoder构造方法
  分别解析出头部header和payload部分的json字符串
  3)再退出来,来到verify(jwt)方法
  如上所示,分别校验如下3个部分
  a。verifyAlgorithm(jwt,algorithm):校验获取到的jwt的加密方式和发送方的加密方式是否相同
  b。algorithm。verify(jwt):通过加密方式的名称,秘钥和头部信息,实体信息等校验获取到的jwt的Signature和发送方的Signature是否一致
  c。verifyClaims(jwt,this。claims):校验payload中的具体数据,如username、签发人等
  好了,JwtService类就完成了,接下来,我们就需要分别实现在用户登录时生成token,而在接到客户端的请求时,进行token的校验工作了
  6登录LoginController
  一般来讲,正如Session会存在过期时间,token也是会存在过期时间的,比如过了1个小时,token过期了,就需要重新生成token了RestControllerpublicclassLoginController{ResourceprivateJwtServicejwtService;ResourceprivateUserServiceuserService;ResourceprivateRedisTemplateString,UserVoredisTemplate;PostMapping(jwtlogin)publicResponseResultlogin(Stringusername,Stringpassword)throwsException{1校验用户名密码是否为空if(StrUtil。isBlank(username)StrUtil。isBlank(password)){thrownewException(用户名或密码不能为空!);}2根据用户查询用户是否存在UseruseruserService。findByUsername(username);if(usernull){thrownewException(用户名或密码有误!);}3验证用户名密码passwordMD5Util。md5slat(password);if(!password。equalsIgnoreCase(user。getPassword())){thrownewException(用户名或密码有误!);}4生成tokenUserVouserVoUserVo。builder()。build();userVo。setId(user。getId());userVo。setUsername(username);userVo。setPassword(password);StringtokenjwtService。token(userVo);userVo。setToken(token);userVo。setRefreshToken(UUID。randomUUID()。toString());同时存储用户到redis中redisTemplate。opsForValue()。set(token,userVo,JwtService。TOKENEXSPIRETIME,TimeUnit。SECONDS);returnnewResponseResult(userVo);}PostMapping(refreshToken)publicResponseResultrefreshToken(RequestParam(token)StringoldToken){1获取tokenUserVouserVoredisTemplate。opsForValue()。get(oldToken);if(userVonull){returnnewResponseResult(500,usernotfound!,null);}StringtokenjwtService。token(userVo);userVo。setToken(token);userVo。setRefreshToken(UUID。randomUUID()。toString());同时存储用户到redis中redisTemplate。delete(oldToken);redisTemplate。opsForValue()。set(token,userVo,JwtService。TOKENEXSPIRETIME10000,TimeUnit。SECONDS);returnnewResponseResult(userVo);}}
  这里分别定义了登录接口jwtlogin和刷新token接口refreshToken
  1)登录接口
  分别校验了用户名密码是否为空、用户名是否存在以及用户名密码是否正确之后,便可以生成token操作,并将其存入redis中,同时采用UUID的随机数,生成refreshToken
  调用jwtService。token()方法,传递的参数为userVo对象
  其实,你可能也发现了,如果考虑token的刷新,将token存入redis中,实际上也类似于Session机制的做法了,因为它也将token存储在了服务器
  所以,token的优势,并不在于扩展性,其实主要还是在于在进行token认证时,直接计算生成token,与客户端所携带的token进行对比,而不是从持久层中查询,从而对于大用户量的系统,比较明显地提升了性能
  2)刷新token
  其实就是获取token,然后重新生成token,并存储在redis中
  可以考虑由前端在访问某个功能调用的时候,若检测到token过期,然后调用refreshToken接口进行token的刷新操作
  7请求时拦截
  1)拦截器Slf4jpublicclassAuthorisationInterceptorimplementsHandlerInterceptor{AutowiredprivateJwtServicejwtService;Value({spring。profiles。active})privateStringprofiles;privatestaticfinalStringAUTHAuthorization;privatestaticfinalStringAUTHUSERNAMEusername;OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{log。info(执行了AuthorisationInterceptor的preHandle方法);1过滤开发环境,开发环境不需要验证tokenif(!StrUtil。isBlank(profiles)dev。equals(profiles)){returntrue;}2ignoreToken,不需要验证tokenif(ignoreToken((HandlerMethod)handler))returntrue;3获取tokenStringtokengetParamValue(request,AUTH);4获取并验证usernameStringusernamegetParamValue(request,AUTHUSERNAME);ResponseResultresponseResultjwtService。verifyUsername(token,username);if(responseResult。getStatus()!1){log。error(用户名校验失败);thrownewValidationException(300,用户名校验失败!);}这里需要注意:1)如果设置为false时,被请求时,拦截器执行到此处将不会继续操作2)如果设置为true时,请求将会继续执行后面的操作returntrue;}OverridepublicvoidpostHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,ModelAndViewmodelAndView)throwsException{log。info(执行了AuthorisationInterceptor的postHandle方法);}OverridepublicvoidafterCompletion(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler,Exceptionex)throwsException{log。info(执行了AuthorisationInterceptor的afterCompletion方法);}privateStringgetParamValue(HttpServletRequestrequest,Stringfiled)throwsValidationException{StringvaluegetParam(request,filed);if(StrUtil。isEmpty(value)){thrownewValidationException(300,filed不允许为空,请重新登录!);}returnvalue;}获取参数的值若参数中不存在,则从请求头中获取paramrequest请求paramfiledName参数名称returnprivatestaticStringgetParam(HttpServletRequestrequest,StringfiledName){Stringparamrequest。getParameter(filedName);if(StrUtil。isEmpty(param)){paramrequest。getHeader(filedName);}returnparam;}忽略token的处理paramhandlerreturnprivatebooleanignoreToken(HandlerMethodhandler){Methodmethodhandler。getMethod();if(method。isAnnotationPresent(IgnoreToken。class)){IgnoreTokenignoreTokenmethod。getAnnotation(IgnoreToken。class);returnignoreToken。required();}returnfalse;}}
  通过实现HandlerInterceptor,定义Spring拦截器类AuthorisationInterceptor来进行token的拦截验证,当然是在调用接口之前进行处理,所以,我们的逻辑主要由其preHandle()方法实现OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{log。info(执行了AuthorisationInterceptor的preHandle方法);1过滤开发环境,开发环境不需要验证tokenif(!StrUtil。isBlank(profiles)dev。equals(profiles)){returntrue;}2ignoreToken,不需要验证tokenif(ignoreToken((HandlerMethod)handler))returntrue;3获取tokenStringtokengetParamValue(request,AUTH);4获取并验证usernameStringusernamegetParamValue(request,AUTHUSERNAME);ResponseResultresponseResultjwtService。verifyUsername(token,username);if(responseResult。getStatus()!1){log。error(用户名校验失败);thrownewValidationException(300,用户名校验失败!);}这里需要注意:1)如果设置为false时,被请求时,拦截器执行到此处将不会继续操作2)如果设置为true时,请求将会继续执行后面的操作returntrue;}
  前两步骤,只是为大家提供了一种技巧思路而已
  步骤1过滤开发环境,开发环境不需要验证token
  就是在开发环境如果需要快速测试一下接口,可以考虑先跳过token的验证操作
  步骤2ignoreToken,不需要验证token
  则可以考虑对于个别方法可以通过注解的方式,实现忽略token的验证操作
  接下来,我们分别获取头信息或者参数中的token和用户名,然后调用jwtService。verifyUsername(token,username)进行校验,如果校验失败,表示用户名校验失败,也就是说token不正确,那么,抛出异常;
  否则就会通过这一关,进入下一关的拦截了
  2)WebMvcConfig注册拦截器ConfigurationpublicclassWebMvcConfigimplementsWebMvcConfigurer{BeanpublicAuthorisationInterceptorauthorazationIntercepter(){returnnewAuthorisationInterceptor();}OverridepublicvoidaddInterceptors(InterceptorRegistryregistry){添加拦截器registry。addInterceptor(authorazationIntercepter())指定需要拦截的路径。addPathPatterns(user);}}
  注册AuthorisationInterceptor拦截器,并指定需要拦截验证的资源路径:user三测试
  启动项目,并进行如下测试
  1访问登录接口
  http:localhost:8086jwtlogin
  参数为username和password
  如预期,得到了token信息
  2资源接口访问测试
  1)不带token
  若不配置header中的Authorization认证信息,则会返回500的错误(一般可以配置为403禁止访问)
  2)带上token访问
  useradmin接口,参数为username、头信息Authorization配置为上面获取到的token的值
  便实现了接口的成功访问
  3刷新token
  传递token参数,便可以重新得到一个token,然后下次请求重新带上这个token即可,直至它过期总结
  从实战中,我们可以发现,使用JWT,对于大用户量的系统,可以明显降低服务器查询数据库的次数,从而对服务器的性能提升有一定的正向作用
  但是对于用户量很少的一些管理平台,其实没有必要采用JWT,这时,采用Session反而更简单,既不会有太大的数据库查询性能影响,也不需要引入Redis进行token的刷新,带来更大的复杂度
  JWT本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限。所以为了减少盗用的情况,JWT的有效期应该设置得比较短。对于一些比较重要的权限,使用时应该再次对用户进行认证
  此外,在实际项目中,JWT不应该使用HTTP协议明码传输,要使用HTTPS协议传输
  文章演示代码地址:https:github。comhelemileSpringBootNotes参考链接:
  https:www。ruanyifeng。comblog201807jsonwebtokentutorial。html
  嗯,就这样。每天学习一点,时间会见证你的强大
  欢迎大家关注我们的公众号,一起持续性学习吧
  往期精彩回顾
  总结复盘
  架构设计读书笔记与感悟总结
  带领新人团队的沉淀总结
  复盘篇:问题解决经验总结复盘
  网络篇
  网络篇(四):《图解TCPIP》读书笔记
  网络篇(一):《趣谈网络协议》读书笔记(一)
  事务篇章
  事务篇(四):Spring事务并发问题解决
  事务篇(三):分享一个隐性事务失效场景
  事务篇(一):毕业三年,你真的学会事务了吗?
  Docker篇章
  Docker篇(六):DockerCompose如何管理多个容器?
  Docker篇(二):Docker实战,命令解析
  Docker篇(一):为什么要用Docker?
  。。。。。。。。。。
  SpringCloud篇章
  SpringCloud(十三):Feign居然这么强大?
  SpringCloud(十):消息中心篇Kafka经典面试题,你都会吗?
  SpringCloud(九):注册中心选型篇四种注册中心特点超全总结
  SpringCloud(四):公司内部,关于Eureka和zookeeper的一场辩论赛
  。。。。。。。。。。
  SpringBoot篇章
  SpringBoot(十二):陌生又熟悉的OAuth2。0协议,实际上每个人都在用
  SpringBoot(七):你不能不知道的Mybatis缓存机制!
  SpringBoot(六):那些好用的数据库连接池们
  SpringBoot(四):让人又爱又恨的JPA
  SpringBoot(一):特性概览
  。。。。。。。。。。
  翻译
  〔译〕用Mint这门强大的语言来创建一个Web应用
  【译】基于50万个浏览器指纹的新发现
  使用CSS提升页面渲染速度
  WebTransport会在不久的将来取代WebRTC吗?
  。。。。。。。。。
  职业、生活感悟
  你有没有想过,旅行的意义是什么?
  程序员的职业规划
  灵魂拷问:人生最重要的是什么?
  如何高效学习一个新技术?
  如何让自己更坦然地度过一天?
  。。。。。。。。。。

图虎皮兰植株水培法养殖技巧再也不为浇水发愁了虎皮兰,又叫虎尾兰、千岁兰,为多年生草本观叶植物。这种植物适应性强,容易养殖,非常适合用于家庭,办公环境的装饰。虎皮兰不仅可以美化环境,还能净化空气。虎皮兰是一种非常漂亮……图了解君子兰烂根原因对症治病让花长得好君子兰向来有花中君子之称,在我国有很多爱花的朋友以养殖君子兰为品味的象征。但是也有的朋友养君子兰总是烂根,这些朋友非常想知道君子兰烂根的原因到底是什么?君子兰这种花对环境……毕业前要做的20件事不管你多么内向,你一定要在全班同学面前,认认真真地讲一次话,或者唱一支歌,像刚入学时一样,再介绍一回自己,再一次认识彼此,感谢他们出现在你的生命里;拜访一回你最尊敬的老师,真诚……图学习牡丹栽培技术让花中魁首开在自家牡丹花艳丽多姿向来被誉为花中魁首,有很多喜欢养花的朋友都希望可以把牡丹花养在自己家里。但是栽培牡丹花不是一件容易的事情,并不是所有人都能轻易的栽种牡丹。想要自己栽培牡丹花……图盆栽草莓的种植方法简单又实用现代社会中,城市的一般住户都没有地方种些蔬菜瓜果,若想吃上健康又好吃的蔬菜瓜果,可以采用阳台盆栽的方法。下面让小编我为大家介绍一下盆栽草莓的种植方法。草莓株型矮小,属于多……鞠婧祎同款的生日写真,氛围感真的拿捏住了又一组过生日必拍的系列写真终于上线了,小韩新Get到了一组最近很火的鞠婧祎同款生日写真。生日写真这样拍,这质感简直不要太好,这是想一直当公主的18岁,氛围感拿捏住了,咱就……图三角梅嫁接技术详解选择适当的接穗是关键三角梅开花非常繁盛,而且枝干强健。很多花友都养过三角梅,希望通过自己的双手能制作出精美的盆景。花友想要获得一盆三角梅盆景,就需要掌握三角梅的嫁接知识。第一年的三角梅枝叶还……图山地玫瑰夏季休眠养护不轻松控水通风遮阳一样不能少山地玫瑰是多肉植物中的一种。在炎热的夏季,山地玫瑰为躲避强光、酷热等环境,外围叶子老化枯萎。但中心部分的叶片紧紧包裹在一起,株型酷似含苞欲放的玫瑰花。山地玫瑰的生长期是在……图让文竹开花必备三个条件多施肥料促进花苞生长文竹属于绿藤植物,根部及茎为肉质茎,手感比较柔软,而且向上直伸。文竹犹如竹子一样有节,寓意节节高升。文竹是家中常见的盆栽景观,主要以观叶为主。文竹除了外形像矮化的竹子之外……潮流绿意盎然如果要用一种色彩描述即将到来的春天,那一定是生机盎然的绿。后疫情时代,人们需要一种治愈的力量,象征着生机与希望的绿色应运而生,成为2023年春夏流行色。全球权威色彩……图一品红的养殖方法和注意事项种花小科普一品红是原产地在中美洲的一种灌木类植物,颜色鲜艳,说是花,其实更像是长着鲜红色叶子的植物。今天便来说一说一品红的养殖方法及其注意事项与相关的传说。这种鲜红色花卉除了有一品……图盆栽一品红有毒吗室内摆放圣诞红有讲究一品红原产中美洲,广泛栽培于热带和亚热带。中国绝大部分省区市均有栽培,常见于公园、植物园及温室中,供观赏。茎叶可入药,有消肿的功效,可治跌打损伤。一品红是比较常见的观赏植……
一款硬核考古恐龙化石拼装游戏HELLO大家好,这里是小白的每日一游推荐时间。世上的游戏千千万,有许多好玩的游戏由于缺乏宣传,所以不被广大玩家所熟知。在这里小白每天会为大家推荐一款评价很高但是不太出名的游戏……盘点背叛赵本山的六大逆徒,王小利失去工作,张小光惨死高速文吃瓜粉猪君编辑吃瓜粉猪君前言盘点背叛赵本山的六大逆徒,刘能靠赵本山身价数千万,最后却因3000块工资撕破脸皮,还扬言要让赵本山身败名裂。最后一位更是可惜,成……冥想日记1月8日世界上各种形式的纷争,归根结底都是同一个起因读书人茹金原文1月8日世界上各种形式的纷争,归根结底都是同一个起因,即个人的自私。人类生活中的各种活动都扎根于一个共同的地方,这个地方便是我们的心。我们……游甘肃来敦煌一趟甘肃之旅,能游完它的7处世界遗产和7家5A景对旅行者来说,甘肃是一个令人期待但又让人颇为头疼的目的地:它有和华夏文明息息相关的历史遗存、千差万别的瑰丽风景和风情各异的民俗文化,然而仅次于河北的破碎地图让旅行者如何组织行程……福田瑞沃EV新能源工程车上市实力抢跑新能源工程车赛道12月15日,首台福田瑞沃EV新能源工程车在瑞沃工厂正式下线;12月17日,以绿色瑞沃,E路畅盈为主题的福田瑞沃EV新能源工程车云上市发布会如期举行,福田瑞沃再一次向外界展示出……当你骂孩子的时候,他在想什么?我要上头条育儿罗森塔尔效应详细的过程是这样的:美国心理学家罗森塔尔来到一所小学,在18个班级中进行了未来发展趋势测验,整理出一份最有发展前途者的名单交给了相关老师。……资讯2022中国汽车流通行业年会召开,多措并举推动稳定汽车消文:懂车帝原创李德喆〔懂车帝原创行业〕12月14日至16日,2022中国汽车流通行业年会暨高峰论坛通过线上方式举行。本届年会设置了宏观经济、汽车市场、国际交流、新车经销商……三角梅的发现及传播三角梅的发现及传播距今,三角梅的驯化已有250多年的历史。1767年,法国著名航海家、政治家、数学家路易斯安东尼德布干维尔伯爵(LouisAntoinedeBougain……钟丽缇大女儿晒性感!穿吊带背心上围丰满,曾获得选美亚军本文编辑剧透社:彤心晓筑未经授权严禁转载,发现抄袭者将进行全网投诉港圈女神钟丽缇一直是观众比较喜爱的艺人,近年她主攻内地市场,与圈中老公张伦硕婚后也是越来越幸福,三……续航强劲iPhone14Plus来袭,iPhone13跌至大从iPhone14Plus续航能力来说,果粉称iPhone14Plus导航、上网、看视频、听音乐、电话邮件等正常使用下来,能用40小时甚至更长时间,可见大屏iPhone的续航确……不起眼的二手生意里有黄金曾几何时,修旧不如买新,是一大消费趋势。然而,当原始商品积累足够多,并且随着互联网的发展,以及共享观念的深入人心,循环利用成了人们的一种习惯,由此造就了火热的二手交易市场……格局打开了!小米11系列用户安心了,网友应该成为高端标配小米11系列发布初期的口碑还是不错的,全系三星E4材质的2K屏,还支持全局DC调光,可以说是这几年体验最好的屏幕,可惜它们遇到了骁龙888,这个芯片的能耗发热过大,导致主板存在……
友情链接:易事利快生活快传网聚热点七猫云快好知快百科中准网快好找文好找中准网快软网