前段时间,撰写过“ 单页应用优化–懒加载”的问题,这篇我们描述一下单页应用的另外一个问题权限。提起权限,一般会涉及如下几种情况:

  • 应用使用权【登录】
  • 页面级别权限【菜单访问权限】
  • 模块级别权限【区域<组件、按钮>是否显示】
  • 数据级别权限【数据权限】

前端的权限控制实质上就是用于展示,让操作变得更加友好,真正的安全实际上是由后端控制的!

下述所有示例,都使用Vue编写,会重点描述页面级别权限模块级别权限

应用使用权限

这里的使用权限是指用户登录,其实就是简单的判断登录状态而已。通常我们会使用Session进行控制,前端请求携带Cookie(Cookie中保存sessionID),服务端依此进行用户身份识别。然而,使用Session进行管理用户登录状态,在当下后台无状态化盛行的情况下,以及多台节点部署Session同步或者横向扩展(Scale-out,把 session 实现基于中心化的 Redis 服务)等问题(有成熟的解决方法,这里不赘述),已不是最佳方案。

前端后分离的项目中,往往采用Restful风格进行前后端约束,我们通常会在请求头中携带Authorization/Token来解决用户身份识别。

上述流程参考自:https://www.cnblogs.com/qianduantuanzhang/archive/2018/01/05/8204692.html

思路:

第一步:点击登录按钮,触发Vuex中的登录事件,成功返回Token,存储Token到sessionStorage/localStorage中(前后端可以约定相应的编码机制);

// 登录成功
store.commit(types.LOGIN)
/** 1. vuex中存储用户和token信息* 2. 同步信息到localStorage中* 3. 调整到相关页面*/

