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

MongoDBSpring-Data-MongoDB详细的操作手册增删改查

github:https://github.com/Ccww-lx/Sp... 模块:spring-boot-base-mongodb 在NoSQL盛行的时代,App很大可能会涉及到MongoDB数据库的使用,而也必须学会在Spring boot使用Spring Data连接MongoDB进行数据增删改查操作,如下为详细的操作手册。 1. 依赖直接导入spring-data-mongodb包或者使用Spring Boot starter <dependencies> <!-- other dependency elements omitted --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>2.2.0.RELEASE</version> </dependency></dependencies><!--spring 框架使用最新的 --><spring.framework.version>5.2.0.RELEASE</spring.framework.version><!--用一即可--><!--使用Spring Boot starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId></dependency>2. 属性文件application.properties#mongodb连接地址,集群用“;”隔开spring.mongo.mongoDatabaseAddress=10.110.112.165:27092;10.110.112.166:27092#mongo数据名spring.mongo.dbname=mongodb#mongo用户spring.mongo.username=mongodbopr#mongo密码spring.mongo.password=123456#mongo最大连接数spring.mongo.connectionsPerHost=503. mongodb 配置注册Mongo实例配置: @Configurationpublic class MongodbConfig { public static final String COMMA = ";"; public static final String COLON = ":"; @Value("${spring.mongo.mongoDatabaseAddress}") private String mongoDatabaseAddress; @Value("${spring.mongo.username}") private String username; @Value("${spring.mongo.dbname}") private String dbname; @Value("${spring.mongo.password}") private String password; @Value("${spring.mongo.connectionsPerHost}") private String connectionsPerHost; /** * 获取mongodb的地址 * * @return */ private List<ServerAddress> getMongoDbAddress() { List<ServerAddress> serverAddrList = new ArrayList<ServerAddress>(); //如果有多个服务器的话 if (this.mongoDatabaseAddress.indexOf(COMMA) > 0) { String[] addressArrays = mongoDatabaseAddress.split(COMMA); String[] hostPort; for (String address : addressArrays) { hostPort = address.split(COLON); ServerAddress serverAdress = new ServerAddress(hostPort[0], Integer.valueOf(hostPort[1])); serverAddrList.add(serverAdress); } } else { String[] hostPort = mongoDatabaseAddress.split(COLON); ServerAddress serverAdress = new ServerAddress(hostPort[0], Integer.valueOf(hostPort[1])); serverAddrList.add(serverAdress); } return serverAddrList; } /** * 设置连接参数 */ private MongoClientOptions getMongoClientOptions() { MongoClientOptions.Builder builder = MongoClientOptions.builder(); // todo 添加其他参数配置 //最大连接数 builder.connectionsPerHost(Integer.valueOf(connectionsPerHost)); MongoClientOptions options = builder.readPreference(ReadPreference.nearest()).build(); return options; } /** * * @return */ @Bean public MongoClient mongoClient() { //使用数据库名、用户名密码登录 MongoCredential credential = MongoCredential.createCredential(username, dbname, password.toCharArray()); //创建Mongo客户端 return new MongoClient(getMongoDbAddress(), credential, getMongoClientOptions()); } /** * 注册mongodb操作类 * @param mongoClient * @return */ @Bean @ConditionalOnClass(MongoClient.class) public MongoTemplate mongoTemplate(MongoClient mongoClient) { MongoTemplate mongoTemplate = new MongoTemplate(new SimpleMongoDbFactory(mongoClient, dbname)); return mongoTemplate; }}4. mongodb操作使用MongoTemplate类进行增删改查 ...

October 9, 2019 · 3 min · jiezi

Vue实战评价组件的设计与实现6

