关于权限控制:Worktile-权限设计与实现

Worktile是国内最优良的企业级我的项目合作与指标管理工具之一,这个我的项目曾经继续了9年之久,书写了研发团队的历史长卷,我作为“后来者”有幸地参加其中。在过来研发的一年里,做的事件大多数是对原有性能的加强和重构,也学习和总结了 一点点Worktile核心技术和常识,本文就是其中之一—— 权限零碎。 Worktile的权限异样简单,在开发中,从纳闷到深刻,再到起初的望之止步,直至最终的克服,这其中屡次与共事的交换,又屡次的总结,逐步地清晰,到当初对它进行了我认为比拟全面的总结,上面就跟大家一起 揭秘(分享) 这块简单而精彩的内容。 一、Worktile 帐户体系 首先总览一下Worktile的帐户体系。在此之前,先介绍一下该零碎:它是多租户零碎的一种,在我接触过的多租户零碎中,有两种类型,一种是像企业微信,飞书,它们的租户类型有用户和团队/组织/企业,那么这类利用的帐户体系 就有两个用户概念,一个是零碎用户,一个是团队成员;而另一种就是 Worktile,租户类型 是 企业/团队/组织的,它是不含集体租户,所有业务的根底条件是 团队(team) ,所以权限这块也是基于 团队成员来管制的。 目前比拟支流的权限设计模型,一种是ACL(Access Control List),是次要是基于用户来管制权限,而另一种是RBAC模型(Role-Based Access Control )基于角色的访问控制,而这两种在Worktile中都有波及,在绝大部分是RBAC模型,大量的权限是基于用户设计和管制的。 上图中,能够看到Worktile权限是由性能权限和数据权限两局部组成,上面对这性能权限和数据权限两局部 具体解说。 二、设计与实现性能权限和数据权限都是基于利用的维度来划分的,Worktile 现有的利用有我的项目、工作、指标(OKR)、音讯、日历、审批、网盘、考勤...... (更多理解点 这里)。 性能权限设计性能权限是齐全依照 RBAC 模型 设计的,关系为: 由两局部组成:操作权限和可见权限,是依照利用模块的维度划分的,每个利用模块下散布多个权限点和可见范畴。 给用户出现的模式是在利用的后盾—>角色治理中(见下图),其中企业角色蕴含两局部: 1. 零碎默认角色(所有者、管理员、成员、部门主管) 2.自定义角色,权限列表(下图右侧)中,打对勾的代表该角色已领有的权限,数据范畴 代表 该角色 在 利用内的可见维度。 可操作权限 可见权限 实现在传统关系型数据库的设计,根本都是三张表:角色表,权限表,角色权限关联表,如果校验一个或一组权限,是须要三表关联查问的。 而在Worktile中则不然,采纳的贮存形式是:非关系型数据库Mongodb + 零碎配置文件, 由一张表来体现,权限列表由零碎配置文件存储。 Mongodb,人造反对数组和JSON类型的数据贮存,在角色和权限的关联配置中更为灵便,这一环在此设计中,不可或缺! 配置文件次要存储的是权限列表,零碎内置,前端也须要一份配置是因为列表展现地位匹配。 为何这么设计? 数据库是因为整个产品的主库就是 Mongodb,这也是最大的起因;权限列表之抉择配置文件贮存,我猜测 是因为权限是零碎内置,并且是固定的,改变频率较低,所以没有必要每次都要再交互一次数据库,不仅是性能权限如此,上面谈到的数据权限亦是如此。 零碎的权限列表 配置的数据结构大抵如下(以下只是阐明构造,并非理论数据): 一级节点的key代表的是利用模块,二级节点的key代表权限点,value为权限的形容,具体如下: 角色与权限的关联配置 在Worktile中只须要一张角色表足矣!构造如下(关键字段): id,name,privileges,is_system,其中外围字段是privileges,该字段记录的是权限项,是一个json,具体如右下图。 ...

February 11, 2022 · 2 min · jiezi

关于权限控制:PingCode-Wiki-权限设计之ACL

2021年 Wiki 退出了很多强硬的个性,其中包含协同编辑 、页面权限、表情符号 等,这些性能给用户带来了更好的体验。作为 Wiki 使用者兼开发者,今日来聊聊年初上线的页面权限,同时总结一下开发阶段波及到的技术、遇到的问题以及解决方案,对于权限自己之前曾经写过一篇 Worktile 权限的文章了,Worktile 权限着重讲了 RBAC(基于角色的权限管制计划)的设计与实现,本文基于 Wiki 页面权限抉择的另一个支流权限设计的计划:ACL。 本文大抵分为三局部: ACL 介绍介绍咱们的权限以及为什么抉择它设计实现一、ACL 介绍1. 什么是 ACL?ACL:Access Control List,权限管制列表,是对文件以及目录的权限管制计划。赫赫有名的 Linux 权限零碎,它就是 ACL 的典型案例,自己在开发过程中也受到了 Linux 权限设计的一些启发。 2. ACL的应用场景应用场景也能够换个问法:为什么要应用 ACL ?对于这个问题咱们还以 Linux 作为案例:Linux 自身只提供了Owner(所有者)、Group(用户组)、Others(其余成员),也就是说其余成员或用户组是无奈指定更细粒度的权限。 为了更好的解释,咱们来举个简略的例子(场景): 有 4 个成员有 A、B、C、D,其中 A、B、C 是开发组G的成员,A成员创立了一个代码仓库并把团队开发的代码搁置到该目录中,其中这些代码次要是对于G组的,与其余成员无关,所以A把文件目录设置了权限,权限是组内可读可写,其他人没有任何权限。 当初来剖析一下各个角色,A 是仓库的 Owner,G 是 Group(含B、C),D 是与该文件无关的成员,所以是 Others。当初入职了一个用户E,因为E是新人,所以不想让E去操作代码,只容许他查看相熟代码。 面对这种场景,试想一下如何给 E 成员设置对应权限呢?答案是 oh no,因为 E 既不能依照 G 组权限,也不能依照 Others 权限,更不能是 Owner!所以面对这种鸡肋的权限,ACL 就作为了其补充,ACL 能够反对针对某一个用户或某个用户组做独立的权限,完满解决了相似场景。 二、PingCode Wiki 权限架构OK,理解了什么是 ACL 以及应用场景,咱们来聊一下 Wiki 的权限架构,根本架构见下图。 1. 根底权限 RBAC——角色对应的权限1.1 权限配置 ...

February 11, 2022 · 2 min · jiezi

关于权限控制:页面元素权限控制

按钮权限管制按钮权限管制的交互方式无非两种:"不可见" 和 "可见不可点"。 不可见不可见的交互方式绝对简略,管制DOM的显示暗藏即可。 在Vue中能够通过下述形式实现: v-if 管制其是否显示v-show管制其是否显示,但不够保险,毕竟 v-show 只是把款式改成 display: none,在实在的 DOM 渲染还是存在在React中能够通过下述形式实现: JSX中条件判断const Demo = () => { return <div> {boolean && <Button>submit</Button>} </div>}应用高阶组件HOC,抽离判断逻辑const Demo = () => { return <div>code...</div>}/** 高阶组件 */const HOC = <T>(Com: Com: React.ComponentType<T>) => { if (whiteList.includes(code)) return <Com {...this.props} /> return null;}可见不可点页面中有很多性能点,如果有些性能点用户不能操作而不显示DOM,可能会导致页面布局错乱,或者影响页面的好看,有些产品在管制性能点权限期间望元素“可见不可点”。 在Vue中能够通过下述形式实现: 自定义指令Vue.directive。应用addEventListener给元素减少一个捕捉事件,捕捉事件会优先于 @click 触发,而后在捕捉事件办法体中应用 stopImmediatePropagation 阻止事件冒泡和其它雷同事件的触发,因而达到管制元素不可点击的目标如果多个事件监听器被附加到雷同元素的雷同事件类型上,当此事件触发时,它们会按其被增加的程序被调用。如果在其中一个事件监听器中执行 stopImmediatePropagation() ,那么剩下的事件监听器都不会被调用。MSDN - stopImmediatePropagation// 注册自定义指令脚本/** 权限拦挡 */const interception = (event) => { event && event.stopImmediatePropagation();}/** 白名单 */const whiteList = [];/** 注册指令 */Vue.directive('permission', { bind(el, binding) { /** 不在白名单中 */ if (!whiteList.includes(binding.value)) { el.style.pointerEvents = 'none'; el.setAttribute('disabled', 'disabled'); el.addEventListener('click', interception, true); } }, unbind(el) { el.removeEventListener('click', interception); }});这里应用 pointer-events 只是一个辅助性能,并不一定意味着元素上的事件监听器永远不会触发,如果后辈元素有指定 pointer-events 并容许成为事件指标的话,是能够触发父元素事件,而且单纯依附 CSS 属性来管制不点击,还是有危险,因而这里仅作辅助作用。 ...

August 2, 2021 · 2 min · jiezi

关于权限控制:SpringBoot整合jasbin实现RBAC权限管理

