《SpringBoot极简教程》第16章SpringBoot安全集成SpringSecurity

丰富的线上&线下活动,深入探索云世界

做任务,得社区积分和周边

最真实的开发者用云体验

让每位学生受益于普惠算力

让创作激发创新

资深技术专家手把手带教

遇见技术追梦人

技术交流,直击现场

海量开发者使用工具、手册,免费下载

极速、全面、稳定、安全的开源镜像

开发手册、白皮书、案例集等实战精华

为开发者定制的Chrome浏览器插件

本章节使用SpringBoot集成SpringSecurity开发一个LightSword接口自动化测试平台,由浅入深的讲解SpringBoot集成SpringSecurity开发技术知识。

本章节采用SpringBoot集成的主要的后端技术框架:

编程语言:java,scalaORM框架:jpaView模板引擎:velocity安全框架:springsecurity数据库:mysql

项目pom.xml添加spring-boot-starter-security依赖

org.springframework.bootspring-boot-starter-security重启你的应用。再次打开页面,你讲看到一个alert表单对话框:

这个用户名,密码是什么呢?

让我们来从SpringBoot源码寻找一下。

你搜一下输出日志,会看到下面一段输出:

2017-04-2721:39:20.321INFO94124---[ost-startStop-1]b.a.s.AuthenticationManagerConfiguration:Usingdefaultsecuritypassword:6c920ced-f1c1-4604-96f7-f0ce4e46f5d4这段日志是AuthenticationManagerConfiguration类里面的如下方法输出的:

@Overridepublicvoidconfigure(AuthenticationManagerBuilderauth)throwsException{if(auth.isConfigured()){return;}Useruser=this.securityProperties.getUser();if(user.isDefaultPassword()){logger.info(String.format("%n%nUsingdefaultsecuritypassword:%s%n",user.getPassword()));}Setroles=newLinkedHashSet<>(user.getRole());withUser(user.getName()).password(user.getPassword()).roles(roles.toArray(newString[roles.size()]));setField(auth,"defaultUserDetailsService",getUserDetailsService());super.configure(auth);}我们可以看出,是SecurityProperties这个Bean管理了用户名和密码。在SecurityProperties里面的一个内部静态类User类里面,管理了默认的认证的用户名与密码。代码如下

publicstaticclassUser{/***Defaultusername.*/privateStringname="user";/***Passwordforthedefaultusername.*/privateStringpassword=UUID.randomUUID().toString();/***Grantedrolesforthedefaultusername.*/privateListrole=newArrayList<>(Collections.singletonList("USER"));privatebooleandefaultPassword=true;publicStringgetName(){returnthis.name;}publicvoidsetName(Stringname){this.name=name;}publicStringgetPassword(){returnthis.password;}publicvoidsetPassword(Stringpassword){if(password.startsWith("${")&&password.endsWith("}")||!StringUtils.hasLength(password)){return;}this.defaultPassword=false;this.password=password;}publicListgetRole(){returnthis.role;}publicvoidsetRole(Listrole){this.role=newArrayList<>(role);}publicbooleanisDefaultPassword(){returnthis.defaultPassword;}}综上所述,security默认的用户名是user,默认密码是应用启动的时候,通过UUID算法随机生成的。默认的role是"USER"。

当然,如果我们想简单改一下这个用户名密码,可以在application.properties配置你的用户名密码,例如

#securitysecurity.user.name=adminsecurity.user.password=admin当然这只是一个初级的配置,更复杂的配置,可以分不用角色,在控制范围上,能够拦截到方法级别的权限控制。且看下文分解。

在上面章节,我们什么都没做,就添加了spring-boot-starter-security依赖,整个应用就有了默认的认证安全机制。下面,我们来定制用户名密码。

写一个extendsWebSecurityConfigurerAdapter的配置类:

1.通过@EnableWebSecurity注解开启SpringSecurity的功能。使用@EnableGlobalMethodSecurity(prePostEnabled=true)这个注解,可以开启security的注解,我们可以在需要控制权限的方法上面使用@PreAuthorize,@PreFilter这些注解。

2.extends继承WebSecurityConfigurerAdapter类,并重写它的方法来设置一些web安全的细节。我们结合@EnableWebSecurity注解和继承WebSecurityConfigurerAdapter,来给我们的系统加上基于web的安全机制。

