前后端分离中的权限管理思路

在传统的前后端不分的开发中,权限管理主要通过过滤器或者拦截器来进行(权限管理框架本身也是通过过滤器来实现功能),如果用户不具备某一个角色或者某一个权限,则无法访问某一个页面。

但是在前后端分离中,页面的跳转通通交给前端去做,后端只提供数据,这种时候,权限管理不能再按照之前的思路来。

首先要明确一点,前端是展示给用户看的,所有的菜单显示或者隐藏目的不是为了实现权限管理,而是为了给用户一个良好的体验,不能依赖前端隐藏控件来实现权限管理,即数据安全不能依靠前端,就像普通的表单提交一样,前端做数据校验是为了提高效率,提高用户体验,后端才是真正的确保数据完整性。(例如前端注册时传来一个邮箱地址,前端已经校验通过,但是后端还需要再校验,因为只有后端的校验才是真正的确保数据是合法的,前端只是为了提高用户体验,给用户快速的响应一下,免得用户把数据传到后端再返回才知道错误)。

所以真正的数据安全是在后端实现的,后端在设计的过程中,就要确保每一个接口都是在满足某种权限的基础上才能访问。也就是说,不怕将后端数据接口暴露出来,即使暴露出来,只要你没有相应的角色,也是访问不了的。

前端为了良好的用户体验,需要将用户不能访问的接口或者菜单隐藏起来。

有人说,如果用户直接在地址栏输入某一个页面的路径,怎么办?此时如果没有过任何额外的处理的话,用户确实可以通过直接输入某一个路径进入到系统的某一个页面中,但是,不用担心数据泄露问题。因为没有相关的角色,就无法访问相关的接口,但是如果用户非这样操作,进入到一个空白的页面,用户体验不好,此时我们可以使用Vue中的路由导航守卫,来监听页面跳转,如果用户想要去一个未获授权的页面,则直接在前置路由导航守卫将之拦截下来,重定向登录页,或者直接就停留在当前页,不让用户跳转。

总而言之一句话,前端的所有操作,都是为了提高用户体验,不是为了数据安全,真正的效验要在后端来做。

后端中的权限管理,每个角色统一一种路径。
在这里插入图片描述
在路由表中的index.js文件中添加权限如下:
在这里插入图片描述
在Home主页读取数据出来显示的时候,当前登陆的用户如果不具备路由表index.js中所要求的角色,就不显示指定菜单
在这里插入图片描述




前言

随着移动互联网的发展,前端开发领域也越来越广,前端早已经告别了切图的时代,迎来了规模化,工程化的大前端时代。近几年随着react、angular、vue等前端框架的兴起,前后端分离的架构迅速流行。但同时权限控制也带来了问题。

前后端分离之后,虽然前端也会进行权限控制、但是都比较简单。而且仅仅前端进行权限控制并不是真正意义的权限控制,用户完全可以绕开前端控制直接向后端发起请求。

权限设计

迄今为止最为普及的权限设计模型是RBAC模型,基于角色的访问控制(Role-Based Access Control)

img

市面上流行的Apache Shrio、Spring Security,都是基于此模型设计的。权限系统可以说是整个系统中最基础,同时也可以很复杂的,在实际项目中,会遇到多个系统,多个用户类型,多个使用场景,这就需要具体问题具体分析,但最核心的RBAC模型是不变的,我们可以在其基础上进行扩展来满足需求。

下面是简单的用户、角色、操作、机构数据库表设计,基本满足了大多数业务场景。

img

前端控制

用户登录成功会生成一个Token,其中会附带一些基本的用户信息,不建议附带角色权限信息。用户向后端发送请求都会附带这个Token

前端一般是菜单和按钮控制,在用户登录认证成功之后,根据用户ID实时获取菜单信息并渲染。按钮控制的话,情况比较复杂,如果要求不是很高可以一次性查询出来,放入本地缓存,进行本地鉴权。

这里撸一个比较简单的实现:

hasRole: function(roles){var roleNames = this.userInfo.roleNames;if(roleNames!=""){var role = roles.split(",");var array  = roleNames.split(",");for(var i=0;i<role.length;i++){if(array.indexOf(role[i])>-1){return true;}}}return false;
}