前言什么是jasbin?概述Casbin是一个弱小的、高效的开源访问控制框架,其权限管理机制反对多种访问控制模型 Casbin反对以下编程语言: Casbin 能够:反对自定义申请的格局,默认的申请格局为{subject, object, action}。具备访问控制模型model和策略policy两个外围概念。反对RBAC中的多层角色继承,不止主体能够有角色,资源也能够具备角色。反对内置的超级用户 例如:root或administrator。超级用户能够执行任何操作而无需显式的权限申明。反对多种内置的操作符,如 keyMatch,不便对门路式的资源进行治理,如 /foo/bar 能够映射到 /foo* Casbin 不能:身份认证 authentication(即验证用户的用户名、明码),casbin只负责访问控制。应该有其余专门的组件负责身份认证,而后由casbin进行访问控制,二者是相互配合的关系。治理用户列表或角色列表。 Casbin 认为由我的项目本身来治理用户、角色列表更为适合, 用户通常有他们的明码,然而 Casbin 的设计思维并不是把它作为一个存储明码的容器。 而是存储RBAC计划中用户和角色之间的映射关系。 什么是RBAC?基于角色的访问控制(RBAC)是施行面向企业安全策略的一种无效的访问控制形式。其根本思维是,对系统操作的各种权限不是间接授予具体的用户,而是在用户汇合与权限汇合之间建设一个角色汇合。每一种角色对应一组相应的权限。一旦用户被调配了适当的角色后,该用户就领有此角色的所有操作权限。这样做的益处是,不用在每次创立用户时都进行调配权限的操作,只有调配用户相应的角色即可,而且角色的权限变更比用户的权限变更要少得多,这样将简化用户的权限治理,缩小零碎的开销。 如何应用Casbin?想要明确如何应用casbin,必须要分明model和policy两个概念,即模型和资源,能够参考官网文档https://casbin.org/zh-CN/ 学习。 springboot集成casbin1.pom.xml文件增加依赖 <!--jcasbin--> <dependency> <groupId>org.casbin</groupId> <artifactId>jcasbin</artifactId> <version>1.4.0</version> </dependency> <!--casbin适配器(上面会概述)--> <dependency> <groupId>org.casbin</groupId> <artifactId>jdbc-adapter</artifactId> <version>2.0.0</version> </dependency>2.定义model模型,这里是应用RBAC+RESTFUL进行模型的定义。[request_definition]r = sub, obj, act[policy_definition]p = sub, obj, act[role_definition]g = _, _[policy_effect]e = some(where (p.eft == allow))[matchers]m = g(r.sub,p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act)3.创立casbin适配器类,将datasource数据源写入casbin的适配器@Slf4j@Configurationpublic class CasbinAdapterConfig { private final DataSource dataSource; @Autowired public CasbinAdapterConfig(DataSource dataSource) { this.dataSource = dataSource; } @Bean public JDBCAdapter adapterConfig() throws Exception { return new JDBCAdapter(dataSource); }}4#.创立一个初始化的配置类,并且继承InitializingBean接口InitializingBean接口为bean提供了初始化办法的形式,它只包含afterPropertiesSet办法,但凡继承该接口的类,在初始化bean的时候都会执行该办法。 ...

May 31, 2021 · 2 min · jiezi

关于shiro:极简入门Shiro的认证与授权流程解析

小Hub领读:接下来的几天,咱们开讲Shiro,从入门到剖析、集成、单点登录整合等几篇。明天咱们先来认识一下Shiro吧~ 其实Shiro框架并不难,我梳理了一下,你只须要学会以下内容根本就足够了: 登陆、受权流程shiro过滤器链整合Springboot、redis做共享会话联合xxl-sso实现单点登录接下来我会分为几篇文章别离去介绍,这篇咱们先来理解一下shiro的一些基础知识,以及登录受权逻辑。 Shiro简介在Web零碎中咱们常常要波及到权限问题,例如不同角色的人登录零碎,他操作的性能、按钮、菜单是各不相同的,这就是所谓的权限。 而构建一个互联网利用,权限校验治理是很重要的安全措施,这其中次要蕴含: 用户认证 - 用户身份辨认,即登录用户受权 - 访问控制明码加密 - 加密敏感数据避免被偷窥会话治理 - 与用户相干的工夫敏感的状态信息Shiro对以上性能都进行了很好的反对,它能够非常容易的开发出足够好的利用。Shiro能够帮忙咱们实现:认证、受权、加密、会话治理、与Web集成、缓存等。而且Shiro的API也是非常简单。 官网源码:https://github.com/apache/shiro 整体构造与重要组件 从上图能够看出,Security Manager是Shiro的外围管理器,认证受权会话缓存等都是在其外部实现,而后会委托给具体的组件来解决,比方认证过程委托给Authenticator,受权委托给Authorizer组件。所以,整顿还是比拟清晰,源代码也容易追踪。 咱们来具体聊聊所有的组件: Subject: 主体,能够看到主体能够是任何能够与利用交互的“用户”; SecurityManager: Shiro的心脏;所有具体的交互都通过SecurityManager进行管制;负责所有Subject、且负责进行认证和受权、及会话、缓存的治理。 Authenticator:认证器,判断用户是否失常登陆Authorizer:受权器,判断用户是否有权限操作资源Realm: 能够有1个或多个Realm,次要提供认证和受权的数据; Session: Shiro提供一个权限的企业级Session解决方案,session的生命周期都在SessionManager中进行治理。 SessionManager: shiro的会话管理器; SessionDAO: 用于会话的CRUD,比方存储到ehcache或者redis中的会话增删改查; CacheManager: 缓存控制器,来治理如用户、角色、权限等的缓存的;因为这些数据基本上很少去扭转,放到缓存中后能够进步拜访的性能 Cryptography: 明码模块,Shiro进步了一些常见的加密组件用于如明码加密/解密的。 官网简略示例官网例子:http://shiro.apache.org/tutorial.html 刚入门Shiro的同学,真的须要去看看这个官网例子,你能够更加深刻理解Shiro的权限校验流程。我还是贴一下代码吧,一些同学比拟懒: shiro.ini# -----------------------------------------------------------------------------# Users and their (optional) assigned roles# username = password, role1, role2, ..., roleN# -----------------------------------------------------------------------------[users]root = secret, adminguest = guest, guestpresidentskroob = 12345, presidentdarkhelmet = ludicrousspeed, darklord, schwartzlonestarr = vespa, goodguy, schwartz# -----------------------------------------------------------------------------# Roles with assigned permissions# roleName = perm1, perm2, ..., permN# -----------------------------------------------------------------------------[roles]admin = *schwartz = lightsaber:*goodguy = winnebago:drive:eagle5下面代码中,root = secret, admin示意,用户名root,明码secret,角色是admin;schwartz = lightsaber:*示意角色schwartz领有权限lightsaber:*。你其实能够把这个文件看成一个Realm,其实就是shiro默认的IniRealm。 ...

March 27, 2021 · 3 min · jiezi

关于shiro:只需要6个步骤springboot集成shiro并完成登录

我的公众号:MarkerHub,Java网站:https://markerhub.com更多精选文章请点击:Java笔记大全.md 小Hub领读:导入jar包,配置yml参数,编写ShiroConfig定义DefaultWebSecurityManager,重写Realm,编写controller,编写页面,零打碎敲。搞定,是个高手~ 下面一篇文章中,咱们曾经晓得了shiro的认证与受权过程,这也是shiro外面最外围罕用的根底性能。当初咱们把shiro集成到咱们的我的项目中,开始搭建一个有认证和权限体系的我的项目,比方用户核心须要登录之后能力拜访等! 1、极简入门,Shiro的认证与受权流程解析 集成Shiro依据官网文档:https://shiro.apache.org/spring-boot.html 第一步:集成导入jar包: <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web-starter</artifactId> <version>1.4.2</version></dependency>有些同学还在用shiro-spring的jar包,然而集成的配置就绝对多一点,所以能够间接应用starter包更加不便。 第二步:写好配置,官网给咱们提供的属性参数,以及一些默认值,如果不合乎咱们的需要,能够自行改变哈。 从配置上就能够看出,shiro的注解性能,rememberMe等性能已近主动集成进来了。所以starter包应用起来还是非常简单的,只须要相熟shiro的流程,从0开发不在话下哈。 application.ymlshiro: web: enabled: true loginUrl: /loginspring: freemarker: suffix: .ftl # 留神新版本后缀是 .ftlh template-loader-path: classpath:/templates/ settings: classic_compatible: true #解决空值下面的配置,我就改了一下登录的url,其余都是应用默认的,作为咱们最简略的测试,置信你们。 第三步:配置shiro的securityManager和自定义realm。因为realm负责咱们的认证与受权,所以是必须的,自定义的realm必须要交给securityManager治理,所以这两个类须要重写。而后还有一些资源的权限阐明,所以个别须要定义ShiroFilterChainDefinition,所以有3个类咱们常写的: AuthorizingRealmDefaultWebSecurityManager shiro的外围管理器ShiroFilterChainDefinition 过滤器链配置@Configurationpublic class ShiroConfig { @Bean AccountRealm accountRealm() { return new AccountRealm(); } @Bean public DefaultWebSecurityManager securityManager(AccountRealm accountRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(accountRealm); return securityManager; } @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); // logged in users with the 'admin' role chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]"); // logged in users with the 'document:read' permission chainDefinition.addPathDefinition("/docs/**", "authc, perms[document:read]"); chainDefinition.addPathDefinition("/login", "anon"); chainDefinition.addPathDefinition("/doLogin", "anon"); // all other paths require a logged in user chainDefinition.addPathDefinition("/**", "authc"); return chainDefinition; }}下面说到ShiroFilterChainDefinition是定义过滤器配置的,啥意思呢,咱们来看看其中一句: ...