5.configureGlobal(AuthenticationManagerBuilderauth)方法,在内存中创建了一个用户,该用户的名称为root,密码为root,用户角色为USER。

输入用户名,密码,点击Login

成功跳转我们之前要访问的页面:

不过,我们发现,SpringBoot应用的启动日志还是打印了如下一段:

2017-04-2722:51:44.059INFO95039---[ost-startStop-1]b.a.s.AuthenticationManagerConfiguration:Usingdefaultsecuritypassword:5fadfb54-2096-4a0b-ad46-2dad3220c825但实际上,已经使用了我们定制的用户名密码了。

如果我们要配置多个用户,多个角色,可参考使用如下示例的代码:

@Overrideprotectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{auth.inMemoryAuthentication().withUser("root").password("root").roles("USER").and().withUser("admin").password("admin").roles("ADMIN","USER").and().withUser("user").password("user").roles("USER");}角色权限控制当我们的系统功能模块当需求发展到一定程度时,会不同的用户,不同角色使用我们的系统。这样就要求我们的系统可以做到,能够对不同的系统功能模块,开放给对应的拥有其访问权限的用户使用。

SpringSecurity提供了SpringEL表达式,允许我们在定义URL路径访问(@RequestMapping)的方法上面添加注解,来控制访问权限。

在标注访问权限时,根据对应的表达式返回结果,控制访问权限:

true,表示有权限fasle,表示无权限

SpringSecurity可用表达式对象的基类是SecurityExpressionRoot。

同时,我们可以看出hasRole跟hasAnyRole是一样的。hasAnyRole是调用的hasAnyAuthorityName(defaultRolePrefix,roles)。所以,我们在学习一个框架或者一门技术的时候,最准确的就是源码。通过源码,我们可以更好更深入的理解技术的本质。

SecurityExpressionRoot为我们提供的使用SpringEL表达式总结如下[1]:

比如说,在lightsword系统中,我们设置测试报告页面,只针对ADMIN权限开放,代码如下:

在方法上添加@PreAuthorize这个注解,value="hasRole('ADMIN')")是Spring-ELexpression,当表达式值为true,标识这个方法可以被调用。如果表达式值是false,标识此方法无权限访问。

{"accountNonExpired":true,"accountNonLocked":true,"authorities":[{"authority":"ROLE_ADMIN"},{"authority":"ROLE_USER"}],"credentialsNonExpired":true,"enabled":true,"username":"root"}这个Authentication对象信息其实就是User实体的信息(当然,密码没放进来)。

publicclassUserimplementsUserDetails,CredentialsContainer{privateStringpassword;privatefinalStringusername;privatefinalSetauthorities;privatefinalbooleanaccountNonExpired;privatefinalbooleanaccountNonLocked;privatefinalbooleancredentialsNonExpired;privatefinalbooleanenabled;....}我们可以使用下面的代码(Java)获得当前身份验证的用户的名称:

Objectprincipal=SecurityContextHolder.getContext().getAuthentication().getPrincipal();if(principalinstanceofUserDetails){Stringusername=((UserDetails)principal).getUsername();}else{Stringusername=principal.toString();}通过调用getContext()返回的对象是SecurityContext的实例对象,该实例对象保存在ThreadLocal线程本地存储中。使用SpringSecurity框架,通常的认证机制都是返回UserDetails实例。

SpringMVC的Web开发使用Controller基本上可以完成大部分需求,但是我们还可能会用到Servlet、Filter、Listener、Interceptor等等。

在SpringBoot中添加自己的Servlet有两种方法,代码注册Servlet和注解自动注册(Filter和Listener也是如此)。

(1)代码注册通过ServletRegistrationBean、FilterRegistrationBean和ServletListenerRegistrationBean获得控制。也可以通过实现ServletContextInitializer接口直接注册。使用代码注册Servlet(就不需要@ServletComponentScan注解)

(2)在SpringBootApplication上使用@ServletComponentScan注解后,Servlet、Filter、Listener可以直接通过@WebServlet、@WebFilter、@WebListener注解自动注册。

代码如下

valprincipal=SecurityContextHolder.getContext.getAuthentication.getPrincipalif(principal.isInstanceOf[UserDetails]){username=principal.asInstanceOf[UserDetails].getUsername}else{username=principal.toString}拿到认证信息,然后把用户名放到session中:

2.给启动类加上注解@ServletComponentScan