按钮控制:

<i-button type="primary" v-if="hasRole('admin')" icon="ios-cloud-download"  @click="exportCashReports">导出</i-button>

后端控制

前端虽然进行了控制,但这远远不够,特殊用户完全可以避开前端控制直接向后端发起请求,这时候如果后端没有对请求进行安全校验,很容易会把敏感数据暴露出去。

在单体架构时代,如果我使用了安全框架,我只需要一个注解,亦或者一个拦截配置就可以搞定。

比如这样:

@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean (SecurityManager securityManager) {ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();shiroFilterFactoryBean.setSecurityManager(securityManager);shiroFilterFactoryBean.setLoginUrl("/login.html");shiroFilterFactoryBean.setUnauthorizedUrl("/403");Map<String, Filter> filtersMap = new LinkedHashMap<>();filtersMap.put("kickout", kickoutSessionControlFilter());shiroFilterFactoryBean.setFilters(filtersMap);Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();/*** 静态文件*/filterChainDefinitionMap.put("/css/**","anon");filterChainDefinitionMap.put("/images/**","anon");filterChainDefinitionMap.put("/js/**","anon");filterChainDefinitionMap.put("/file/**","anon");/*** 登录*/filterChainDefinitionMap.put("/login.html","anon");filterChainDefinitionMap.put("/sys/logout","anon");filterChainDefinitionMap.put("/sys/login","anon");/*** 管理后台*/filterChainDefinitionMap.put("/sys/**", "roles[admin]");filterChainDefinitionMap.put("/**", "kickout,authc");shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);return shiroFilterFactoryBean;
}

或者这样:

 /*** 角色列表*/@PostMapping("/list")@RequiresRoles(value="admin")public Result list(SysRole role){return sysRoleService.list(role);}

前后端分离之后,后端并不会保存任何用户信息,只能通过前端传输的token进行校验,这里参考Shrio的实现思路,自己撸一个注解来实现权限校验。

 
/*** 权限注解*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresRoles {/*** A single String role name or multiple comma-delimitted role names required in order for the method* invocation to be allowed.*/String[] value();/*** The logical operation for the permission check in case multiple roles are specified. AND is the default* @since 1.1.0*/Logical logical() default Logical.OR;
}

然后写个拦截器对请求进行拦截,这里截取部分认证代码:

/*** @Description* @Date 2020/6/12*/
@Component
public class AuthUtils {@Autowiredprivate RedisUtils redisUtils;public boolean check(Object handler,String userId){HandlerMethod handlerMethod = (HandlerMethod) handler;Annotation permAnnotation= handlerMethod.getMethod().getAnnotation(RequiresPermissions.class);if(permAnnotation!=null) {String[] role = handlerMethod.getMethod().getAnnotation(RequiresPermissions.class).value();List<String> roleList = Arrays.asList(role);/*** 获取用户实际权限*/List<Object> list = redisUtils.lGet("perms:"+userId,0,-1);List<String> permissions = roleList.stream().filter(item -> list.contains(item)).collect(toList());if (permissions.size() == 0) {return false;}}else{Annotation roleAnnotation= handlerMethod.getMethod().getAnnotation(RequiresRoles.class);if(roleAnnotation!=null){String[] role = handlerMethod.getMethod().getAnnotation(RequiresRoles.class).value();List<String> roleList = Arrays.asList(role);/*** 获取用户实际角色*/List<Object> list = redisUtils.lGet("roles:"+userId,0,-1);List<String> roles = roleList.stream().filter(item -> list.contains(item)).collect(toList());if (roles.size() == 0) {return false;}}}return true;}
}

以上,在用户登录成功以后会保存用户的角色信息到缓存,生产环境中可以根据业务需求的实时性,在读取数据库和读取缓存上自行选择。

小结

前后端开发不是什么银弹,微服务也不是,不要盲目的选型跟风,也不要学习什么大厂经验,更不要谈什么技术债,适合自己团队的才是最好的。

当然,项目不高大上一些,出去怎么吹逼,怎么扩展团队规模,怎么升职加薪,所以我前面的都是废话,该分还是得分!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/555829.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前、后端分离权限控制设计与实现