March 25, 2021 · 2 min · jiezi

关于shiro:理解这9大内置过滤器才算是精通Shiro

我的公众号:MarkerHub,Java网站:https://markerhub.com更多精选文章请点击:Java笔记大全.md 小Hub领读:权限框架个别都是一堆过滤器、拦截器的组合使用,在shiro中,有多少个内置的过滤器你晓得吗?在哪些场景用那些过滤器,这篇文章心愿你能对shiro有个新的意识! 别忘了,点个 [在看] 反对一下哈~ 前两篇原创shiro相干文章: 1、极简入门,Shiro的认证与受权流程解析 2、只须要6个步骤,springboot集成shiro,并实现登录 咱们都晓得shiro是个认证权限框架,除了登录、退出逻辑咱们须要侵入我的项目代码之外,验证用户是否曾经登录、是否领有权限的代码其实都是过滤器来实现的,能够这么说,shiro其实就是一个过滤器链汇合。 那么明天咱们具体讨论一下shiro底层到底给咱们提供了多少默认的过滤器供咱们应用,又都有什么用呢?带着问题,咱们先去shiro官网看看对于默认过滤器集的阐明。 http://shiro.apache.org/web.h...When running a web-app, Shiro will create some useful default Filter instances and make them available in the [main] section automatically. You can configure them in main as you would any other bean and reference them in your chain definitions.The default Filter instances available automatically are defined by the DefaultFilter enum and the enum’s name field is the name available for configuration. ...

March 24, 2021 · 4 min · jiezi

关于权限控制:权限校验auth框架

背景:门户网站分为个人用户,集体开发者,机构用户,页面不同的操作须要特定的用户能力操作。如api申请,密钥下载只有机构用户才可操作,重置明码须要登录后才可操作。治理端分为系统管理员,开放平台管理员,银行管理员,不同的角色具备不同的权限,权限按资源划分服务间调用也须要进行爱护,如调用发送短信接口,调用发送站内信的接口,不能不加限度地对外裸露。因而须要以接口为粒度进行对立鉴权,在接口处注明须要的权限,需注明申请起源:门户,治理端,服务间调用。如果是门户或治理端,还可标注须要的角色或资源。可校验多个起源。 技术设计:对于门户网站和治理端,用户登录胜利后生成蕴含用户信息(userId)的JWT token,前端保留在vuex中。每次操作申请将token放入front- Authorization和manage- Authorization以供服务端校验。其中front和manage代表源自门户和治理端。服务间调用发送http申请时,在header处增加service- Authorization,值为有效期为30s的JWT token,service代表源自服务间调用。通过注解标记须要校验的接口,并增加所须要的申请起源和资源名称,如果匹配则放行,否则报无权限申请。利用拦截器对申请进行切面操作,如果该办法加@AuthRequest注解则寻找header,若蕴含front- Authorization,manage- Authorization或service- Authorization,则对该token进行JWT校验。其中front和service校验较为简单,间接校验即刻,manage校验token胜利后还需从token中获取userId,通过服务间调用判断该用户是否领有该资源。如果门户和治理端校验胜利,从token中取出userId,role放入attribute,供接口应用。引入该包还为feign调用增加service- Authorization的header 流程图: 阐明:门户网站,治理端和服务间调用通常通过gateway,然而对立校验不在gateway,而在各自服务,起因如下: 更平安,有的申请可能间接通过服务调用,而非gateway,因而须要在服务的接口层面做校验配置更不便权限是一种安全策略,用户只可拜访被受权的资源。因而须要采取策略管制用户的行为。波及到以下几个方面: 用户认证:如何校验用户的合法性并保留用户的登录状态权限校验:如何爱护服务端的接口,用户是否有资格调用接口,包含:从web端发送来的申请,服务间的调用权限治理:如何给用户分配资源,RBAC权限性能在服务从单体转向微服务架构面临如下挑战: 如何保障用户的登录状态。单体中可将登录状态保留至session中,但微服务中利用被分为多个服务,服务应该是无状态的,不能保留用户的登录状态;微服务拆分后,调用起源不仅仅是客户端,还有来自服务间的调用,因而须要全面思考多个起源的调用权限校验性能不能散落在各个服务中,应对立解决前后端拆散,只做数据交互,前端路由/按钮资源化,如何治理资源微服务利用的权限性能应具备特点: 与业务零碎解耦,性能独立,职责繁多保障可用性,当权限服务不可用时,不能扭转业务零碎的行为保障性能,防止因鉴权导致响应工夫减少对已有代码侵入性小,革新不便现有的解决方案: Oauth2:受权框架JWT token:认证协定Security:有些重Shiro:可做权限认证,明码加密等,但不太实用于微服务环境,SecurityManager分布式session:将username,session id作为key存储至分布式存储中,用户拜访微服务时,能够从分布式存储中断定。保障了高可用和可扩大。毛病是存在安全隐患。通过比拟,决定自行研发一套权限校验框架,包含: JWT Token进行用户认证及鉴权RBAC权限调配体系架构图: Token设计一段字符串,用户登陆胜利后服务端生成返回至客户端保留,作为后续已登陆状态的凭证。长处: 每次申请将token放入header中,可防止CSRF本身无状态,可在服务间共享,服务端不保留token仍可校验其合法性。(不必在服务端保留k-v)应具备以下特点: 一个Token就是一些信息的汇合,蕴含如username,phone-number,资源等信息;可作为用户认证的凭据。因为token是被签名的,服务端可对cookie和HTTP Authrorization Header进行Token信息的查看,如果校验非法,可认为该申请是平安的Token有肯定的有效期,保障安全性Token在有效期内无效,无奈通过本身生效,除非通过放入redis辅助校验过期策略:Token过期后应进行续签,而不是跳转到登陆画面,造成蹩脚的用户体验。Token生效工夫过长会存在安全性隐患,过短会造成频繁的refresh token。好的体验应该是在用户无感知的状况下进行token刷新。 服务端保留token状态,用户每次操作均刷新token有效期,可做到一段时间没有操作即登出,但这种计划对内存压力较大,每次操作都要拜访,失去了token可被验证的便捷性refresh token:用户登陆胜利后返回token及refresh token,token过期后通过refresh token续签token,token有效期短而refresh token有效期长,refresh token生效后认为登出。可实现每次登陆保留登录状态肯定工夫。能够防止对内存的频繁读写何时refresh token: 前端建设定时工作每隔肯定工夫通过refresh token获取新token收到响应后,如果响应为token过期,通过refresh token获取新token,再次发送申请,如果refresh token过期,阐明需从新登录

February 28, 2021 · 1 min · jiezi

关于权限控制:React-hooks-hoc-实现权限校验系统按钮页面等权限

前置条件react,这里应用 umiJs脚手架应用redux数据流,这里应用 dvaJS数据流创立页面 「TestPage」,作为例子页面创立按钮组件「MyInput」,作为例子按钮局部代码目录Demo/ node_modules/ dist/ src/ components/ MyInput/ index.js // 公共组件,input HOCAuth/ index.js // 外围权限校验组件 pages/ test/ index.js // 咱们的测试页面 model.js // test页面的状态 home/ index.js // home 页面 model.js // home 页面的状态 models/ global.js // 最顶层的全局公共状态 services/ // api等等 utils/ app.js // 入口函数 router.js // 路由配置 package.json ...等等思路如何校验权限?咱们将须要校验的(按钮或页面等)指标组件,通过一个公共组件包裹(即hoc组件),在这个hoc组件中判断指标组件的权限编码是否存在于权限表里,「若存在」则以后有权限拜访,渲染。「不存在」则返回 null。 那么,咱们首先要贮存一份权限表,供所有组件应用。再为每个组件设置对于的权限编码。 这里咱们对页面的权限编码配置规定为 '数字-数字',如:'1-2'、'1-3'等等。页面级组件应用'-'连贯。按钮级的权限编码为:'1-1_1'、'1-1_2'等等。 按钮级组件应用'_'连贯。如咱们以后 test 页面编码为 '1-1',且该上面也有两个按钮级组件,那么该组件编码别离为 '1-1_1'、'1-1_2'。 例子:const auth = { '1-1': true, '1-1_1': true} // 权限表const testPageAuthKey = '1-1' // test页面的权限编码const inputAuthKey = '1-1_1' // test页面下的input组件权限编码若 auth[authKey] === true 即有权限,渲染对应组件接下来定义状态: ...

February 20, 2021 · 2 min · jiezi

关于权限控制:一文读懂-TKE-及-Kubernetes-访问权限控制