在上篇文章我们将项目头部模块进行了编写与数据渲染。 本篇文章我们进一步深入项目设计评价组件。 分析页面 如图所示,点菜,评价,商家,为导航,我们点击评价的时候,直接跳转评价页面。 评价页面由商家评分一栏,评论列表构成,评论列表支持:全部,有图,点评三种筛选。 综上我们现在开始设计评论组件: 建立组件文件夹 1.css图片的存放 针对组件引用的图片可能产生变动性,我们将组件内的图片放入组件文件夹内,进行引用。使得组件更加便于维护。 2.路径配置 build/webpack.base.conf.js内: alias: { 'vue$': 'vue/dist/vue.esm.js',//自动补全设置 '@': resolve('src'), 'components': resolve('./src/components')}通过alias重命名设置对组件导入模块时进行了重命名。 实际在导入需要的组件写法: // 举个例子,导入Ratings组价可以写成 import Ratings from 'components/Ratings/Ratings'图片存放,路径配置完成以后我们建立Ratings文件夹并进入: 根据分析页面结构整理以后所以我们先把页面结构搭建出来: 在Ratings.vue中: //设置容器存放评论组件<template> <div class="ratings" ref='ratingView'> <div class="ratings-wrapper"> //细化我们组件 </div> </div></template>现在我们设计商家评分,口味,包装,等结构如下图: <div class="overview"> <div class="overview-left"> <div class="comment-score"> <p class="score">{{ratings.comment_score}}</p> <p class="text">商家评分</p> </div> <div class="other-score"> <div class="quality-score item"> <span class="text">口味</span> <Star :score='ratings.quality_score' class='star'></Star> <span class="score">{{ratings.quality_score}}</span> </div> <div class="pack-score item"> <span class="text">包装</span> <Star :score='ratings.pack_score' class='star'></Star> <span class="score">{{ratings.pack_score}}</span> </div> </div> </div> <div class="overview-right"> <div class="delivery-score"> <p class="score">{{ratings.delivery_score}}</p> <p class="text">配送评分</p> </div> </div></div>实现评论中选项卡(全部,有图,点评),列表页面: ...

June 20, 2019 · 3 min · jiezi

Vue实战头部模块编写5

通过上篇我们了解到了vue可以通过axios发送前端请求。 我们知道的在发送请求可以在creted()钩子内,也可以在mounted()钩子内。 本篇我们通过头部模块的编写,将请求到的数据渲染到模块内。 当然我们先要准备静态页面: 01.分析制作静态页面 如图所示,我们可以将整个一个头部模块分为4个部分: · 顶部通栏:返回,搜索,拼单,等; · 主题内容:餐厅名字 · 公告:新用户; · 背景图片。 然后我们依据当前这三块内容进行布局 <div class="header"><div class="top-wrapper"></div><div class="content-wrapper"></div><div class="bulletin-wrapper"></div><div class="bg-wrapper"></div></div>结构定好了,我们需要注意: 1.写css,添加背景图片,等通用的需要我们放在static下,比如初始化css文件。 2.头部组件需要用到的图片直接放在头部组件的文件夹内,如以后需要更改,操作,是很方便管理的。 3.bg-wrapper用绝对定位进行背景图片的设置。 我们将静态头部模块完成后需要为组件传入数据,比如商家信息,公告,主题内容,通过后端获取。 如下,我们在app.vue中进行数据请求 <script>// 1、导入头部模块import Myheader from 'components/Header/Header';export default {name: 'app',components: { // 2、注册Myheader},data() {return {// header组件需要的信息(商家信息)poiInfo: {},               commentNum: 0,               }},created() { // 发起异步请求,获取数据var that = this;// 通过axios发起get请求this.$axios.get('/api/goods').then(function(response) { // 获取到数据var dataSource = response.data;if(dataSource.code == 0){that.poiInfo = dataSource.data.poi_info;}}).catch(function(error) { // 出错处理console.log(error);});}}</script>我们通过axios请求到了来自后端的商家信息。 ...

June 18, 2019 · 1 min · jiezi

Vue实战项目数据交互axios4

1.axios地址 https://github.com/axios/axios 2.安装 npm install axios3.使用 1.用在哪? main.js 全局2.什么时候用? 生命周期:https://cn.vuejs.org/v2/guide/instance.html created 的时候 发起异步请求获取数据3.怎么用 数据从哪里来: 1.美团API接口 , 优点:贴近工作情形缺点:官方接口申请有门槛,手续繁琐,限制多,速度慢,非官方不稳定,容易失效2.自己搭建线上服务器数据 优点:贴近工作情形,自己造数据想怎玩怎么玩缺点:写JSON麻烦,不稳定,速度慢,域名空间收费,繁琐3.搭建本地模拟数据 优点:贴近工作情形,自己造数据想怎玩怎么玩,访问速度快,稳定缺点:写JSON、配置服务器麻烦(如使用express或者mockjs)结论:为了工作使用1,为了灵活性使用3,自己有现成的服务器或空间,从2、3中选的话,选择2 我们使用1,按照工作标准来: 美团外卖官方接口: http://developer.waimai.meitu... GET例子: axios.get('/user?ID=12345') .then(function (response) { // handle success console.log(response); }) .catch(function (error) { // handle error console.log(error); }) .then(function () { // always executed });POST例子: axios.post('/user', { firstName: 'Fred', lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });总 结 本文我们从安装,到axios,让我们对vue的数据相关的技术点有了一定了解,我们将一步步完善项目,丰富我们的技术经验。 ...

June 17, 2019 · 1 min · jiezi

Vue实战路由轻松设置vuerouter3

上篇我们说了vue项目的目录设计,本篇我们来学习一下vue路由。 路由的作用: 在web端路由(route)就是URL到函数的映射,vue的router就像一个容器,分配,处理每一个route到URL中。 文档地址: vue路由官方文档https://router.vuejs.org/zh/guide/#html安装: 通过node.js安装;npm install vue-router 但是一般情况下在node中安装vue项目的时候根据提示选择安装vue-router;如何使用路由: 举个项目例子: 1.添加路由链接,打开Nav.vue <router-link to="/goods" class="nav-item">点菜</router-link> <router-link to="/rates" class="nav-item">评价</router-link> <router-link to="/seller" class="nav-item">商家</router-link>to是路由指向的地址。 2.决定将组建渲染在哪,打开App.vue,添加: <router-view/>3.配置路由,打开router文件夹下index.js import Vue from 'vue'import Router from 'vue-router'//1.引入各个组件import Goods from '@/components/Goods/Goods'import Rates from '@/components/Rates/Rates'import Seller from '@/components/Seller/Seller'Vue.use(Router)//2.配置路由 路径->组件export default new Router({ routes: [ { path: '/', redirect:'/goods' }, { path: '/goods', component: Goods }, { path: '/rates', component: Rates }, { path: '/seller', component: Seller } ], linkActiveClass:'active'})redirect路由重定向: 我们在router数组设定redirect为“/goods”。那么只要路径是/。页面会跳转到"/goods"页面。 ...

June 16, 2019 · 1 min · jiezi