简述 近几年随着react、angular、vue等前端框架兴起&#xff0c;前后端分离的架构迅速流行。但同时权限控制也带来了问题。 网上很多前、后端分离权限仅仅都仅仅在描述前端权限控制、且是较简单、固定的角色场景&#xff0c;满足不了我们用户、角色都是动态的场景。且仅仅前端…

前后端分离必备的接口规范,十分接地气

1. 前言 随着互联网的高速发展&#xff0c;前端页面的展示、交互体验越来越灵活、炫丽&#xff0c;响应体验也要求越来越高&#xff0c;后端服务的高并发、高可用、高性能、高扩展等特性的要求也愈加苛刻&#xff0c;从而导致前后端研发各自专注于自己擅长的领域深耕细作。 然…

ubuntu php设置,关于ubuntu php环境设置详解-PHP问题

ubuntu php设置办法&#xff1a;起首更新源列表&#xff1b;而后关上“终端窗口”&#xff0c;输出饬令“sudo apt-get install php5”来装置php&#xff1b;接着装置设置装备摆设好apache环境&#xff0c;并装置php5-gd模块&#xff1b;最初创立“info.php”文件便可。Ubuntu …

MyBatis-Plus——增删查改

开发环境 IDEA JDK&#xff1a;1.8 Spring Boot:2.6.2 Maven:3.3.9 MySQL:8.0.23 数据库准备 CREATE DATABASE mybatis_plus_db;DROP TABLE IF EXISTS person; CREATE TABLE person(id BIGINT(20) NOT NULL COMMENT 主键ID, name VARCHAR(30) NULL DEFAULT NULL COMMENT 姓…

让程序员最爽的ThreadLocal使用姿势

一、常见场景 ​ 1、ThreadLocal作为线程上下文副本&#xff0c;那么一种最常见的使用方式就是用来方法隐式传参&#xff0c;通过提供的set()和get()两个public方法来实现在不同的方法中的参数传递。对于编程规范来说&#xff0c;方法定义的时候是对参数个数是有限制的&#x…

一场事故告诉你zookeeper和nacos谁更适合做注册中心

前言 ​ 在分布式系统中&#xff0c;注册中心充当着重要角色&#xff0c;是服务发现、客户端负载均衡中不可缺少的一员。注册中心除了能够实现基本的功能外&#xff0c;他的稳定性、可用性和健壮性对整个分布式系统的流畅运行影响重大。dubbo作为国内一款主流的分布式系统&…

Mysql执行计划含义,mysql执行计划介绍

烂sql不仅直接影响sql的响应时间&#xff0c;更影响db的性能&#xff0c;导致其它正常的sql响应时间变长。如何写好sql&#xff0c;学会看执行计划至关重要。下面我简单讲讲mysql的执行计划&#xff0c;只列出了一些常见的情况&#xff0c;希望对大家有所帮助。测试表结构&…

寄生虫php版,-PHP版SEO最新教材版排名DeDeCms寄生虫V90繁殖

今天视频教程演示说明下PHP寄生虫服务端的使用。主要在很多搭建的过程中会出错&#xff0c;今天主要就讲解下寄生虫配置常见的问题。那么同样也可以看下我们之前的通用版寄生虫使用教程[通用版教程在文件夹中有]&#xff0c;本教程是针对PHP版本的寄生虫服务端进行配置演示。继…

MySQL中 JSON 数据类型应用

前言 今天接触到mysql中json数据类型&#xff0c;之前不知道有这个类型&#xff0c;今天学习一下。 JSON我相信大家都已经很熟悉了&#xff0c;但在 MySQL中&#xff0c;直至 5.7 版本中&#xff0c;才正式引入 JSON数据类型。在次之前&#xff0c;我们通常使varchar或text数…

MySql中json类型的使用___mybatis存取mysql中的json

MySql中json类型的使用 MySQL从5.7.8起开始支持JSON字段&#xff0c;这极大的丰富了MySQL的数据类型。也方便了广大开发人员。但MySQL并没有提供对JSON对象中的字段进行索引的功能&#xff0c;至少没有直接对其字段进行索引的方法。本文将介绍利用MySQL 5.7中的虚拟字段的功能…