你有理解过Kubernetes的认证受权链路吗?是否对TKE的权限管制CAM策略、服务角色傻傻分不清楚?本文将会向你介绍腾讯云TKE平台侧的访问控制、Kubernetes访问控制链路,以及演示如何将平台侧账号对接到Kubernetes内。当你在应用腾讯云容器服务TKE(Tencent Kubernetes Engine)的时候,如果多人共用一个账号的状况下,是否有遇到以下问题呢? 密钥由多人共享,泄密危险高。无奈限度其他人的拜访权限,其他人误操作易造成平安危险。为了解决以上问题,腾讯云CAM(Cloud Access Management)提供了主账号和子账号的认证体系以及基于角色的权限管制。 而不同的子账号对于TKE平台侧资源的管制粒度比拟粗(cluster实例级别),又会遇到以下问题: 同一个集群由多子账号可拜访,无奈保障集群资源级别、命名空间级别的读写管制。集群的高权限子账户无奈对低权限子账户进行受权治理。为了解决以上两个问题,TKE针对平台侧资源、Kubernetes资源别离进行相应的访问控制治理。 平台侧访问控制首先介绍下什么是平台侧资源,平台侧资源即Cluster资源、CVM资源、CLB资源、VPC资源等腾讯云资源,而拜访的用户次要分为用户和服务角色载体。 用户就是咱们平时登录控制台的主账号、子账号或者协作者账号服务角色是一种定义好带有某些权限的角色,能够将这个角色赋予某个载体,能够是某个其余账户,也能够是腾讯云下一个产品的服务提供者,CAM会默认为产品提供一个预设的载体和默认的角色,例如TKE的默认角色就是TKE_QCSRole,而载体就是ccs.qcloud.com。而这个角色有什么用途呢?举个TKE的例子,比方TKE的service-controller会Watch集群内的Service资源,如果须要创立LoadBalance类型的Service,会通过云API购买并创立CLB资源,而service-controller是TKE平台为用户部署的,去拜访云API须要有身份,这个身份就是ccs.qcloud.com载体,而权限则须要用户给载体授予一个角色,即TKE_QCSRole。只有用户在受权TKE载体之后,TKE才能够通过服务表演的形式代替用户购买CLB。上面我会简略为你介绍如何给用户受权,以及如何给TKE平台授予角色。 定制策略TKE通过接入CAM,对集群的API接口级别进行权限细分,须要您在CAM控制台对子账户进行不同的权限授予。同时TKE也在CAM侧提供了预设的权限,提供您默认抉择,例如: 也能够自定义策略,具体策略定制请参考CAM产品介绍文档 例如领有只读权限的子账户尝试批改集群名称,将会在API接口时校验CAM权限失败 划分用户组能够根据团队的职责划分好用户组,将之前布局好的自定义策略绑定到一个用户组上,来不便的进行权限治理。例如:有新同学入职时可不便的退出指定用户组(如运维组),就能够获取到该用户组的权限,防止了繁琐的权限配置操作。 授予TKE角色权限应用TKE容器服务须要授予TKE平台为您操作CVMCLBVPCCBS等权限,所以首次拜访TKE控制台须要确保批准受权,即创立预设角色TKE_QCSRole,此角色默认授予TKE载体,该载体会通过CAM获取操作您集群的长期密钥,来进行相应的云API操作。 更多更多丰盛的平台侧访问控制用法请拜访CAM产品阐明文档 Kubernetes访问控制介绍完平台侧资源的访问控制,咱们再来看看TKE集群内的资源如何进行权限治理。当不同的子账户都领有拜访同一个TKE Kubernetes集群权限之后,如何保障不同的子账户,对于集群内资源领有不同的角色和权限呢?让咱们首先从社区的Kubernetes拜访链路来剖析整个过程,从而向您介绍TKE是如何实现容器服务子账户对接Kubernetes认证受权体系的。 Overview首先从宏观的角度看下Kubernetes的申请链路是如何进行的。图片来源于k8s社区官网。 能够大略理解到一个申请的链路是顺次通过Authentication(认证,简称Authn)、Authorization(受权,简称Authz)、AdmissionControl(准入管制),从而获取到后端长久化的数据。 从图中能够看到Authn、Authz、AdmissionControl是由多个模块组成的,每个步骤都有多种形式形成的。 在进入认证模块之前会将HTTP的Request进行构建context,而context中就蕴含了用户的RequestInfo,userInfo、Verb、APIGroup、Version、Namespace、Resource、Path等。 带着这些信息,上面咱们来一次看下准入过程中的每个步骤吧。 Kubernetes认证认证的过程的证实user身份的过程。 Kubernetes中有两类用户,一类是ServiceAccount,一类是集群实在的用户。 ServiceAccount账户是由Kubernetes提供API(资源)进行创立和治理的,ServiceAccount能够认为是非凡的Secret资源,可用户集群内资源拜访APIServer的认证所用。通过能够通过mount的形式挂载到Pod内进行应用。 实在的用户通常是从内部发动申请拜访APIServer,由管理员进行治理认证凭证,而Kubernetes自身不治理任何的用户和凭证信息的,即所有的用户都是逻辑上的用户,无奈通过API调用Kubernetes API进行创立实在用户。 Kubernetes认证的形式泛滥,常见的有TLS客户端证书双向认证、BearerToken认证、BasicAuthorization或认证代理(WebHook) 所有的认证形式都是以插件的模式串联在认证链路中,只有有一种认证形式通过,即可通过认证模块,且后续的认证形式不会被执行。 在此处参考一点点Kubernetes APIServer Authentication模块的代码,能够发现,任何的认证形式都是一下Interface的实现形式都是接管http Request申请,而后会返回一个user.Info的构造体,一个bool,以及一个error // Request attempts to extract authentication information from a request and returns// information about the current user and true if successful, false if not successful,// or an error if the request could not be checked.type Request interface { AuthenticateRequest(req *http.Request) (user.Info, bool, error)}user.Info中蕴含了用户的信息,包含UserName、UUID、Group、Extra。 ...

January 21, 2021 · 2 min · jiezi

关于权限控制:菜单权限

介绍菜单权限是依据登陆角色实现返回不同的菜单,使不同角色能看到不同的菜单。 思路及问题思路一、首先要在刚进入路由之前应用vue的路由守卫拦挡,来判断有没有获取过菜单权限。二、前端和后盾磋商好菜单的构造和菜单的名称,先在前端定义一个路由表。三、后盾返回平行结构的数据,前端组装成一个菜单构造,并且如果后盾返回子菜单没有返回父菜单那么该父菜单上面所有的子菜单不应该显示。四、将筛选过后的路由作为首页的子路由增加进去。五、前端编写页面 问题一、如何动静增加子路由?二、点击到子路由之后能失常显示,刷新页面之后空白页三、在曾经注册了的路由表中增加了*匹配,为什么刷新页面的时候间接跳转到404页面四、基于element封装一个无论后盾返回多少层级的菜单 代码git仓库https://github.com/mengyuhang4879/auth-menu.git 1 npm install2 启动serve文件3 npm run servegit创立近程仓库及提交https://blog.csdn.net/liuweix...

January 12, 2021 · 1 min · jiezi

关于权限控制:Redash中文版以PostgreSQL为例设置用户权限

作为一款数据可视化软件,用户更多的是利用Redash中文版来查找剖析数据源,而不须要编辑变更数据内容,在建设数据源时,配置一个带有权限管制的数据库用户,能更好地保障数据安全,防止用户误操作导致失落数据。上面以PostgreSQL数据源为例,演示如何配置只读数据模式。 首先创立一个新数据库命名为business,拥有者为admin,数据库中建设三个表Employees,jobs和customers,并填入数据。数据库管理员能管制公共用户的所有权限,间接吊销公共角色的权限会影响以后所有用户和角色。因而在理论架构中,解决形式个别是在数据库中设置一部分只读权限的角色,同时零碎也保留其余不同权限的角色。 1、建设只读角色 readonly CREATE ROLE readonly;GRANT CONNECT ON DATABASE defaultbusiness TO readonly;GRANT USAGE ON SCHEMA business TO readonly; 在PostgreSQL的操作中,在PostgreSQL的操作中,配置只容许拜访usage模式中蕴含的对象,因而只读模式中查找性能将不受影响。 2、授予新角色权限 GRANT SELECT ON TABLE "business"."employees" TO readonly;GRANT SELECT ON TABLE "business"."jobs" TO readonly;GRANT SELECT (id, name) ON TABLE business.customers TO readonly; 前两条语句是对employees和jobs表赋予齐全读取权限。 第三条语句限度readonly角色仅能查看customers表的ID和姓名,表中的所有其余字段均被暗藏,customers其余信息字段数据只能由管理员查看,这样可确保零碎中其余的用户不会无意地看到该数据。如果用户尝试执行SELECT * FROM business,数据库将引发权限谬误,只有查问ID和名称字段能显示进去。 3、在数据库中创立名为redash_user的只读用户,用于连贯到Redash中文版 CREATE USER redash_user WITH PASSWORD 'secret';GRANT readonly TO redash_user; 增加数据源时设置界面须要填写用户名redash_user,“secret”示意数据库明码,这里能够设置一个较强的明码来替换。 4、应用新的只读用户连贯到Postgres 连贯Redash中文版很简略。只需提供主机名,端口和数据库用户名、明码即可,示例如下。 接下来,咱们能够执行一些查问来查看权限状况: SELECT * FROM business.employees ...

December 31, 2020 · 1 min · jiezi

前端面试必备权限控制