packagecom.springboot.in.actionimportorg.springframework.boot.autoconfigure.SpringBootApplicationimportorg.springframework.boot.web.servlet.ServletComponentScan@SpringBootApplication@ServletComponentScan(basePackages=Array("com.springboot.in.action"))classAppConfig这个注解将开启扫描Servlet组件功能。那些被标注了@WebFilter,@WebServlet,@WebListener的Bean将会注册到容器中。需要注意的一点是,这个扫描动作只在当我们使用的是嵌入式Servlet容器的时候才起作用。完成Bean注册工作的类是org.springframework.boot.web.servlet.ServletComponentScanRegistrar,它实现了Spring的ImportBeanDefinitionRegistrar接口。

3.前端显示用户信息

Velocity内置了一些对象,例如:$request、$response、$session,这些对象可以在vm模版里可以直接调用。所以我们只需要使用$session取出,当初我们放进session的对应key的属性值即可。

我们在LoginFilter里面是这样放进去的:

session.setAttribute("username",username)在前端页面直接这样取出username

部署应用运行,我们看一下运行日志:

o.s.b.c.embedded.FilterRegistrationBean:Mappingfilter:'com.springboot.in.action.filter.LoginFilter'to:[/*]这表明我们定义的LoginFilter类成功注册,路径映射到/*。同时,我们在

o.s.s.web.DefaultSecurityFilterChain:Creatingfilterchain:这行日志后面,看到SpringBoot默认创建了的那些FilterChain。这些Filter如下:

我们刚才是使用@WebFilter注解一个javax.servlet.Filter的实现类来实现一个LoginFilter。

基于JavaConfig,SpringBoot同样可以使用如下的方式实现Servlet、Filter、Listener的Bean的配置:

本节我们将在我们之前的系统上,实现一个用数据库存储用户和角色,实现系统的安全认证。在权限角色上,我们简单设计两个用户角色:USER,ADMIN。

我们设计页面的权限如下:

对应的领域实体模型类如下:

用户表

packagecom.springboot.in.action.entityimportjavax.persistence.{Entity,GeneratedValue,GenerationType,Id}importscala.beans.BeanProperty/***Createdbyjackon2017/4/29.*/@EntityclassUser{@Id@GeneratedValue(strategy=GenerationType.AUTO)@BeanPropertyvarid:Integer=_@BeanPropertyvaruserName:String=_@BeanPropertyvarpassword:String=_}角色表

packagecom.springboot.in.action.entityimportjavax.persistence.{Entity,GeneratedValue,GenerationType,Id}importscala.beans.BeanProperty/***Createdbyjackon2017/4/29.*/@EntityclassRole{@Id@GeneratedValue(strategy=GenerationType.AUTO)@BeanPropertyvarid:Integer=_@BeanPropertyvarrole:String=_}用户角色关联表

packagecom.springboot.in.action.entityimportjavax.persistence.{Entity,GeneratedValue,GenerationType,Id}importscala.beans.BeanProperty/***Createdbyjackon2017/4/29.*/@EntityclassUserRole{@Id@GeneratedValue(strategy=GenerationType.AUTO)@BeanPropertyvarid:Integer=_@BeanPropertyvaruserId:Integer=_@BeanPropertyvarroleId:Integer=_}为了方便测试,我们后面会写一个用户测试数据的自动生成的Bean,用来做测试数据的自动初始化工作。

同样的,我们要写一个继承WebSecurityConfigurerAdapter的配置类:

(1)覆盖写userDetailsService方法,具体的LightSwordUserDetailService实现类,我们下面紧接着会讲。

(2)默认不拦截静态资源的urlpattern。我们也可以用下面的WebSecurity这个方式跳过静态资源的认证

packagecom.springboot.in.action.securityimportorg.springframework.context.annotation.Configurationimportorg.springframework.web.servlet.config.annotation.{ViewControllerRegistry,WebMvcConfigurerAdapter}/***Createdbyjackon2017/4/30.*/@ConfigurationclassWebMvcConfigextendsWebMvcConfigurerAdapter{/***统一注册纯RequestMapping跳转View的Controller*/overridedefaddViewControllers(registry:ViewControllerRegistry){registry.addViewController("/login").setViewName("/login")}}这里我们直接采用ViewControllerRegistry来注册一个纯路径映射的Controller方法。

login.html

我们同样使用@EnableGlobalMethodSecurity(prePostEnabled=true)这个注解,开启security的注解,这样我们可以在需要控制权限的方法上面使用@PreAuthorize,@PreFilter这些注解。

代码如下:

我们首先添加一个GlobalExceptionHandlerAdvice,使用@ControllerAdvice注解:

packagecom.springboot.in.action.adviceimportorg.springframework.web.bind.annotation.{ControllerAdvice,ExceptionHandler}importorg.springframework.web.context.request.WebRequestimportorg.springframework.web.servlet.ModelAndView/***Createdbyjackon2017/4/27.*/@ControllerAdviceclassGlobalExceptionHandlerAdvice{@ExceptionHandler(value=Array(classOf[Exception]))//表示捕捉到所有的异常,你也可以捕捉一个你自定义的异常defexception(exception:Exception,request:WebRequest):ModelAndView={valmodelAndView=newModelAndView("/error")//error页面modelAndView.addObject("errorMessage",exception.getMessage)modelAndView.addObject("stackTrace",exception.getStackTrace)modelAndView}}其中,@ExceptionHandler(value=Array(classOf[Exception])),表示捕捉到所有的异常,这里你也可以捕捉一个你自定义的异常。比如说,针对安全认证的Exception,我们可以单独定义处理。此处不再赘述。感兴趣的读者,可自行尝试。

错误统一处理页面error.html

#parse("/common/header.html")

系统异常统一处理页面

异常消息:$errorMessage

异常堆栈信息:

#foreach($ein$stackTrace)$e#end#parse("/common/footer.html")6.测试运行为了方便测试用户权限功能,我们给数据库初始化一些测试数据进去:

我们自定义LightSwordUserDetailService实现了UserDetailsService接口,从我们自己定义的数据库表里面取得用户信息来认证鉴权。

SpringSecurity提供的功能还远不止于此,更多SpringSecurity的使用可参见【参考资料】部分。

THE END
1.Origin图保存指南:轻松保存你的文档(origin图怎么保存文档本文详细介绍了如何在Origin软件中保存文档,包括保存文档的方法、保存选项以及如何导出图表为图片格式。掌握这些技巧可以帮助用户更好地管理和分享自己的工作成果。https://origin.zaixianjisuan.com/jiqiao/origintu-bao-cun-zhi-nan-qing-song-bao-cun-ni-de-wen-dang.html
2.如何轻松将文档保存至桌面并掌握相关操作技巧如何轻松将文档保存至桌面并掌握相关操作技巧 保存文件到桌面是电脑操作中的基础步骤,无论是个人使用还是工作需求,它都显得尤为重要。通过将文档、图片、表格等重要文件保存到桌面,我们能够更加便捷地访问和管理这些文件。本文将详细介绍如何在Windows和MacOS操作系统中将文档保存至桌面,并提供一些实用的操作技巧,助您https://baijiahao.baidu.com/s?id=1818911666226206592&wfr=spider&for=pc
3.标准手册下载ID:1182482202标准手册 琚宾设计手法解析 琚宾设计 水平线设计 设计分析 设计手法解析 年度最热标准手册 标准手册 长租公寓标准手册 全方位的住宅专家 30天内热门标准手册 标准手册 设计管理 标准化 7天内新作品 标准手册 地下车库导视系统 地库导视标准 标准手册 硬装施工控制节点 室内施工 节点细节 施工手册 年度最热标准手册 标https://wenben.znzmo.com/wenben/1182482202.html
4.Java208道面试题,大厂不是梦,好东西就要让更多人看到一般程序在运行时,产生对象,这些对象随着程序的停止而消失,但我们想将某些对象保存下来,这时,我们就可以通过序列化将对象保存在磁盘,需要使用的时候通过反序列化获取到。 对象序列化的最主要目的就是传递和保存对象,保存对象的完整性和可传递性。 譬如通过网络传输或者把一个对象保存成本地一个文件的时候,需要使用序列https://blog.csdn.net/IT_LaoFan/article/details/122116290
5.苍穹中级开发考试复习C、本地缓存(主要用于缓存元数据以及极高频率的数据) D、分布式缓存 (使用redis) 异常处理 1.(多选题) 以下属于异常规范的是 A、统一使用KDException,可自定义子异常 B、catch异常后,未往上抛出异常,务必记录日志 C、UI显示的异常信息,应是业务语义,让用户知道下一步该怎么处理 https://vip.kingdee.com/article/481397140678052096
6.设计模式篇之一文搞懂如何实现单例模式腾讯云开发者社区大家好,我是小简,这一篇文章,6种单例方法一网打尽,虽然单例模式很简单,但是也是设计模式入门基础,我也来详细讲讲。 DEMO仓库:https://github.com/JanYork/DesignPattern,欢迎PR,共建。 单例模式 单例模式(SingletonPattern)是Java中最简单的设计模式之一。 https://cloud.tencent.com/developer/article/2240961
7.java工程师面试题46.开发中都用到了那些设计模式?用在什么场合? 每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。 (1) MVC模式,在J2EE项目开发中主要用在表示层框架中,很好解决视图和流程控制。在项目中采用的Strhttps://www.iteye.com/blog/weitao1026-2361531
8.个人简历个人简历模板个人简历设计网站免费提供了多款个人简历模板,例如UI类个人简历模板,通用类个人简历模板等。打开个人简历设计网站后,设计师便可以在线使用网站提供的个人简历模板,并进行在线编辑和本地保存。https://js.design/special/resource-tag/personal-resume.html
9.医疗降海报怎么做?医疗降海报制作教程步骤模板修改完成后,点击编辑器右上角即可一键将设计好的作品保存到本地了,完全不懂设计的人也可以快速搞定医疗健康海报制作。 常规医疗健康海报的标准尺寸是多少? 医疗健康海报根据使用场景和设计需求不同,尺寸大小也会有所不同,一般医疗健康海报尺寸为(1242px * 2208px)其中线上展示医疗健康海报分辨率一般为72dpi(像素https://m.chuangkit.com/searcheo/course/28190.html
10.2016年4月全国自主考试(网页设计与制作)真题自考2016年4月全国自主考试(网页设计与制作)真题及答案,历年真题 一、单项选择题 (本大题共25小题,每小题1分,共25分) 在每小题列出的四个备选项中只有一个选项是符合题目要求的,请将其代码填写在题后的括号内。错选、多选或未选均无分。 1.以下协议用于远程终端登录主机的是 https://www.educity.cn/zikao/28145.html
11.面试一mob604756ee87ff的技术博客注册中 心,服务提供者,服务消费者三者之间均为长连接,监控中心除外,注册 中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立 即推送事件通知消费者注册中心和监控中心全部宕机,不影响已运行的提 供者和消费者,消费者在本地缓存了提供者列表注册中心和监控中心都是 可选的,服务消费者可以直连服务提供https://blog.51cto.com/u_15127553/4519203
12.煤矿安全监控系统AQ6201本文作者--贾柏青 郭凤斌 黄亚来 2006年5月,国家煤矿安全监察局颁布了一项全新的强制标准,即:AQ6201监控系统制造标准,决定重新换发带有N字头的“安标证”, 就是说众厂家必须推倒原来老产品,重新设计一套符合新标准的硬件和软件系统,统一检验达标后才能恢复生产。新标准颁布后,各厂家摩拳擦掌跃跃欲试,准备迎接这http://www.360doc.com/content/11/1003/18/198329_153153441.shtml
13.帮助中心2、若用户利用本服务从事任何违法或侵权行为,由用户自行承担全部责任,因此给中国统一教育网知学爱问或任何第三方造成任何损失,用户应负责全额赔偿。 八、服务条款的完善和修改 中国统一教育网知学爱问会有权根据互联网的发展和有关法律、法规的变化,不时地完善和修改“知道”的服务条款。中国统一教育网知学爱问保留随时https://www.tongyi.com/index.php/helpp/search
14.《界面设计》复习资料单项选择题1.交互设计师使用 Sketch 就是为了更好地完成产品项目的(C)工作。A.视觉设计B.动画设计C.交互设计D.平面设计【注释】:第二章 敲黑板画重点部分 第31页 交互设计师使用 Sketch 就是为了更好地完成产品项目的交互设计工作2.交互设计师需要全程参与产品的(B),与产品团队的人员达成共识,要让自己的交互https://www.wjx.cn/xz/260641939.aspx
15.社会实践活动策划(15篇)⑤ 最好家在本地,新义工优先. 3. 人员确定后,将他们平均分组。每组选出两位具有领导才能、认真负责的老义工,并对他们进行培训,由他们直接负责。 中期准备 从xx年7月份暑假开始,福利院义工活动正式开始。全体同学共计80人,分为10人一小组活动。每组活动时间为两天,早上9:00到达郑州福利院,下午5:00结束活动。中https://mip.oh100.com/daxue/4375862.html
16.容灾备份解决方案智动全景灾备系统的迁移功能,可方便、简单的迁移客户的服务器系统,而无论迁移源/目标是本地或云端,为企业服务器的布局和风险控制提供了便利的解决方案。 智动全景灾备系统产品的目: 为用户赋能-让用户拥有自主灾备系统运营、管理和应急恢复能力;让合作伙伴拥有自主灾备系统设计、建设和售后服务能力。 http://m.hxst188.com/KLRdataSystem.html
17.Rust程序设计语言简体中文版在本章中,你学习了如何: 使用rustup 安装最新稳定版的 Rust 更新到新版的 Rust 打开本地安装的文档 直接通过 rustc 编写并运行 Hello, world! 程序 使用Cargo 创建并运行新项目 是时候通过构建更实质性的程序来熟悉读写 Rust 代码了。所以在第二章我们会构建一个猜猜看游戏程序。如果你更愿意从学习 Rust https://rust-cn.redwoodjs.cn/print.html
18.新化县城乡居民基本养老保险(通用8篇)参保范围:具有本县户籍,年满16周岁(不含在校学生),未参加机关事业单位和城镇企业职工(含灵活就业者)基本养老保险的城乡居民,均可以参加城乡居民基本养老保险。实施时间:新型农村基本养老保险2010年9月30日起实施。 符合哪些条件时可以领取养老保险待遇 1、养老保险待遇的条件是什么? https://www.360wenmi.com/f/fileudzriv18.html
19.监理工作总结范文13篇另外,我们开展了“保安全、防阻断”的专项整治工作,完善了本地网的技术资料管理,加强了本地网线路的抢修及抢修人员的技术培养,确保了线路障碍恢复及时率考核指标的完成。 第五、开展岗位大练兵,不断提高员工技术素质。实践证明,只有娴熟的技能和过硬的本领才能做好一切工作,要想适应企业改革发展的要求,逐步提高线务https://www.gdyjs.com/shiyongwen/gongzuozongjie/510697.html
20.简短个人发展计划(精选33篇)抓住新教材的特点,结合本地学生实际情况设计开展活动,会做相关的调整。 2、科学备课:根据学校的要求,认真及时地备课、上课。注重上课过程的高效率,努力利用每一分钟使学生的知识得到巩固和发展。 3、不断提高教育教学能力:作为年青教师与老教师有很大差距。因此要不断加强自己的教学能力,虚心向有经验的老师讨教。努力https://www.diyifanwen.com/fanwen/gerengongzuojihua/16529874.html
21.鲜花阅读,流光故事。流光海岸望青鸟,故事池塘唱绿蛙。第5页3.检查本单位及下属单位的会计业务执行情况,保证输出、上报数据的正确性、完整性、规范性。 数据审核按分级控制的需要,分为省公司会计审核、本地网会计审核、县分公司会计审核三个角色,在各自应用范围内执行审核工作。除基本的审核权限外,一般应赋予一定查询权限,满足从多个角度检查会计业务的需要。 https://flowerread.wordpress.com/page/5/
22.培训学习心得体会(通用25篇)在新课程改革实施中,我深切地体会到,体育教师不再是消极地扮演教材执行者的角色,而是一个新课程的设计者;体育教师不应是一个只懂得教人如何运动的教练员,更应该是一个具备现代观念和教育素养,知道如何进行课程建设以及如何运用体育教学方法去促进学生全面发展的教育专业人员。新课标的实施,改变了以往的那种师道尊严,https://www.jy135.com/xindetihui/656599.html
23.大学语文(王树青第三版)教案91通知和通报92请示和报告9无法吸引他们注意的简历很可能被忽略,永久地沉睡在纸堆里。因此,突出个性、与众不同便是设计个人简历成功的法宝。个人简历写作时要注意做到以下几点: 1.内容上突出个性内容就是一切,所以一定要突出你个人的能力、成就以及过去经验,使你的简历更出众。写作时应该注意先将本人具备的能力和所取得的成绩一一列出,然后https://max.book118.com/html/2023/0714/5004242344010242.shtm