百度下拉词+php,百度下拉词是如何生成的?

我们在百度搜索某一词汇的时候&#xff0c;都会在搜索框下面弹出一些相关性和搜索次数比较多的语句或词语&#xff0c;我们在百度上搜索一下&#xff0c;就可以看到用户平时搜索习惯&#xff0c;搜索爱好是什么。护发下拉很多小伙伴就又有疑问了&#xff1a;这些下拉词是根据什…

python元组赋值给变量,Python的赋值

一、序列解包多个赋值操作同时进行&#xff1a;赋值多个值后面再遇到对多个变量赋值时&#xff0c;就不需要对一个变量赋完值再对另一个变量赋值了&#xff0c;用一条语句就可以搞定&#xff0c;例如&#xff1a;再次赋值由输出结果看到&#xff0c;x和y的值交换了&#xff0c;…

微服务,你得知道这

目录 一、业务场景介绍 二、Spring Cloud核心组件&#xff1a;Eureka 三、Spring Cloud核心组件&#xff1a;Feign 四、Spring Cloud核心组件&#xff1a;Ribbon 五、Spring Cloud核心组件&#xff1a;Hystrix 六、Spring Cloud核心组件&#xff1a;Zuul 七、总结 概述…

分布式和微服务的区别

分布式和微服务的区别 1.颜老师&#xff0c;分布式和微服务有什么区别呢&#xff1f;网上说啥的都有&#xff0c;越看越晕了。 答&#xff1a;分布式的核心就一个字&#xff1a;拆。只要是将一个项目拆分成了多个模块&#xff0c;并将这些模块分开部署&#xff0c;那就算是分布…

Oracle数据库空间突然增大,Oracle 表空间异常增长过快解决方法

1. 首先用语句查询容量大于1G的数据段select segment_name,sum(bytes)/1024/1024 from dba_segments group by segment_name having sum(bytes)/1024/1024>1000;得到如下结果&#xff1a;SYS_LOB0000136091C00003$$ 255332MSYS_LOB0000136441C00004$$ 7170MSYS_C…

分布式和微服务是什么?二者的区别又是什么?

一、分布式系统 在《分布式系统原理与范型》一书中有如下定义&#xff1a; “分布式系统是若干独立计算机的集合&#xff0c;这些计算机对于用户来说就像单个相关系统”&#xff1b; 分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统…

SpringCloud 超详细个人笔记

文章目录SpringCloud1、常见面试题2、微服务概述2.1、什么是微服务2.2、微服务和微服务架构2.3、微服务优缺点2.4、微服务技术栈有哪些&#xff1f;2.5、为什么选择SpringCloud 作为微服务架构2.5.1、选型依据2.5.2、当前各大IT公司用的微服务架构有哪些&#xff1f;2.5.3、各微…

oracle server process,Oracle体系结构及备份(四)server-process

一 什么是服务器进程 除了 Oracle 的后台进程外&#xff0c;还有一些进程是代表用户的&#xff0c;称为服务器进程。这些服务器进程负责按照用户的要求检索数据&#xff0c;并将结果返回给用户。此外&#xff0c;还负责为用户修改缓冲区高数缓存中的数据。 当用户连接到 Oracle…

潘多拉路由器搭建php,MT7620A 无线路由 极路由 1S 定制版 OPERWRT 潘多拉 中继 营销...

定制版 机器 非原版极路由 1S原版极路由下面连接购买https://item.taobao.com/item.htm?id527531952640这个机器是大客户 定制版 营销路由 硬件和极路由 1S 完全相同&#xff0c;只简化了 SD卡座更换为塑胶外壳可以自己DIY 增加USB 接口和SD卡座电源接口为 MICRO USB接口&…

linux close 头文件,Linux open close read write lseek函数的使用

我们经常需要在Linux中进行文件操作&#xff0c;今天我就来分享下文件操作用到的一些函数1 open所需头文件&#xff1a;函数原型&#xff1a;int open(const char *pathname,flags,int perms)pathname&#xff1a;被打开的文件名&#xff0c;可包含路径flag &#xff1a;文件打…