0.前言记得当年面试的时候,面试官问我,前端怎么做权限控制,咱也不太会这个,只能尴尬回答道:“都是老大搭的架子,我只负责写业务模块代码”,????????????。如今自己也做了很多项目了,觉得有必有对前端权限控制做一个总结。 前端权限控制一直是前端必须掌握的一个知识点,一般来说稍微正规一点的后台系统肯定有权限控制。当然还是那句老话,前端本来就是不安全的,真正的安全还是需要后端兄弟去把关,所以后端也必须按做权限控制!我们前端的权限校验主要的目的是过滤不该有的请求和操作,减少服务端压力。 我个人认为前端权限控制应该分为四个方面,接口权限、按钮权限,页面权限,路由权限,下面就分四个部分探讨下权限控制怎么做 1.接口权限原则接口权限最简单,目前一般采用jwt的形式来验证,没有通过的话一般返回401 Authentication Required登录完拿到Token,将token存起来(cookie或者ssessionStorage),每次登录的时候头部携带token就行了(axios请求拦截器实现)。 伪码实现const {token} = login()cookie.set('token',token)axios.interceptors.request.use(config => { config.headers['token'] = cookie.get('token') return config})2.按钮权限原则一个页面会有新增,删除,编辑等等按钮。不同用户应该是有不同操作权限的。我们不妨定义权限码 0:不可见 1:不可编辑 2:可编辑我们提前和后端约定好按钮的名字,后端会返回一个按钮权限列表。然后我们根据权限列表使用v-if指令或者 绑定disabled属性达到相应权限效果。当然更好的最好是自己写一个自定义权限指令,实质就是根据相应权限操作dom 伪码实现比如概览页面的编辑按钮 名字先和后端定义好叫做overview-edit // overviwe.vue overview是概览页面的路由名...<button v-auth='edit'>...//util.js 全局注册自定义指令Vue.directive('auth', { inserted: function (el, binding, vnode) { const optName = binding.arg const authName = `${routeName}-${optName}` //这里根据路由名和操作类型拼出按钮名 overview-edit const btnAuthList = store.state.auth.btnAuthList if (btnAuthList[authName]===0) { // 按钮权限为0则移除dom el.parentNode.removeChild(el) } else if (btnAuthList[authName]===1) { // 按钮权限为1则禁用俺就 vnode.componentInstance.disabled = true } }})// 登录的时候接受按钮权限并存在vuex里面const {btnAuthList} = login()vuex.state.btnAuthList = btnAuthList3.页面权限(菜单权限)个人任务页面权限实际上就是菜单权限,如果我们有去某个页面的导航菜单,那我是不是也就相应的没有去那个页面的权限了,所以说页面权限的实际就是菜单权限。 ...

November 2, 2019 · 1 min · jiezi

Spring-security五完美权限管理系统授权过程分析

1. 权限管理相关概念 权限管理是一个几乎所有后台系统的都会涉及的一个重要组成部分,主要目的是对整个后台管理系统进行权限的控制。常见的基于角色的访问控制,其授权模型为“用户-角色-权限”,简明的说,一个用户拥有多个角色,一个角色拥有多个权限。其中, 用户: 不用多讲,大家也知道了;角色: 一个集合的概念,角色管理是确定角色具备哪些权限的一个过程 ;权限:1).页面权限,控制你可以看到哪个页面,看不到哪个页面; 2). 操作权限,控制你可以在页面上进行哪些操作(查询、删除、编辑等); 3).数据权限,是控制你可以看到哪些数据。 实质是: 权限(Permission) = 资源(Resource) + 操作(Privilege) 角色(Role) = 权限的集合(a set of low-level permissions) 用户(User) = 角色的集合(high-level roles) 权限管理过程: 鉴权管理,即权限判断逻辑,如菜单管理(普通业务人员登录系统后,是看不到【用户管理】菜单的)、功能权限管理(URL访问的管理)、行级权限管理等授权管理,即权限分配过程,如直接对用户授权,直接分配到用户的权限具有最优先级别、对用户所属岗位授权,用户所属岗位信息可以看作是一个分组,和角色的作用一样,但是每个用户只能关联一个岗位信息等。 在实际项目中用户数量多,逐一的为每个系统用户授权,这是极其繁琐的事,所以可以学习linux文件管理系统一样,设置group模式,一组有多个用户,可以为用户组授权相同的权限,简便多了。这样模式下: 每个用户的所有权限=用户个人的权限+用户组所用的权限 用户组、用户、与角色三者关系如下: 再结合权限管理的页面权限、操作权限,如菜单的访问、功能模块的操作、按钮的操作等等,可把功能操作与资源统一管理,即让它们直接与权限关联起来,关系图如下: 2. 授权过程分析### 2.1 授权访问权限工作流程: FilterSecurityInterceptor doFilter()->invoke() ->AbstractSecurityInterceptor beforeInvocation() ->SecurityMetadataSource 获取ConfigAttribute属性信息(从数据库或者其他数据源地方) getAttributes() ->AccessDecisionManager() 基于AccessDecisionVoter实现授权访问 Decide() ->AccessDecisionVoter 受AccessDecisionManager委托实现授权访问 vote()默认授权过程会使用这样的工作流程,接下来来分析各个组件的功能与源码。 ### 2.2 AbstractSecurityInterceptor分析 FilterSecurityInterceptor为授权拦截器, 在FilterSecurityInterceptor中有一个封装了过滤链、request以及response的FilterInvocation对象进行操作,在FilterSecurityInterceptor,主要由invoke()调用其父类AbstractSecurityInterceptor的方法。 invoke()分析: public void invoke(FilterInvocation fi) throws IOException, ServletException { ..... // 获取accessDecisionManager权限决策后结果状态、以及权限属性 InterceptorStatusToken token = super.beforeInvocation(fi); try { fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { super.finallyInvocation(token); } super.afterInvocation(token, null); }} AbstractSecurityInterceptor 的授权过滤器主要方法beforeInvocation(),afterInvocation()以及authenticateIfRequired(),其最主要的方法beforeInvocation() 分析如下: ...

October 14, 2019 · 4 min · jiezi

基于Vue实现后台系统权限控制