第二步:拦截处理

  • 【请求后台API】Axios Request钩子中,添加Authorization头,服务端获取进行校验;如果存在伪造情况,返回401,前端在Axios Response钩子中,进行捕获处理

 // Axios Request钩子axios.interceptors.request.use(req => {req.headers.Authorization = store.state.tokenreturn req;}, error => {return Promise.reject(error);})// Axios Response钩子axios.interceptors.response.use(res => {return res;}, error => {switch(error.response.status) {case 401:// 触发退出操作 并跳转到登录页面store.commit(types.LOGOUT)router.replace({path: '/login'})}                           return Promise.reject(error);})                         
  • 【页面跳转】路由beforeEach钩子进行token信息校验(这里只能校验是否存在,具体准确性无法校验)
 router.beforeEach((to, from, next) => {// 注销 或者 没有用户信息if(to.path === '/login' || store.state.[info]) {store.commit(types.LOGOUT)next({path: '/login'})} else {next()}})

页面级别权限

需要router.addRoutes动态挂载路由。vue2.2.0以后新增了router.addRoutes,可动态挂载路由,无需在实例化之前就挂载上去的!

  • 创建vue实例的时候将vue-router挂载,但这个时候vue-router挂载一些登录或者不用权限的公用的页面;
  • 当用户登录后,获取用户权限列表,生成最终用户可访问的路由表;
  • 调用router.addRoutes(store.getters.addRouters)添加用户可访问的路由;
  • 使用vuex管理路由表,根据vuex中可访问的路由渲染header、侧边栏组件。

参考地址:https://juejin.im/post/591aa14f570c35006961acac

// 登录成功,触发
this.updateRouter(data.routes)// ...
methods: {// routes是后台返回来的路由信息 routes里应包含404情况async updateRouter (routes) {// routers默认const routers = [{path: '/login',name: 'login',component: login},  {path: '/',component: App,redirect: 'index',children: []}]routes.forEach(r => {routers[1].children.push({name: r.name,path: r.path,component: () => routesMap[r.component]})})this.$router.addRoutes(routers)this.$router.push('/')}
}

这样就实现了根据后端的返回动态扩展路由,当然也可以根据后端的返回生成侧栏或顶栏的导航菜单,这样就不需要再在前端处理页面权限了。需要注意的是,上面有待处理问题:

  • 登录成功后默认跳转到’/’,并非后台指定

注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在routers一同声明了404,后面的所以页面都会被拦截到404,详细的问题见addRoutes when you’ve got a wildcard route for 404s does not work

对于后台返回的routes的说明:

方式一:后台完整返回整个路由,这里后台需要返回component的加载信息,然后前端直接addRoutes指定路由下(无权限的路由不会挂载,但后台需要指定component地址,前端强制依赖后台);

方式二:后台返回相关路由权限标识,前端将完整路由进行标识展示(所有路由会被挂载

我们采用二者结合方式,使用后台路由标识name(这里需要保证name的唯一性),然后前端根据后台返回的标识对路由进行剔除,动态添加路由。

模块级别权限

某些按钮是否可以点击;某些区域是否可以查看~

组件形式

这里使用render函数,它比template更接近编译器。

// Auth.vue
<script>export default {name: 'Auth-Comp',functional: true,// 增加了context来弥补缺少的实例render: function(createElement, context) {let {props, children, data} = contextif(props.auth) {// return children  // 完全透明的传入任何特性、事件监听器、子节点等。return createElement('div', data, children)} else {return null}}}
</script>// 使用
<Auth-Comp :auth="true"><Hello></Hello></Auth-Comp>

缺点,多添加了一层div,因为不允许存在多个根节点;注意,这里不能使用context.slots().default,因为如果存在具名slots会展示不全

指令形式

Vue.directive('auth', {inserted(el, binding, vnode) {let {value} = bindingif(value && !hasPermission(value)) {el.parentNode && el.parentNode.removeChild(el)}}
})// 使用
<Hello v-auth="true"></Hello>

一个指令定义对象可以提供几个钩子(均可选):

  • bind:指令第一次绑定到元素时调用,只调用一次
  • inserted:被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已被插入文档中);
  • update:所有组件VNode更新时调用,可能发生在其子VNode更新前,可以比较更新前后的值来忽略不必要的模板更新;
  • componentUpdate:指令所在组件的VNode**及其子VNode**全部更新后调用;
  • unbind:只调用一次,指令与元素解绑时调用。

缺点,不能在<template>标签上使用!

数据级别权限

这通常需要服务端根据用户权限对数据进行控制,来确保是否返回给前端,前端根据返回结果进行展示~~~

补充

公司采用的权限标识为8421,即

delete put post get
8 4 2 1

关于权限规则,也可以采用Apache Shiro的规则。printer:query:lp7200 第一部分是域,第二部分是操作,第三部分是正在执行的实例。

参考地址:http://shiro.apache.org/permissions.html

单页应用优化--权限相关推荐

  1. 网站单页的优化技巧和方式

    对于绝大部分SEOer来说,优化多页面的网站比优化单页面网站简单,因为单页面网站内容比较固定和简单,站内锚文本更是无从谈起,这些无疑增加了SEO优化的难度.单页面网站顾名思义,就是只有一个页面的网站, ...

  2. 单页应用优化--懒加载

    单页Web应用(single page web application,SPA)会一次性载入页面资源,利用本地计算能力渲染页面,提高页面切换速度与用户体验.由此带来了首屏加载缓慢耗时的诟病,这也是困扰 ...

  3. H5竞价单页网站源码带订单系统

    竞价单页一直都是比较火爆的一类源码,很多做产品竞价的朋友几乎都会找这样的源码,因为做搜索引擎的竞价推广,如果人工一一对接的话会很累,而且可能下单量要少得多,但是使用竞价单页就不一样了,很多消费者从竞价 ...

  4. ajax div 赋值重新渲染_优化向:单页应用多路由预渲染指南

    前言 Ajax 技术的出现,让我们的 Web 应用能够在不刷新的状态下显示不同页面的内容,这就是单页应用.在一个单页应用中,往往只有一个 html 文件,然后根据访问的 url 来匹配对应的路由脚本, ...

  5. 玉米社:单页网站怎么做seo?优化思路?

    单页网站怎么做seo?优化思路? seo是一个持续优化探索的过程,一些seo大咖会尝试各种优化方法,其中就包括单页优化.下面,介绍一些单页网站怎么做seo?优化思路?供大家学习参考. 1.没有多个页面 ...

  6. SEO单页优化技巧与软文推广

    SEO是什么,或许你已经了解.但SEO教程自学网还是简单和你说一下SEO的本质原理. SEO本质原理: SEO是指在了解搜索引擎自然排名机制的基础上,对网站进行内部及外部的调整优化,改进网站在搜索引擎 ...

  7. prerender html5,HTML5 VUE单页应用 SEO 优化之 预渲染(prerender-spa-plugin)

    前言:当前 SPA 架构流行的趋势如日中天,前后端分离的业务模式已经成为互联网开发的主流方式,但是 单页面 应用始终存在一个痛点,那就是 SEO, 对于那些需要推广,希望能在百度搜索时排名靠前的网站而 ...

  8. 单页应用的优缺点,单页应用首屏加载优化、小程序首次启动速度优化

    单页应用的优缺点 单页应用,简称(Single Page Application)是指整个应用只一个HTML页面,所有的功能和交互都在这个页面完成,利用JavaScript动态改变HTML内容. 优点 ...

  9. vue单页项目常用优化

    vue项目是单页应用,项目在第一次加载的时候会将大部分内容都加载进来,故而会导致加载很慢,以下是优化方案: 1.使用cdn加载一些不常变化的文件,比如用到的UI框架,vue脚手架相关的文件 (参见vu ...

最新文章

  1. html兼容不同屏幕 代码,rem的正确使用姿势 -- 完美解决H5页面不同尺寸屏幕的适配问题...
  2. CTFshow 信息收集 web12
  3. WebService怎样在IIS上部署
  4. 运维自动化 第二章 openpyxl的用法,读写excel内容
  5. Java并发编程实战 代码bug,Java并发编程实战(1)- 并发程序的bug源头
  6. 生成n套数位加减乘除_leetcode 算法汇总(四)位运算
  7. PhpStorm failed to transfer files by FTP 报错解决方法
  8. 桁和 / Digit Sum(AtCoder-2038)
  9. SpringBoot入门-自动配置原理
  10. PostgreSQL查看系统视图的源码
  11. Spring/Spring MVC-面试题
  12. getdatatable mysql_C# 自定义MySqlHelp类,包含了获取DataTable的方法,但是调用时总是提示“类型初始值设定项引发异常”...
  13. 关于c语言中栈和堆释放的问题
  14. php parse_url,pathinfo,basename函数
  15. opendds协议服务器,OpenDDS 开发手册
  16. 项目管理前话001——商业模式画布
  17. 微信小程序分享小程序码的生成(带参数)以及参数的获取
  18. 人工智能研究中深度学习的局限性
  19. win7系统安装卡在启动服务器,安装win7卡在启动界面不动进不了BIOS的解决方法 - 系统家园...
  20. mysql免安装百度云_Mysql免安装配置

热门文章

  1. 修复win10启动项
  2. C# 把图片转换成流
  3. 看完这篇文章,你的SCI可以100%发出去
  4. php bcmul结果为0,php – 为什么bcmul返回的数字与我指定的数字不同?
  5. 继承方式之原型链继承
  6. Maven之生命周期和插件
  7. 超频到3200最佳时序_全网性价比最高:威刚龙耀D50新品内存,为超频而生
  8. 第六次 java实验 紫金学院 泛型01
  9. 苹果cms 压缩html,苹果cmsv10seo友好模板配合关键设置两个月上权重2
  10. python列表实现栈,Python之列表实现栈的工作功能