专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

SpringSecurity与RBAC用户模型

  一、介绍Security
  官方原话SpringSecurityisaframeworkthatprovidesauthentication,authorization,andprotectionagainstcommonattacks即SpringSecurity是一个提供身份验证、授权和防止常见攻击的框架。它是Spring提供的一个安全框架,可以根据使用者需要定制相关验证授权操作,配合SpringBoot可以快速开发一套完善的权限系统。二、快速上手创建一个SpringBoot项目并导入如下依赖或点击下载示例代码dependencygroupIdorg。springframework。bootgroupIdspringbootstartersecurityartifactIddependencydependencygroupIdorg。springframework。bootgroupIdspringbootstarterwebartifactIddependency复制代码运行SpringBoot应用程序
  若是正确启动了,可以看到SpringSecurity生成了一段默认密码。。。。2022091323:56:07。841WARN19924〔main〕。s。s。UserDetailsServiceAutoConfiguration:Usinggeneratedsecuritypassword:70a36ac670c14f72822c71165988c56e。。。复制代码访问http:localhost:8080会跳转到login登录页面,输入账号(user)密码(控制台自动生成的密码)以继续访问。
  SrpingSecurity主要解决的问题是安全访问控制,其实现原理是通过Filter对进入系统的请求进行拦截。当初始化SpringSecurity时,它创建了一个名为springSecurityFilterChain的Servlet过滤器,负责程序中的所以安全控制。三、基本原理DelegatingFilterProxy
  从必要知识里我们知道了Filter的工作原理,在Spring中使用自定义的Filter有个问题那就是Filter必须在Servlet容器启动前就注册好,但是Spring使用ContextLoaderListener来加载SpringBean,于是设计了DelegatingFilterProxy。本质上来说DelegatingFilterProxy就是一个Filter,其间接实现了Filter接口,它嵌入在ServletFilterChain中,但是在doFilter中其实调用的从Spring容器中获取到的代理Filter的实现类delegate。
  FilterChainProxy和SecurityFilterChain
  FilterChainProxy是SpringSecurity提供的一个特殊Filter,DelegatingFilterProxy并不是直接实例化和调用SpringSecurityFilter,而是构建了一个FilterChainProxy,当有请求进来就会去执行doFilter方法调用SecurityFilterChain所包含的各个Filter,同时这些Filter作为Bean被Spring管理,它是SpringSecurity使用的核心。
  此外,SecurityFilterChain提供了更大的灵活性,Servlet容器中,仅根据URL调用过滤器。但是,FilterChainProxy可以利用RequestMatcher接口,根据HttpServletRequest中的任何内容确定调用,比原生的Servlet更灵活,此外,FilterChainProxy可以构建多条SecurityFilterChain,你的应用程序可以为不同的情况提供完全独立的配置,如下图所示。
  过滤器链中主要的几个过滤器及其作用SecurityContextPersistenceFilter:这个Filter是整个拦截过程的入口,会在请求开始时从配置好的SecurityContextRepository中获取SecurityContext,然后把它设置给SecurityContextHolder。在请求完成后将SecurityContextHolder持有的SecurityContext再保存到配置好的SecurityContextRepository,同时清除securityContextHolder所持有的SecurityContext。UsernamePasswordAuthenticationFilter:用于处理来自表单提交的认证。该表单必须提供对应的用户名和密码,其内部还有登录成功或失败后进行处理的AuthenticationSuccessHandler和AuthenticationFailureHandler,这些都可以根据需求做相关改变;。LogoutFilter:用来处理实现用户登出和清除认证信息工作,登出成功后执行LogoutSuccessHandler,这里可以自定义实现一些功能。FilterSecurityInterceptor:是用于保护web资源的,使用AccessDecisionManager对当前用户进行授权访问ExceptionTranslationFilter:能够捕获来自FilterChain所有的异常,并进行处理。但是它只会处理两类异常:AuthenticationException和AccessDeniedException,其它的异常它会继续抛出。异常处理
  首先,ExceptionTranslationFilter调用FilterChain。doFilter(request,response)来调用应用程序的其余部分。如果用户未通过身份验证或者是AuthenticationException,则启动身份验证。SecurityContextHolder被清除HttpServletRequest保存在RequestCache中。当用户成功认证后,RequestCache用于重放原始请求。AuthenticationEntryPoint用于启动身份验证。例如,它可能重定向到登录页面或BASIC认证等。否则,如果是AccessDeniedException,则拒绝访问。调用AccessDeniedHandler来处理拒绝访问。表单登录
  以上示例在未授权的情况下访问会经过以下安全过滤器:Securityfilterchain:〔DisableEncodeUrlFilterWebAsyncManagerIntegrationFilterSecurityContextPersistenceFilterHeaderWriterFilterCsrfFilterLogoutFilterUsernamePasswordAuthenticationFilterDefaultLoginPageGeneratingFilterDefaultLogoutPageGeneratingFilterBasicAuthenticationFilterRequestCacheAwareFilterSecurityContextHolderAwareRequestFilterAnonymousAuthenticationFilterSessionManagementFilterExceptionTranslationFilterFilterSecurityInterceptor〕复制代码
  当没有登录的时候默认是anonymousUser匿名用户,经过一些列过滤器处理后,最后由FilterSecurityInterceptor进行权限校验授权,AccessDecisionManager进行授权投票,匿名用户不允许访问该接口,请求被拒绝重定向到登录页面,接着由DefaultLoginPageGeneratingFilter(自定义表单则不会初始化这个Filter)生成默认登录界面输出到浏览器。登录时经过UsernamePasswordAuthenticationFilter,只要用户请求满足该过滤器要求,则认证成功,接着是授权成功访问通过。
  每个过滤器都有不同的功能,组织在一起形成了强大的安全体系,你可以在过滤链中自定义过滤器,里面的逻辑我就不一一细说了没啥好讲的,官方文档中都有介绍。下面讲讲我自己的一些实现吧。四、我实现思路是什么,我是怎么实现的
  背景:拓展SpringSecurity实现基于Token的API认证授权基础程序
  采用的广为熟知的RBAC模型,基于角色的访问控制(RoleBasedAccessControl)
  拓展点:禁用CSRF(有个过滤器校验会报错)、会话管理设置为无状态STATELESS(因为我们要自定义处理登录注销逻辑)自定义UserDetailsService重写loadUserByUsername方法,从数据库中读取账号信息添加自定义Token认证过滤器自定义登录成功和失败处理器successHandler与failureHandler自定义注销处理器LogoutSuccessHandler自定义异常处理器AuthenticationEntryPoint与AccessDeniedHandler自定义AuthorizationManager
  开发调试可以设置一下日志输出级别,这样能助于我们更快地分析和排查问题:logging:level:org。springframework。web:traceorg。springframework。security:trace复制代码
  另外EnableWebSecurity这个注解debug属性设置为true也能看到更多的日志信息,这对我们很有帮助。SecurityConfiguration核心配置类EnableWebSecurity(debugfalse)publicclassSecurityConfiguration{privatefinalAppUserDetailsServiceuserDetailsService;privatefinalAbstractStringCacheStorecacheStore;privatefinalAuthenticationTokenFilterauthenticationTokenFilter;privatefinalPermissionAuthorizationManagerRequestAuthorizationContextpermissionAuthorizationManager;publicSecurityConfiguration(AppUserDetailsServiceuserDetailsService,AbstractStringCacheStorecacheStore,PermissionAuthorizationManagerRequestAuthorizationContextpermissionAuthorizationManager){this。userDetailsServiceuserDetailsService;this。cacheStorecacheStore;this。permissionAuthorizationManagerpermissionAuthorizationManager;this。authenticationTokenFilternewAuthenticationTokenFilter(cacheStore,userDetailsService);}BeanpublicWebSecurityCustomizerwebSecurityCustomizer(){return(web)web。ignoring()SpringSecurityshouldcompletelyignoreURLsstartingwithresources。antMatchers(resources);}BeanpublicSecurityFilterChainsecurityFilterChain(HttpSecurityhttp)throwsException{http。authorizeHttpRequests()。antMatchers(HttpMethod。OPTIONS,)。permitAll()。antMatchers()。permitAll()。antMatchers(userinfo)。authenticated()需要认证。anyRequest()。access(permissionAuthorizationManager)动态权限认证。and()。userDetailsService(userDetailsService)。formLogin()。permitAll()。successHandler(newCustomizeAuthenticationSuccessHandler(cacheStore))。failureHandler(newAuthenticationEntryPointFailureHandler(newCustomizeAuthenticationEntryPoint()))。and()。logout()。logoutSuccessHandler(newCustomizeLogoutSuccessHandler(cacheStore))。and()。exceptionHandling()。authenticationEntryPoint(newCustomizeAuthenticationEntryPoint())。accessDeniedHandler(newCustomizeAccessDeniedHandler())。and()。csrf()。disable()。sessionManagement()。sessionCreationPolicy(SessionCreationPolicy。STATELESS)。and()。addFilterBefore(authenticationTokenFilter,UsernamePasswordAuthenticationFilter。class)。addFilterBefore(authenticationTokenFilter,LogoutFilter。class);returnhttp。build();}复制代码
  释义:AuthenticationTokenFilterToken认证过滤器(除了自定义开放的接口外都会被调用)PermissionAuthorizationManager动态权限授权管理器(基于角色与资源权限表)CustomizeAuthenticationSuccessHandler登录处理器(登录成功后被调用用于生成Token)
  CustomizeLogoutSuccessHandler注销处理器(注销成功后被调用用于清除Toekn)CustomizeAuthenticationEntryPoint认证失败处理器(认证出现异常被调用)CustomizeAccessDeniedHandler授权失败处理器(授权出现异常被调用,如权限不足以访问某接口)AbstractStringCacheStore缓存类(用于缓存Token)CustomizeAuthenticationSuccessHandler登录处理器Slf4jpublicclassCustomizeAuthenticationSuccessHandlerimplementsAuthenticationSuccessHandler{privatefinalAbstractStringCacheStorecacheStore;Expiredseconds。privatestaticfinalintACCESSTOKENEXPIREDSECONDS243600;privatestaticfinalintREFRESHTOKENEXPIREDDAYS30;publicCustomizeAuthenticationSuccessHandler(AbstractStringCacheStorecacheStore){this。cacheStorecacheStore;}OverridepublicvoidonAuthenticationSuccess(HttpServletRequestrequest,HttpServletResponseresponse,Authenticationauthentication)throwsIOException{AppUserDetailsuserDetails(AppUserDetails)SecurityContextHolder。getContext()。getAuthentication()。getPrincipal();GeneratenewtokenAuthTokentokennewAuthToken();token。setAccessToken(BottleUtils。randomUUIDWithoutDash());token。setExpiredIn(ACCESSTOKENEXPIREDSECONDS);token。setRefreshToken(BottleUtils。randomUUIDWithoutDash());Cachethosetokens,justforclearingcacheStore。putAny(SecurityUtils。buildAccessTokenKey(userDetails),token。getAccessToken(),ACCESSTOKENEXPIREDSECONDS,TimeUnit。SECONDS);cacheStore。putAny(SecurityUtils。buildRefreshTokenKey(userDetails),token。getRefreshToken(),REFRESHTOKENEXPIREDDAYS,TimeUnit。DAYS);CachethosetokenswithuseridcacheStore。putAny(SecurityUtils。buildTokenAccessKey(token。getAccessToken()),userDetails。getUserId(),ACCESSTOKENEXPIREDSECONDS,TimeUnit。SECONDS);cacheStore。putAny(SecurityUtils。buildTokenRefreshKey(token。getRefreshToken()),userDetails。getUserId(),REFRESHTOKENEXPIREDDAYS,TimeUnit。DAYS);response。setCharacterEncoding(utf8);response。setStatus(HttpServletResponse。SCOK);response。setContentType(MediaType。APPLICATIONJSONVALUE);response。getWriter()。write(JsonUtils。objectToJson(BaseResponse。ok(登录成功!,token)));}复制代码LogoutSuccessHandler注销处理器Slf4jpublicclassCustomizeLogoutSuccessHandlerimplementsLogoutSuccessHandler{privatefinalAbstractStringCacheStorecacheStore;publicCustomizeLogoutSuccessHandler(AbstractStringCacheStorecacheStore){this。cacheStorecacheStore;}OverridepublicvoidonLogoutSuccess(HttpServletRequestrequest,HttpServletResponseresponse,Authenticationauthentication)throwsIOException,ServletException{if(Objects。isNull(authentication)){return;}AppUserDetailsuserDetails(AppUserDetails)authentication。getPrincipal();ClearaccesstokencacheStore。getAny(SecurityUtils。buildAccessTokenKey(userDetails),String。class)。ifPresent(accessToken{DeletetokencacheStore。delete(SecurityUtils。buildTokenAccessKey(accessToken));cacheStore。delete(SecurityUtils。buildAccessTokenKey(userDetails));});ClearrefreshtokencacheStore。getAny(SecurityUtils。buildRefreshTokenKey(userDetails),String。class)。ifPresent(refreshToken{cacheStore。delete(SecurityUtils。buildTokenRefreshKey(refreshToken));cacheStore。delete(SecurityUtils。buildRefreshTokenKey(userDetails));});response。setCharacterEncoding(utf8);response。setStatus(HttpServletResponse。SCOK);response。setContentType(MediaType。APPLICATIONJSONVALUE);response。getWriter()。write(JsonUtils。objectToJson(BaseResponse。ok(登出成功!,null)));log。info(Youhavebeenloggedout,lookingforwardtoyournextvisit!);}}复制代码AuthenticationTokenFilterToken认证过滤器Slf4jpublicclassAuthenticationTokenFilterextendsOncePerRequestFilter{privatestaticfinalStringAUTHENTICATIONSCHEMEBEARERBearer;privatefinalAbstractStringCacheStorecacheStore;privatefinalAppUserDetailsServiceappUserDetailsService;publicAuthenticationTokenFilter(AbstractStringCacheStorecacheStore,AppUserDetailsServiceappUserDetailsService){this。cacheStorecacheStore;this。appUserDetailsServiceappUserDetailsService;}OverrideprotectedvoiddoFilterInternal(HttpServletRequestrequest,HttpServletResponseresponse,FilterChainfilterChain)throwsServletException,IOException{GettokenfromrequestheaderStringaccessTokenrequest。getHeader(HttpHeaders。AUTHORIZATION);if(!StringUtils。hasText(accessToken)){DofilterfilterChain。doFilter(request,response);return;}if(!StringUtils。startsWithIgnoreCase(accessToken,AUTHENTICATIONSCHEMEBEARER)){thrownewBadCredentialsException(Token必须以bearer开头);}if(accessToken。equalsIgnoreCase(AUTHENTICATIONSCHEMEBEARER)){thrownewBadCredentialsException(Token不能为空);}GettokenbodyaccessTokenaccessToken。substring(AUTHENTICATIONSCHEMEBEARER。length()1);OptionalLongoptionalUserIdcacheStore。getAny(SecurityUtils。buildTokenAccessKey(accessToken),Long。class);if(!optionalUserId。isPresent()){log。debug(Token已过期或不存在〔{}〕,accessToken);filterChain。doFilter(request,response);return;}UserDetailsuserDetailsappUserDetailsService。loadUserById(optionalUserId。get());UsernamePasswordAuthenticationTokenauthenticationnewUsernamePasswordAuthenticationToken(userDetails,null,userDetails。getAuthorities());SecurityContextHolder。getContext()。setAuthentication(authentication);DofilterfilterChain。doFilter(request,response);}}复制代码CustomizeAuthenticationEntryPoint认证异常处理器Slf4jpublicclassCustomizeAuthenticationEntryPointimplementsAuthenticationEntryPoint{Overridepublicvoidcommence(HttpServletRequestrequest,HttpServletResponseresponse,AuthenticationExceptionauthException)throwsIOException,ServletException{BaseResponseObjecterrorDetailhandleBaseException(authException);errorDetail。setData(Collections。singletonMap(uri,request。getRequestURI()));response。setCharacterEncoding(utf8);response。setStatus(HttpStatus。UNAUTHORIZED。value());response。setContentType(MediaType。APPLICATIONJSONVALUE);response。getWriter()。write(JsonUtils。objectToJson(errorDetail));}privateBaseResponseObjecthandleBaseException(Throwablet){Assert。notNull(t,Throwablemustnotbenull);BaseResponseObjecterrorDetailnewBaseResponse();errorDetail。setStatus(HttpStatus。UNAUTHORIZED。value());if(log。isDebugEnabled()){errorDetail。setDevMessage(ExceptionUtils。getStackTrace(t));}if(tinstanceofAccountExpiredException){errorDetail。setMessage(账户过期);}elseif(tinstanceofDisabledException){errorDetail。setMessage(账号被禁用);}elseif(tinstanceofLockedException){errorDetail。setMessage(账户被锁定);}elseif(tinstanceofAuthenticationCredentialsNotFoundException){errorDetail。setMessage(用户身份凭证未找到);}elseif(tinstanceofAuthenticationServiceException){errorDetail。setMessage(用户身份认证服务异常);}elseif(tinstanceofBadCredentialsException){errorDetail。setMessage(t。getMessage());}else{errorDetail。setMessage(访问未授权);}returnerrorDetail;}}复制代码CustomizeAccessDeniedHandler授权异常publicclassCustomizeAccessDeniedHandlerimplementsAccessDeniedHandler{Overridepublicvoidhandle(HttpServletRequestrequest,HttpServletResponseresponse,AccessDeniedExceptionaccessDeniedException)throwsIOException,ServletException{BaseResponseObjecterrorDetailnewBaseResponse();errorDetail。setStatus(HttpStatus。FORBIDDEN。value());errorDetail。setMessage(禁止访问);response。setCharacterEncoding(utf8);response。setStatus(HttpServletResponse。SCFORBIDDEN);response。setContentType(MediaType。APPLICATIONJSONVALUE);response。getWriter()。write(JsonUtils。objectToJson(errorDetail));}}复制代码PermissionAuthorizationManager动态权限授权管理Slf4jComponentpublicclassPermissionAuthorizationManagerTimplementsAuthorizationManagerT{privatefinalAuthenticationTrustResolvertrustResolvernewAuthenticationTrustResolverImpl();privatefinalPermissionServicepermissionService;publicPermissionAuthorizationManager(PermissionServicepermissionService){this。permissionServicepermissionService;}OverridepublicAuthorizationDecisioncheck(Supplierauthentication,Tobject){DeterminesifthecurrentuserisauthorizedbyevaluatingifthebooleangrantedisGranted(authentication。get());if(!granted){returnnewAuthorizationDecision(false);}Collectionlt;?extendsGrantedAuthorityauthoritiesauthentication。get()。getAuthorities();SetStringauthorityauthorities。stream()。map(GrantedAuthority::getAuthority)。collect(Collectors。toSet());log。debug(username〔{}〕havroles:〔{}〕,authentication。get()。getName(),authority);RequestAuthorizationContextrequestAuthorizationContext(RequestAuthorizationContext)object;StringservletPathrequestAuthorizationContext。getRequest()。getRequestURI();log。debug(accessurl:{},servletPath);AppUserDetailsuserDetails(AppUserDetails)authentication。get()。getPrincipal();ListLongroleIdsuserDetails。getRoles()。stream()。map(Role::getId)。collect(Collectors。toList());ListPermissionpermissionspermissionService。listByRoleIds(roleIds);booleanagreeFlagpermissions。stream()。anyMatch(permissionisRouter(permission)permission。getUrl()。equals(servletPath));log。debug(checkresult:{},agreeFlag);returnnewAuthorizationDecision(agreeFlag);}privatebooleanisGranted(Authenticationauthentication){returnauthentication!nullisNotAnonymous(authentication)authentication。isAuthenticated();}privatebooleanisNotAnonymous(Authenticationauthentication){return!this。trustResolver。isAnonymous(authentication);}privatebooleanisRouter(Permissionpermission){return1。equals(permission。getType());}}复制代码五、示例
  登录成功POSTlogin?usernameuserpassword123456Host:localhost:8080response:{status:200,message:登录成功!,devMessage:null,data:{accesstoken:8430064e7d9b497c8b786a33b0524bc5,expiredin:86400,refreshtoken:8d2c6fb3489b47389a65cbf79f732f9a}}复制代码登录失败POSTlogin?usernameuserpassword123Host:localhost:8080response:{status:401,message:用户名或密码错误,devMessage:org。springframework。security。authentication。BadCredentialsException:用户名或密码错误。。。,data:{uri:login}}复制代码登录注销POSTlogoutHost:localhost:8080Authorization:Bearerb6422e3462224126a67f876b5f1b3a1eresponse:{status:200,message:登出成功!,devMessage:null,data:null}复制代码未登录或Token过期POSTlogoutHost:localhost:8080Authorization:Bearerb6422e3462224126a67f876b5f1b3a1eresponse:{status:401,message:访问未授权,devMessage:org。springframework。security。authentication。InsufficientAuthenticationException:Fullauthenticationisrequiredtoaccessthisresource。。。,data:{uri:userinfo}}复制代码权限不足GETadminHost:localhost:8080Authorization:Bearerf7a542c4899a4e6ea5039002a8f19110response:{status:403,message:禁止访问,devMessage:null,data:null}复制代码六、小结
  好了,就分享到这里了,希望对大家有所帮助,另外如有理解错误的地方请多多指教。SpringSecurity还有很多值得探索的功能,继续学习吧

江西南昌昨日新增21,这些地方划定为中高风险地区央广网南昌7月10日消息(记者胡斐)7月10日,据江西省卫生健康委员会发布通报2022年7月9日024时,江西省新增本土确诊病例2例,均在南昌市,为省外输入关联病例。从2020年1东亚杯日本VS中国本队此次出征东亚杯的球员均从J联赛中征召,除了后防线的谷口彰悟等几位边缘国脚外,大部分球员都是第一次入选国家队,可以说是日本队的二队甚至三队。不过球队的实力仍是不可忽视,首场比赛日爆冷逼平日本队!国足将士们拒绝连败,昂首离开赛场北京时间7月24日,东亚杯进行了第二轮的比赛,与第一轮惨败韩国不同,国足小将们众志成城,依靠韩佳奇和后防线的出色发挥,逼平了实力强大的日本队。这也是本届东亚杯中国男足拿到的第一分,为什么不能原谅日本人安倍遇刺身亡,曾莹身为中国某知名媒体驻日记者,不当发言引起中国人众怒。然后又是南京九华山公园玄奘寺事件发酵,各地今年的夏日祭文化活动纷纷被取消。然后又热炒中国内地的日本人学校,大意刚刚!南京通报吴啊萍身份查明,已刑拘点蓝字关注,不迷路关于南京玄奘寺供奉侵华日军战犯牌位事件调查处理情况的通报玄奘寺供奉侵华日军战犯牌位事件发生后,南京市委市政府迅速成立调查组,组织进行全面深入调查处理。现将有关情况赛前真不敢想22岁戴伟浚今晚3次戏耍日本国脚太争气中国足球今晚迎来了惊喜的时刻,中国队在首场0比3不敌韩国队后,迅速调整状态和打法,在日本队的主场打出了自己的气势,最终零封日本队,拿下了一场宝贵的平局。赛前几乎很少有人预想到中国队85年后的南京,今天我们绝不能失守文六月六一名身着破烂军装的士兵背着一把破枪走出烈士陵园大街上身穿各式各样华丽和服的年轻人熙熙攘攘路过玄奘寺看到里面供奉的排位恐惧而惊恐喃喃道没守住么?南京自古以来就是兵家必争之地,东亚杯中国00逼平日本,中谷进之介暴力传球把队友砸晕北京时间7月24日1820,东亚杯男足比赛继续进行,由中国队对阵日本队,中国队在首场比赛中全面被动挨打,03完败于韩国,而日本则在首场比赛中60大胜中国香港,日本虽然本次出征东亚杯日本樱岛火山又喷发了!1年3次,群众紧急撤离,富士山还稳定吗日本火山又喷发了!小火山一年之内多次喷发,富士山还稳定吗?当地时间7月24日晚20时05分(北京时间今晚19时05分),位于九州鹿儿岛县的樱岛火山突然喷发,释放出了浓浓的烟雾,直冲幸福到万家韩主任说了一句台词,暗示他跟何幸运有私密关系?幸福到万家大结局了。这个大结局,虽然看起来圆满,但实际上很多地方,也大可不必如此刻意追求圆满。刻意追求的圆满,简直让人一言难尽。就比如说,何幸运从义道辞职,还非得要去关涛的律所。何幸福到万家顿悟怂包王庆来,是如何靠离婚打败关涛的?王庆来回到万家庄后,每天就是心不在焉地锄土。这天,何幸福突然回来了。王庆来心头一紧,以为何幸福是来跟自己谈离婚的,便说你回去吧,我们俩不一样。你注定就是这天上飘的云彩,我就是这土泥
旅途和返乡后及春节期间聚餐儿童在防护方面有哪些注意事项?专家建议今天(1月16日)15时,国务院联防联控机制召开新闻发布会,北京儿童医院急诊科主任王荃表示,春节将至,旅途和返乡后及春节期间聚餐儿童在防护方面应注意以下方面首先建议尽量不要给孩子安春秋时期,晋宋关系有什么特点?探究晋宋邦交的特别之处如果您喜欢这篇作品,欢迎点击右上方关注。感谢您的鼓励与支持,希望能给您带来舒适的阅读体验。春秋时期,随着周天子权势的衰微,大国争霸成为时代主题,小诸侯国则不断变换国策来应对国际局势五角大楼发布最新UFO报告!真有外星文明?轮到天眼联系它们了据科学家估计,只要是大约五分之一的太阳大小的恒星,在宜居带中都会有一颗地球大小的行星。因此据估计在银河系中,适合居住的地球大小的行星,至少有110亿颗。而当咱们抬起头望向夜空中那难太空三峡即将到来?发电效率是地面的10倍,可供美国使用半年什么是太空三峡?这是我国在太空建造的空间太阳能电站,目前已经启动,发电效率是地面的10倍,能源困局或将彻底解决。我国又一项新技术建造成功,在空间站搭建太阳能发电系统,每平方米的太阳大展宏兔逐梦星辰!中国探月航天太空兔命名兔星星我们的太空1月14日,在北京颐堤港的中国探月太空兔展陈活动现场,中国探月航天IP形象太空兔正式对外公布了名称。在过去几年时间里,大家一直亲切地称呼其为太空兔,在农历兔年到来之际,中为啥月球土壤可以带回地球,火星土壤却不行?难不成火星土壤有毒文猫行图网络为啥月球土壤可以带回地球,火星土壤却不行?难不成火星土壤有毒?宇宙浩瀚无穷,其中蕴含着无数人类所想要去追求的东西。只是苦于科技的限制,并不能完成全面的探索。火星就是一个大展宏兔逐梦星辰中国探月航天太空兔名称正式对外宣布!来源我们的太空1月14日,也是中国农历兔年的小年。在北京颐堤港的中国探月太空兔展陈活动现场,中国探月航天IP形象太空兔正式对外公布了名称。中国探月工程也叫嫦娥工程,自2007年10让AppleWatch自叹不如的didoE55SPro智能手表体验有感在科技高速发展的今天,我们的生活迎来了更多贴心设计的智能产品,作为生活中的必须品,智能穿戴如今也已悄然进入到我们的日常生活中来,在经过智能手环的洗礼后,智能手表的出现更是包含了智能国产内存比肩国际一线,阿斯加特DDR5,高调迈进7800MHz俱乐部国产内存比肩国际一线,阿斯加特DDR5,高调迈进7800MHz俱乐部如果在五年前(2018年)DIY过电脑的朋友们,一定对当年的内存硬盘价格心有余悸,要知道当时普普通通的DDR4内屏保限定新年将至,福兔迎春癸卯兔年即将到来,大家的手机屏保都准备好了吗?卯兔,是十二生肖地支的第四位传说兔子是天上的玉衡星变化而成生性灵活机警,温柔欢乐象征敏捷机智长寿吉祥温顺可爱幸福在全世界都收获了不少粉小巧精致的代表,内部做工如何?图拉斯50W小冰块快充拆解前言图拉斯推出了一款全新的小冰块充电器,这款充电器升级到双PD接口,支持最大50W输出功率,也支持双口同时快充,能够同时满足两部iPhone快充,还能为MacBook笔记本快充,更
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网