需求分析基础需求项目的基础需求是: 系统管理员拥有最大权限,管理所有企业;企业管理员拥有该企业所有权限,可下放权限给子账户;子账户拥有限制权限,且可被随时更改。根据权限列表展示隐藏相对应菜单栏、按钮等。 我们在登录后,将获取到的用户权限保存到本地缓存中,以便每次方便获取权限,判断权限。 但由于“子账户拥有限制权限,且可被随时更改”这条需求,我们的项目变得稍稍棘手一点: 权限变少:当用户点击到原本有权限但修改后没有权限的相关请求,后端会给出相对应的状态码供前端判断,此时前端可以根据状态码做出相对应的反馈。权限变多:每个请求都是通的,后端无法反馈,前端也无从得知权限什么时候变多了。我们要求用户退出重新登录,获取最新的权限树。进阶需求然而,我们的用户特别懒,产品也特别惯着他们,他们要求——“界面刷新,就获取最新的权限列表”。 看来原来的计划得改了,获取到的用户权限保存到vuex的状态管理器store中,刷新的时候,重新异步获取一次权限,再判断权限。 路由结构根据项目需求,路由结构如下: routes: [ { path: '/login', component: Login, name: 'login' }, { path: '/enterprise', component: Enterprise, name: 'Enterprise', children: getRouter(routerConfig) }, { path: '*', redirect: {name: 'login'} ]项目是多页面项目,在同一个域名下访问,系统管理员登录后以/admin为前缀,企业账户登录后以/enterprise为前缀,企业系统做权限控制,只列出企业系统部分路由大纲。 流程构思从输入地址到页面展示,权限控制流程构思如下: 逻辑实现为了将路由与权限控制分离,我将权限管理单独抽出来一个类。 因此核心逻辑大致可以分为: 状态管理部分:处理权限树、存储权限权限管理类:判断是否登录、判断是否有权限权限指令:控制页面的展示状态管理部分从后端获取的权限树格式大致长这样: { "data": [ { "title": "A模块", "name": "module_A", "children": [ { "title": "A模块-1", "name": "module_A_1", "children": [ { "title": "A模块-1-新增", "name": "A_1_add", "children": [] }, { "title": "A模块-1-编辑", "name": "A_1_edit", "children": [] } ] } ] }, { "title": "B模块", "name": "module_B", "children": [ { "title": "B模块-删除", "name": "B_del", "children": [] } ] }]}我们需要将权限树扁平化为以下形式,方便判断。这个列表存储为store中的 permissions,后期的判断权限都以它为依据。 ...

July 8, 2019 · 3 min · jiezi

手摸手带你用vue实现后台管理权限系统及顶栏三级菜单显示

手摸手,带你用vue实现后台管理权限系统及顶栏三级菜单显示 效果演示地址项目demo展示 重要功能总结权限功能的实现权限路由思路:根据用户登录的roles信息与路由中配置的roles信息进行比较过滤,生成可以访问的路由表,并通过router.addRoutes(store.getters.addRouters)动态添加可访问权限路由表,从而实现左侧和顶栏菜单的展示。 实现步骤: 1.在router/index.js中,给相应的菜单设置默认的roles信息; 如下:给"权限设置"菜单设置的权限为:meta:{roles: ['admin', 'editor']},及不同的角色都可以看到; 给其子菜单"页面权限",设置权限为:meta:{roles: ['admin']},及表示只有"admin"可以看到该菜单; 给其子菜单"按钮权限"设置权限为:meta:{roles: ['editor']},及表示只有"editor"可以看到该菜单。 2.通过router.beforeEach()和router.afterEach()进行路由过滤和权限拦截; 代码如下: // permission judge functionfunction hasPermission(roles, permissionRoles) { if (roles.indexOf('admin') >= 0) return true // admin permission passed directly if (!permissionRoles) return true return roles.some(role => permissionRoles.indexOf(role) >= 0)}const whiteList = ['/login'] // 不重定向白名单router.beforeEach((to, from, next) => { NProgress.start() // 设置浏览器头部标题 const browserHeaderTitle = to.meta.title store.commit('SET_BROWSERHEADERTITLE', { browserHeaderTitle: browserHeaderTitle }) // 点击登录时,拿到了token并存入了vuex; if (getToken()) { /* has token*/ if (store.getters.isLock && to.path !== '/lock') { next({ path: '/lock' }) NProgress.done() } else if (to.path === '/login') { next({ path: '/' }) // 会匹配到path:'',后面的path:'*'还没有生成; NProgress.done() } else { if (store.getters.roles.length === 0) { store.dispatch('GetInfo').then(res => { // 拉取用户信息 const roles = res.roles store.dispatch('GenerateRoutes', { roles }).then(() => { // 根据roles权限生成可访问的路由表 router.addRoutes(store.getters.addRouters) // 动态添加可访问权限路由表 next({ ...to, replace: true }) // hack方法 确保addRoutes已完成 }) }).catch((err) => { store.dispatch('FedLogOut').then(() => { Message.error(err || 'Verification failed, please login again') next({ path: '/' }) }) }) } else { // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓ if (hasPermission(store.getters.roles, to.meta.roles)) { next()// } else { next({ path: '/401', replace: true, query: { noGoBack: true }}) } } } } else { if (whiteList.indexOf(to.path) !== -1) { next() } else { // 点击退出时,会定位到这里 next('/login') NProgress.done() } }})router.afterEach(() => { NProgress.done() // 结束Progress setTimeout(() => { const browserHeaderTitle = store.getters.browserHeaderTitle setTitle(browserHeaderTitle) }, 0)})用户点击登录之后的业务逻辑分析: ...

June 19, 2019 · 3 min · jiezi

上帝的归上帝,凯撒的归凯撒—— CODING 权限管理更新

上帝的归上帝,凯撒的归凯撒《马太福音》22 章 15-22 节,耶稣用这句话,说明了神权与政权之间的正确关系,奠定了神权与政权的基础,也划清了二者的界限。其实这两个问题如今也依旧出现在公司架构中,随着数字化转型的浪潮,越来越多的企业开始使用信息化管理系统取代传统办公。在转型过程中,最大的挑战之一就是如何给相应信息设置权限,确保不同职能部门的员工只能使用特定功能,浏览与自身业务相关的信息,不能擅自查看或修改超越权限的内容,保障企业数字资产的准确性、保密性、安全性。CODING 研发管理系统作为一个高效的研发流程与管理平台,在上线了“测试管理”、“缺陷管理”、“持续集成”等重要功能后,在既有的权限管理基础上增加了企业级权限管理,以及根据研发团队各角色职能界定的项目级权限管理,通过更精细的权限划分协助企业研发团队更有序地进行软件开发。企业级权限管理企业级权限管理功能可按照系统角色和自定义用户组来管理成员权限。企业所有者和管理员可根据实际协作和管理场景,将具体的权限项分配给系统角色和自定义用户组,为企业量身打造最高效最适合的权限管理体系。权限设置给系统角色分配的默认对应权限,可由企业所有者/管理员进行修改。成员权限为其在各个用户组的权限之和(例如:某企业成员既是管理员也是某自定义用户组成员,则该成员权限为管理员权限加上自定义用户组权限之和)。企业所有者/管理员修改系统角色/自定义用户组权限后,被修改权限的成员刷新页面即可生效新权限。功能说明系统角色系统角色分为企业所有者、管理员、普通成员三类,且系统角色不支持删除。企业所有者企业所有者默认拥有企业所有权限,当前企业所有者可在【企业设置】中转让企业,变更所有者。可在【企业管理】->【权限管理】中看到企业所有者所拥有的权限。企业所有者可编辑企业管理员、企业普通成员、自定义用户组的权限。企业管理员企业管理员默认拥有除【转让企业】和【设置管理员】外的所有权限,支持企业所有者对其默认权限进行编辑。企业所有者可在【成员管理】中设置企业管理员。可在【企业管理】->【权限管理】中看到企业管理员所拥有的权限。企业管理员可编辑企业管理员、企业普通成员、自定义用户组的权限。企业普通成员企业普通成员默认拥有【个人设置】选项中 “创建项目、导入项目、访问令牌、应用授权“ 等权限。企业所有者/管理员可将企业各项权限分配给普通成员,并支持对其权限进行编辑。自定义用户组当企业成员架构比较复杂,部门内成员涉及不同模块时,可由企业所有者/管理员创建自定义用户组给不同成员分配不同的权限。在【权限管理】页面点击【添加分组】,输入用户组名称后即可完成创建。点击右侧【添加成员】按钮,选择指定成员进行添加。在权限列表中勾选该用户组成员的对应权限并保存,该用户组成员在刷新页面后即可生效新权限。项目内权限管理项目内权限管理支持自定义配置用户组和权限,项目管理员可根据团队实际情况进行灵活配置。权限设置原项目的“管理员”、“普通成员”、“受限成员”分别对应现“项目管理员”、“开发”、“测试”用户组,相关权限与原有一致,不影响项目成员在项目的权限操作。创建项目的用户默认为【管理员组】,【管理员】用户组为系统默认用户组,不可编辑和删除。【项目经理】、【产品】、【开发】、【测试】、【运维】为预设自定义用户组,管理员可进行编辑和删除。权限展示管理员权限列表(该权限不可编辑):开发默认权限列表,对应原普通成员权限:测试默认权限,对应原受限成员权限:项目经理默认权限:产品默认权限:运维默认权限:分组设置(自定义权限分组)点击添加分组,输入名称按 Enter 键即可完成添加,分组可添加对应成员,权限可自定义。随着全新的权限管理功能上线,CODING 研发管理系统将通过更精细的权限划分协助企业研发团队更有序更高效地进行软件开发。点击立即体验 CODING 研发管理系统敏捷开发,解放效能,提升产品质量!

April 9, 2019 · 1 min · jiezi

前端权限控制

欢迎关注我的公众号睿Talk,获取我最新的文章:一、前言在成熟的电商系统中,权限管理是不可或缺的一个环节。灵活的权限管理有助于管理员对不同的人员分配不同的权限,在满足业务需要的同时保证敏感数据只对有权限的人开放。笔者最近对系统的权限管理做了一次改造,在此分享一些经验以供参考。二、权限管理基础权限管理一版分以下 3 个基础概念:功能点角色用户它们之间的关系一句话就能说清楚:一个用户可以拥有多个角色,而一个角色可以包含多个功能。比如一个员工可以既有收银员的角色,也可以有库管员的角色。对于收银员这个角色,可以有开单收银、查看订单、查看会员信息等功能点。此外还有 2 个概念:功能权限数据权限它们之间的关系举例来说明:想象一个连锁店的场景,某个门店的管理员具有查看营收的功能权限,和查看自己门店数据的数据权限;高级管理员同样拥有查看营收的功能权限,和查看所有门店数据的数据权限。三、前端权限控制下面我们聚焦到前端领域,聊聊前端应该怎么做权限设计。前端本质上只有 2 种权限:页面权限和组件权限。为了更好理解,我将菜单权限从组件权限中拆出来,形成了以下 3 类的权限:每一个权限最终都会落到权限点上。权限点可以理解为一个编码,有这个权限点就说明有对应的功能权限。权限点的编码要注意 2 点:全局唯一尽量短小(减少带宽消耗,因为一个用户可能会有很多权限点)需要控制权限的地方,都要定义一个权限点,然后告诉后端。一个用户所有的权限点会以数组的形式返回。判断是否有权限就是从数组中匹配一个元素。下面以 React 为例,聊聊具体的实现方式。对于页面的权限判断,可以在 React Router 的 onEnter 回调中判断:// 编码映射,下面的 getUrlCodeByName 会用到export default { order_list: ‘zaq0’, // 订单列表 order_detail: ‘xsw1’, // 订单详情 order_refund_list: ‘cde2’, // 订单退款列表 order_refund_detail: ‘vfr3’, // 订单退款详情 order_deduct_modify: ‘bgt4’, // 订单修改业绩};function canAccessUrl(urlName) { const moduleCode = getUrlCodeByName(urlName); // 权限点一般是一个没意义的编码,为了更易于理解,前端做了一个编码映射 return accesses.u.indexOf(moduleCode) > -1; // accesses.u 数组是后端返回的所有 url 权限点}function routerOnEnterCheck(urlName) { return function routerOnEnter(nextState, replace) { if (!canAccessUrl(urlName)) { replace(’/unauthorized’); } };}…{ path: ’list’, getComponent: loadAsync(() => import(/* webpackChunkName: “order” / ‘../../order/List’)), onEnter: routerOnEnterCheck(‘order_list’),}…对于菜单和组件的权限判断,大体上长这样:// 用以缓存是否有权限访问组件const componentAccessCache = {};/* * 检查访问组件的权限 * 一个组件可能会重复 render 多次,而组件权限的数量可能会超多(上百个),因此将权限缓存起来以提高性能 */function canAccessComponent(module, componentName) { if (!module || !componentName) { console.error(canAccessComponent ${module} ${componentName} 缺参数); } const key = ${module}.${componentName}; let result = componentAccessCache[key]; if (result !== undefined) { return result; } const moduleCode = getComponentCodeByModuleAndName(module, componentName); // 权限点一般是一个没意义的编码,为了更易于理解,前端做了一个编码映射 result = accesses.c.indexOf(moduleCode) > -1; // accesses.c 数组是后端返回的所有组件权限点 componentAccessCache[key] = result; return result;}class SomeComponent extends PureComponent { … render() { return ( … { canAccessComponent(‘asset’, ‘buy_pay’) && <Button type=“primary” className=“btn-buy” onClick={() => (buy(num))} > 立即订购 </Button> } … ) }}权限点的获取笔者放在了 node 端,通过全局变量的形式注入到页面中,保证呈现的页面是由权限点过滤过的。此外接口返回对权限点是一个一维数组,为了加快前端检索速度,在 node 端根据编码规则将权限点分为 3 类(菜单/页面/组件),具体细节就不细说了。四、总结本文介绍了权限管理的基础知识,还结合 React 讲解了前端权限控制的一些细节。技术方案比较简单,真正麻烦的是每一个权限点的定义及录入,以及对现有系统的改造。改造过程中可以分模块进行迭代,毕竟罗马不是一天就能建成。 ...

April 3, 2019 · 1 min · jiezi

odoo访问权限 (二. 记录规则)

记录规则通过记录规则可以灵活地设置权限。规则保存在ir.rule模型表里,需要设置关联某个模型,关联很多组,访问权限控制和domian。通过domain_force过滤出的一些记录来执行约束。例子:经理只能删除状态为’cancel’的客户线索。注意向many2many字段添加值的写法。<record id=“delete_cancelled_only” model=“ir.rule”> <field name=“name”>Only cancelled leads may be deleted</field> <field name=“model_id” ref=“crm.model_crm_lead”/> <field name=“groups” eval="[(4, ref(‘base.group_sale_manager’))]"/> <field name=“perm_read” eval=“0”/> <field name=“perm_write” eval=“0”/> <field name=“perm_create” eval=“0”/> <field name=“perm_unlink” eval=“1” /> <field name=“domain_force”>[(‘state’,’=’,‘cancel’)]</field></record>例子:只有经理可以编辑课程,如果没有经理,任何人都可以编辑security.xml<record id=“group_manager” model=“res.groups”><field name=“name”>todufiledu / 管理员</field></record><record id=“only_responsible_can_modify” model=“ir.rule”><field name=“name”>只有经理可以编辑</field><field name=“model_id” ref=“model_todo_file”/><field name=“groups” eval="[(4, ref(’todufiledu.group_manager’))]"/><field name=“perm_read” eval=“0”/><field name=“perm_write” eval=“1”/><field name=“perm_create” eval=“0”/><field name=“perm_unlink” eval=“1”/><field name=“domain_force”> [’|’, (‘responsible_id’,’=’,False), (‘responsible_id’,’=’,user.id)]</field></record>odoo设置员工能看自己新建的记录规则 经理能看所有记录的规则增加2个组组1 能看全部记录组2 增加只能看自己的记录增加一个经理能看所有记录的规则关联模型 res.partner规则填入 [(1,’=’,1)]组加入 全部记录组增加一个员工能看自己记录的规则关联模型 res.partner规则 [’|’,(‘user_id’,’=’,user.id),(‘id’,’=’,user.partner_id.id)]组加入 只能看自己记录组

March 14, 2019 · 1 min · jiezi

Odoo访问权限(一)

Odoo访问权限一四个ODOO权限管理层次一. Odoo 菜单级别: 即,不属于指定菜单所包含组的用户看不到该菜单。不安全,只是隐藏菜单,若用户知道菜单ID,仍然可以通过指定URL访问二. Odoo 对象级别: 即,对某个对象是否有‘创建,读取,修改,删除“的权限。OE中的对象可以简单理解为表对象,比如“客户”,“产品”,“销售订单”等都是对象三. Odoo 记录级别: 即,对对象表中的数据的访问权限。比如同样访问“客户”对象,业务员只能对自己创建的客户有访问的权限,而经理可以访问其所辖的业务员的所有“客户”对象,这里的访问也可以进一步明细到“创建,读取,修改,删除”的权限四. 字段级别: 即,一个对象或表上的某些字段的访问权限。比如产品的成本字段只有经理有读权限,比如订单上的单价字段只有经理才有修改的权限等。本章节介绍一二层次的权限在security文件夹下新建两个文件夹model_security.xmlir.model.access.csv用户组实例<?xml version=“1.0” encoding=“utf-8”?><odoo> <data noupdate=“0”> <record model=“ir.module.category” id=“module_category_activity”> <field name=“name”> 活动管理 </field> </record> <record model=“res.groups” id=“group_activity_user”> <field name=“name”> 用户 </field> <field name=“category_id” ref=“module_category_activity”/> </record> <record model=“res.groups” id=“group_activity_manager”> <field name=“name”> 管理 </field> <field name=“implied_ids” eval="[(4, ref(‘group_activity_user’))]"/> <field name=“category_id” ref=“module_category_activity”/> </record> </data></odoo>权限分配实例id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlinkaccess_activity_event_user,读权限,model_activity_event,group_activity_user,1,0,0,0access_activity_event_system_user,管理权限,model_activity_event,group_activity_manager,1,1,1,1access_activity_type_user,分类读权限,model_activity_type,group_activity_user,1,0,0,0access_activity_type_system_user,分类管理权限,model_activity_type,group_activity_manager,1,1,1,1id: 可以自定义,不能重复name: 自定义就可以model_id:id: model_模型名称。注意,这里要把“.”全部换成“_”,否则会报错。perm_read:读权限。有权限写‘1’,没权限写‘0’perm_write: 编辑权限。有权限写‘1’,没权限写‘0’perm_create: 创建权限。有权限写‘1’,没权限写‘0’perm_unlink: 删除权限。有权限写‘1’,没权限写‘0’重点注意要在__manifest__.py文件中引入以上新建的两个文件always loaded’data’: [‘security/activity_security.xml’,‘security/ir.model.access.csv’,‘views/views.xml’,‘views/templates.xml’,‘views/menus.xml’,‘data/activity_data.xml’,],最后安装或升级项目模块就可以试试效果了

March 14, 2019 · 1 min · jiezi

企业管理系统前后端分离架构设计 系列一 权限模型篇

前段时间分别用vue和react写了两个后台管理系统的模板vue-quasar-admin和3YAdmin。两个项目中都实现了基于RBAC的权限控制。因为本职工作是后端开发,比较清楚权限控制一个管理系统应该必须具备的核心功能,而且是可以做到通用的。打算写写关于管理系统前后端分离方面的文章,也是做一个知识的总结,其中会涉及到vue,react,node,.net core等方面的知识。术语描述用户(Subject):发起操作的主体对象(Object):指操作所针对的客体对象,比如文章或评论权限(Permission):用来指代对某种对象的某一种操作,例如“添加文章的操作”权限码:权限的代号,例如用“ARTICLE_ADD”来指代“添加文章的操作”权限权限有时候也可以称为动作或者功能。比如“添加文章”,既可以认为它是一个动作,也可以认为它是一个功能。对象也可以称为资源。常用的权限模型ACL(Access Control List)(访问控制列表)DAC(Discretionary Access Control)(自主访问控制)MAC(Mandatory Access Control)(强制访问控制)RBAC(Role-Based Access Control)(基于角色的访问控制)ABAC(Attribute-Based Access Control)(基于属性的访问控制)ACL(Access Control List)(访问控制列表)ACL是最早也是最基本的一种访问控制机制,它是用来描述用户和权限之间关系的数据列表。它的原理非常简单:每一项资源,都配有一个列表,这个列表记录的就是哪些用户可以对这项资源执行CRUD等操作。当试图访问这项资源时,会首先检查这个列表中是否有关于当前用户的访问权限,从而确定当前用户可否执行相应的操作。例如一个文件对象的 ACL 为 Alice: read,write; Bob: read,这代表 Alice 对该文件既能读又能写,而 Bob 只能读取。由于ACL的简单性,使得它几乎不需要任何基础设施就可以完成访问控制。但同时它的缺点也是很明显的,由于需要维护大量的访问权限列表,ACL在性能上有明显的缺陷。另外,对于拥有大量用户与众多资源的应用,管理访问控制列表本身就变成非常繁重的工作。最开始的ACL定义中,用户直接和权限挂钩,数据存储的是用户与权限的关联关系。如果两个用户的权限是一样的,那么就需要分别存储这两个用户与权限的关联关系,也是上面所提到的ACL的缺陷。为了解决这些问题,便有了对ACL设计的改进,相同权限的用户放到同一个分组里,分组与权限挂钩,不再是用户直接与权限挂钩。以及后来出现的RBAC(基于角色的访问控制),角色与分组也是差不多的概念,角色直接与权限挂钩,用户再与角色进行关联。所以,现在一般说ACL,不再是用户直接和权限挂钩的一种权限控制模型,把它看做一个单纯的访问控制列表即可。列表里维护的可能是用户与权限的关系,也可以是用户组与权限的关系,也可以是角色与权限的关系,甚至是部门,职位等等于权限的关系。ACL是权限体系中的业务规则。RBAC等权限模型要用到ACL才能工作,ACL服务于RBAC等权限模型,其它权限控制体系里的权限规则也叫ACL。DAC(Discretionary Access Control)(自主访问控制)系统会识别用户,然后根据被操作对象(Subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户的是否能对其进行哪些操作,例如读取或修改。而拥有对象权限的用户,又可以将该对象的权限分配给其他用户,所以称之为“自主(Discretionary)”控制。因为用户能自主地将自己拥有的权限授予其他用户,所以DAC模型可以任意传递权限,用户能间接获得本不具有的访问权限,因此DAC模型的安全性较低,不能给系统充分的数据保护。DAC可以直接使用ACL的物理模型,区别在于,DAC模型中用户可以将自己具备的权限分配给其它用户(程序里的操作就是根据用户ID筛选出权限列表,根据列表为要分配权限的用户构造出新的权限列表并保存)DAC是传统的UNIX访问控制模型,也是Windows文件系统的访问控制模型。Windows的文件访问权限的设置中,除了用户,还有组。这个组与后面要说到的RABC模型的角色有什么区别呢?https://stackoverflow.com/questions/7770728/group-vs-role-any-real-difference我认为没必要去划分的太清楚,不管是组还是角色,都是为了更好的管理和分配权限在最原始的ACL模型上做的改进。如果有需要,甚至可以把权限分配到部门,职位上。MAC(Mandatory Access Control)(强制访问控制)MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每一个对象都有一些权限标识,每个用户同样也会有一些权限标识,而用户能否对该对象进行操作取决于双方的权限标识的关系,这个限制判断通常是由系统硬性限制的。访问时,系统先对用户的访问许可级别和资源对象的密级进行比较,再决定用户是否可以访问资源对象。用户不能改变自身和资源对象的安全级别,只有系统管理员或管理程序才能 控制资源对象和用户的级别。比如在影视作品中我们经常能看到特工在查询机密文件时,屏幕提示需要“无法访问,需要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具有。MAC非常适合机密机构或者其他等级观念强烈的行业,但对于类似商业服务系统,则因为不够灵活而不能适用。MAC可以继续使用DAC的模型,但是要对用户进行等级划分,比如一级,二级,三级。。。,对对象资源也要做划分,比如机密,秘密和最高机密。用户访问的资源的时候,根据用户等级与资源访问级别来做判断,比如一级用户只能访问机密文件,如果访问的是最高机密文件,系统就会拒绝。这一系列规则是优先于DAC的,如果MAC与DAC混用,要先校验MAC再校验DAC。RBAC(Role-Based Access Control)(基于角色的访问控制)ACL的访问控制机制中,直接维护的是用户与功能的关系,这一系列的关系就是一个权限列表。当很多的用户具有相同功能权限的时候,就要进行繁琐的关联操作。RBAC就是在用户与权限之间引入了角色的概念。用户与角色之间做关联,权限列表维护的是角色与功能的关系。RBAC是目前使用最普遍的权限控制模型。当某些用户具备相同的权限的时候,只需要为这些用户建一个角色,把相应的功能关联到这个角色上,生成角色的权限列表。当有新的用户需要相同权限的时候,把用户关联到这个角色上即可。而当用检查或校验用户的操作权限的时候,查询用户所属角色的权限列表即可。当然,RBAC也不是完美的,比如想要为某个用户单独设置某个功能权限,可能需要为这个功能权限单独创建一个角色,然后把特定的用户关联到这个角色上。当想要移除某个用户的特定功能权限的时候,可能需要重新设置角色的功能权限,把特定功能权限从当前角色中移除,建立新的角色并关联特定的功能权限,然后再把新角色与相关的用户做关联(也可以直接在特定功能的程序里校验操作用户)这里说一个比较常见的RBAC的错误的用法:那就是直接使用角色做权限判断。比如只有角色A才能做文章的删除操作。function delPost(postId){ if(!isRole(‘A’)){ return false; }}如果需求该为角色B也可以删除文章。那就必须修改代码function delPost(postId){ if(!isRole(‘A’)&&!isRole(‘B’)){ return false; }}正确的做法应该是添加"删除文章"这个功能,把这个功能关联到相应的角色上。判断的时候是根据功能去判断而不是角色。function delPost(postId){ if(!hasPermission(‘POST_DEL’)){ return false; }}针对“只有角色A才能做文章的删除操作”这一需求,把这个删除功能关联到角色A上,然后把需要这个操作权限的用户加入到角色A中即可。当别的角色也需要这个操作权限,把功能关联到对应角色上即可,不需要再修改代码。在RBAC的核心基础上,还可以做相应的扩展,比如角色继承,角色分组之类的,这些扩展都是为了在一定程度简化权限管理工作。ABAC(Attribute-Based Access Control)(基于属性的权限控制)RBAC虽然是目前最普遍的权限控制模型。但是某些情况下,RBAC是无法满足并且也实现不了的。比如业务员1和业务员2都属于业务员角色,都有查看客户订单的权限。当有一个需求,要求业务员1只能查看北京地区的客户的订单,业务员2只能查看上海的客户的订单。这单单使用RBAC是无法实现。借助RBAC,可行的做法是,分地区创建角色,然后程序中根据角色做数据的过滤,这种做法缺点之前也提到过,需求变更的时候可能需要每次都修改代码。上面业务员查看订单的例子,地区是订单的一个属性,需求就是针对这个地区属性来做订单的查询范围的权限控制。这种权限控制方式就是ABAC(Attribute-Based Access Control)(基于属性的权限控制),也被一些人称为是权限系统设计的未来。不同于常见的将用户通过某种方式关联到权限的方式,ABAC则是通过动态计算一个或一组属性是否满足某种条件来进行授权判断的(可以编写简单的逻辑)。属性通常来说分为四类:用户属性(如用户年龄),环境属性(如当前时间),操作属性(如读取)和对象属性(如一篇文章,又称资源属性),所以理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求。例如规则:“允许所有班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操作属性,而“校门”就是对象属性了。ABAC非常的灵活,但是实现也是非常的难。这其中涉及到逻辑的动态执行,数据动态过滤等,更加具体就是动态拼接SQL语句(使用ORM的话就是动态组装对应ORM的查询语句)。感兴趣的可以在Github上搜索ABAC,看看不同语言是否已经有现成的解决方案。下面说说我学习到的一种实现方式:还是业务员查看订单的例子,在RBAC的基础上,扩展一个实体规则,订单就是实体,也就是针对订单设置一系列的规则。规则存储格式可以是json也可以是xml,甚至是Sql语句,能解析即可。比如北京地区这个规则:{ “regionId”:1}上海地区:{ “regionId”:3}regionId 就是系统里对应区域的Id,也是订单或订单相关表的某个字段。保存这个规则的时候,规则内容(就是上面的json),规则实体(也就是订单,表明这个规则是针对订单的)是必须的。也可以加上这个规则是适用增删改查中的一种或多种。创建好实体的规则,将规则与角色做关联,也就是将北京地区的规则关联到北京地区角色上,上海地区的规则关联到上海地区角色上。后端做权限校验的时候,还是先按RBAC模型的控制方式进行校验(是否具备订单查看权限),然后根据当前操作对象(也就是实体),取出用户所属角色关联的对应实体的规则。然后解析规则,动态拼接Sql或者ORM语句。没做地区限制(或没配置规则)的时候,Sql可能是select userId,orderNo,createdDate from T_Order配置了规则,解析拼接后可能就是select userId,orderNo,createdDate from T_Order where regionId=1这里是针对地区这个属性实现了动态的权限控制。实际开发过程中,要控制的东西是非常多了,查看字段的控制,数据范围的控制。要满足这些复杂的控制,需要制定一套完整的规则,以及针对规则编写相应的解析程序。比如根据配置的规则,最后解析出来可能是各种Sql语句:<,>,=,like,in,not in等等。可以看出,要真正的落地实现ABAC是多么的复杂。每次都要解析规则,对程序的性能也造成的影响,就算使用缓存,命中的概率也是非常的小,因为很多因素都是动态的。所以,如果需要根据属性做权限判断的场景不是很多的话,还是建议使用RBAC,然后程序中做判断比较省事省力。总结ACL早期定义中是一种权限控制机制,这种机制直接维护的是用户与功能的关系,功能就是针对对象定义的一些操作,比如增删改查的等。用户与功能的关系列表也称为权限列表或访问控制列表,现在说ACL,一般就是指这个权限列表或访问控制列表,但是里面维护的关系不一定是用户与功能的关系,在RBAC中维护的就是角色与功能的关系。RBAC在ACL的基础上加入了角色的概念,权限列表或访问控制列表里维护的不再是用户与功能的关系,而是角色与功能的关系。ACL可以和RBAC混着用,既可以在角色上设置权限,也可以直接给用户设置权限,更加灵活。借助角色的思想,可以在用户组,组织,职位等等上设置权限,以便更好的做好权限管理,也就是将权限设置从单一个体转移到某一类组合上。ABAC非常的灵活,也非常的难实现。参考文章权限系统设计模型分析Authorization Models: ACL, DAC, MAC, RBAC, ABAC ...

October 23, 2018 · 1 min · jiezi