序: 
本文使用springboot+mybatis+SpringSecurity 实现数据库动态的管理用户、角色、权限管理

本文细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义滤器,代替原有的FilterSecurityInterceptor过滤器, 
并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。

spring security的简单原理:

使用众多的拦截器对url拦截,以此来管理权限。但是这么多拦截器,笔者不可能对其一一来讲,主要讲里面核心流程的两个。

首先,权限管理离不开登陆验证的,所以登陆验证拦截器AuthenticationProcessingFilter要讲; 
还有就是对访问的资源管理吧,所以资源管理拦截器AbstractSecurityInterceptor要讲;

但拦截器里面的实现需要一些组件来实现,所以就有了AuthenticationManager、accessDecisionManager等组件来支撑。

现在先大概过一遍整个流程,用户登陆,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。 
访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。


重要

本文设计和代码是基于 上一篇博客(请点击)

springboot+mybatis+SpringSecurity 实现用户角色数据库管理

进行修改。


本文目录: 
1:数据库表设计 
2:权限表的业务 
3:springSecurity 配置修改 
4:修改home.html 文件 
5:修改HomeController.Java 文件 
6:测试检验

目录结构如下:


1:数据库表设计

由于本文增加了权限表所以本文的数据库表为5个分别是: 用户表、角色表、权限表、用户角色中间表、角色权限中间表

初始化数据

    注意:Sys_permission 表的url通配符为两颗星,比如说 /user下的所有url,应该写成 /user/**;权限的名字可以随意起名
insert into SYS_USER (id,username, password) values (1,'admin', 'admin');
insert into SYS_USER (id,username, password) values (2,'abel', 'abel');insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
insert into SYS_ROLE(id,name) values(2,'ROLE_USER');insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(1,1);
insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(2,2);BEGIN;
INSERT INTO `Sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null), ('2', 'ROLE_ADMIN', 'ABel', '/admin', null);
COMMIT;BEGIN;
INSERT INTO `Sys_permission_role` VALUES ('1', '1', '1'), ('2', '1', '2'), ('3', '2', '1');
COMMIT;

2:权限表的业务代码

2.1 java bean

2.2 dao 层

在 com.us.example.dao 包下新建PermissionDao.java 文件。

PermissionDao.java

package com.us.example.dao;
import com.us.example.config.MyBatisRepository;
import com.us.example.domain.Permission;
import java.util.List;/*** Created by yangyibo on 17/1/20.*/
public interface PermissionDao {public List<Permission> findAll();public List<Permission> findByAdminUserId(int userId);
}

在src/resource/mapper目录下新建对应的mapper.xml 文件

PermissionDaoMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.us.example.dao.PermissionDao">
<select id="findAll"  resultType="com.us.example.domain.Permission">SELECT * from Sys_permission ;
</select><select id="findByAdminUserId" parameterType="int" resultType="com.us.example.domain.Permission">select p.*from Sys_User uLEFT JOIN sys_role_user sru on u.id= sru.Sys_User_idLEFT JOIN Sys_Role r on sru.Sys_Role_id=r.idLEFT JOIN Sys_permission_role spr on spr.role_id=r.idLEFT JOIN Sys_permission p on p.id =spr.permission_idwhere u.id=#{userId}</select></mapper>

3:springSecurity 配置修改

3.1 修改 WebSecurityConfig.java

修改com.us.example.config包下的 WebSecurityConfig.java 文件如下:

package com.us.example.config;import com.us.example.service.CustomUserService;
import com.us.example.service.MyFilterSecurityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;/*** Created by yangyibo on 17/1/18.*/@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate MyFilterSecurityInterceptor myFilterSecurityInterceptor;@BeanUserDetailsService customUserService(){ //注册UserDetailsService 的beanreturn new CustomUserService();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserService()); //user Details Service验证}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated() //任何请求,登录后可以访问.and().formLogin().loginPage("/login").failureUrl("/login?error").permitAll() //登录页面用户任意访问.and().logout().permitAll(); //注销行为任意访问http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);}
}

3.2 修改CustomUserService

修改CustomUserService.java 内容如下:

package com.us.example.service;import com.us.example.dao.PermissionDao;
import com.us.example.dao.UserDao;
import com.us.example.domain.Permission;
import com.us.example.domain.SysRole;
import com.us.example.domain.SysUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;import java.util.ArrayList;
import java.util.List;/*** Created by yangyibo on 17/1/18.*/
@Service
public class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口@AutowiredUserDao userDao;@AutowiredPermissionDao permissionDao;public UserDetails loadUserByUsername(String username) {SysUser user = userDao.findByUserName(username);if (user != null) {List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());List<GrantedAuthority> grantedAuthorities = new ArrayList <>();for (Permission permission : permissions) {if (permission != null && permission.getName()!=null) {GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());//1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。grantedAuthorities.add(grantedAuthority);}}return new User(user.getUsername(), user.getPassword(), grantedAuthorities);} else {throw new UsernameNotFoundException("admin: " + username + " do not exist!");}}}

3.3 新增MyAccessDecisionManager

在com.us.example.service 包下新增 
MyAccessDecisionManager.java 文件

package com.us.example.service;import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;import java.util.Collection;
import java.util.Iterator;/*** Created by yangyibo on 17/1/19.*/
@Service
public class MyAccessDecisionManager implements AccessDecisionManager {// decide 方法是判定是否拥有权限的决策方法,//authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.//object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();//configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。@Overridepublic void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {if(null== configAttributes || configAttributes.size() <=0) {return;}ConfigAttribute c;String needRole;for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {c = iter.next();needRole = c.getAttribute();for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合if(needRole.trim().equals(ga.getAuthority())) {return;}}}throw new AccessDeniedException("no right");}@Overridepublic boolean supports(ConfigAttribute attribute) {return true;}@Overridepublic boolean supports(Class<?> clazz) {return true;}
}

3.4 新增 MyFilterSecurityInterceptor

在com.us.example.service 包下新增 
MyFilterSecurityInterceptor.java 文件

package com.us.example.service;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;import java.io.IOException;/*** Created by yangyibo on 17/1/19.*/
@Service
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {@Autowiredprivate FilterInvocationSecurityMetadataSource securityMetadataSource;@Autowiredpublic void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {super.setAccessDecisionManager(myAccessDecisionManager);}@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}public void invoke(FilterInvocation fi) throws IOException, ServletException {
//fi里面有一个被拦截的url
//里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够InterceptorStatusToken token = super.beforeInvocation(fi);try {
//执行下一个拦截器fi.getChain().doFilter(fi.getRequest(), fi.getResponse());} finally {super.afterInvocation(token, null);}}@Overridepublic void destroy() {}@Overridepublic Class<?> getSecureObjectClass() {return FilterInvocation.class;}@Overridepublic SecurityMetadataSource obtainSecurityMetadataSource() {return this.securityMetadataSource;}
}

3.5 新增 MyInvocationSecurityMetadataSourceService

在com.us.example.service 包下新增MyInvocationSecurityMetadataSourceService.java文件

package com.us.example.service;import com.us.example.dao.PermissionDao;
import com.us.example.domain.Permission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Service;import javax.servlet.http.HttpServletRequest;
import java.util.*;/*** Created by yangyibo on 17/1/19.*/
@Service
public class MyInvocationSecurityMetadataSourceService  implementsFilterInvocationSecurityMetadataSource {@Autowiredprivate PermissionDao permissionDao;private HashMap<String, Collection<ConfigAttribute>> map =null;/*** 加载权限表中所有权限*/public void loadResourceDefine(){map = new HashMap<>();Collection<ConfigAttribute> array;ConfigAttribute cfg;List<Permission> permissions = permissionDao.findAll();for(Permission permission : permissions) {array = new ArrayList<>();cfg = new SecurityConfig(permission.getName());//此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。array.add(cfg);//用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,map.put(permission.getUrl(), array);}}//此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。@Overridepublic Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {if(map ==null) loadResourceDefine();//object 中包含用户请求的request 信息HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();AntPathRequestMatcher matcher;String resUrl;for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {resUrl = iter.next();matcher = new AntPathRequestMatcher(resUrl);if(matcher.matches(request)) {return map.get(resUrl);}}return null;}@Overridepublic Collection<ConfigAttribute> getAllConfigAttributes() {return null;}@Overridepublic boolean supports(Class<?> clazz) {return true;}
}

4:修改home.html 文件

修改src/resources/templates目录下 的home.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta content="text/html;charset=UTF-8"/>
<title sec:authentication="name"></title>
<link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
<style type="text/css">
body {padding-top: 50px;
}
.starter-template {padding: 40px 15px;text-align: center;
}
</style>
</head>
<body><nav class="navbar navbar-inverse navbar-fixed-top"><div class="container"><div class="navbar-header"><a class="navbar-brand" href="#">Spring Security演示</a></div><div id="navbar" class="collapse navbar-collapse"><ul class="nav navbar-nav"><li><a th:href="@{/}"> 首页 </a></li><li><a th:href="@{/admin}"> admin </a></li></ul></div><!--/.nav-collapse --></div></nav><div class="container"><div class="starter-template"><h1 th:text="${msg.title}"></h1><p class="bg-primary" th:text="${msg.content}"></p><div sec:authorize="hasRole('ROLE_HOME')"> <!-- 用户类型为ROLE_ADMIN 显示 --><p class="bg-info" th:text="${msg.etraInfo}"></p></div><div sec:authorize="hasRole('ROLE_ADMIN')"> <!-- 用户类型为ROLE_ADMIN 显示 --><p class="bg-info">恭喜您,您有 ROLE_ADMIN 权限 </p></div><form th:action="@{/logout}" method="post"><input type="submit" class="btn btn-primary" value="注销"/></form></div></div></body>
</html>

5:修改HomeController.java 文件

package com.us.example.controller;import com.us.example.domain.Msg;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;/*** Created by yangyibo on 17/1/18.*/
@Controller
public class HomeController {@RequestMapping("/")public String index(Model model){Msg msg =  new Msg("测试标题","测试内容","欢迎来到HOME页面,您拥有 ROLE_HOME 权限");model.addAttribute("msg", msg);return "home";}@RequestMapping("/admin")@ResponseBodypublic String hello(){return "hello admin";}
}

6.测试检验

启动访问 http://localhost:8080/ 到登录页面

由于数据库的配置 admin 用户拥有 访问 home和admin 页面的权限。
abel 用户只有访问 home 的权限

使用admin 登录

点击 admin 按钮 会反回结果 “hello admin“

使用abel 用户登录 点击 点击 admin 按钮 页面会报403

源码地址:https://github.com/527515025/springBoot

参考资料: 
http://www.tuicool.com/articles/jq6fuur#c-23220 
http://blog.csdn.net/u012367513/article/details/38866465

springBoot+springSecurity 数据库动态管理用户、角色、权限(二)相关推荐

  1. springboot整合shiro,mybatis-plus实现用户角色,权限管控.(完整demo)

    资源下载链接:https://download.csdn.net/download/dayonglove2018/13960978 shiro是轻量级的权限管控框架.很早前就接触过.不过一直没有实现了 ...

  2. SpringSecurity动态加载用户角色权限实现登录及鉴权

    本文来说下SpringSecurity如何动态加载用户角色权限实现登录及鉴权 文章目录 概述 动态数据登录验证的基础知识 UserDetails与UserDetailsService接口 实现User ...

  3. oracle数据库赋权_Oracle角色权限创建用户赋权

    1.权限&用户 角色权限: Sysdba:可以改变字符集.创建删除数据库.登录之后用户是SYS(可以启动和关闭数据库) Sysoper:不可改变字符集.不能创.删数据库.登陆之后用户是PUBL ...

  4. 后台用户角色权限管理设计

    目录 1.概述 2.设计 2.1 用户管理 2.2 角色管理 2.3 权限管理 2.4 用户.角色.权限的关系 3.总结 1.概述 在设计产品后台系统设置时,可根据不同项目的实际需求来设计后台系统设置 ...

  5. Mysql —— C语言链接mysql数据库,用户 角色 权限(用户根据角色的不同拥有增删改查的权限、用户有三种认证方式)

    db_修改过(用户 角色 权限): 1.新增用户时候id 改为最大id值加一,之前用的select查看出来的记录数加一,删除后再增加会出错: 2.删除用户时候,若该用户创建过其他用户(不能改此用户名. ...

  6. Jenkins中安装Role-based Authorization Strategy插件来实现用户角色权限管理

    场景 CentOS中Jenkins的下载.安装.配置与启动(图文教程): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/11649 ...

  7. java用户角色权限管理 只显示姓_扩展RBAC用户角色权限设计方案

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...

  8. 数据库实验8 数据库安全性(用户与权限管理)实验

    实验8 数据库安全性(用户与权限管理)实验 8.1实验目的及要求 加深对数据库安全性的理解 8.2实验内容 数据库用户与权限管理 8.3实验步骤 8.3.1创建新用户 1.创建新用户: Mysql&g ...

  9. RBAC用户角色权限管理

    RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...

最新文章

  1. 简单的聊聊自动化测试:Selenium的高级操作
  2. Maven中使用tomcat:run 出现错误 org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException...
  3. 惠普打印信息页无法连接到服务器,惠普M400系列打印机网络连接无法打印怎么办?...
  4. 五个数字从小到大排序java,五个数冒泡排序 用c语言数组定义5个数使用冒泡排序 从小到大...
  5. 生成跨语言的类型声明和接口绑定的工具(Djinni )
  6. vue-cli3项目通过vue如何引入第三方js包完成登陆功能
  7. 以后出去找工作,只能说自己是产品策划了
  8. Java 11:String类中的新方法
  9. [题解](树形dp/换根)小x游世界树
  10. Mule ESB File Connector轮询单个文件的实现(3)
  11. endnotex7怎么导入中文文献_EndNote导入CNKI文献的方法 | 科研动力
  12. 软件测试工程师工作总结
  13. 计算机管理模块无法初始化单元,win7组策略提示MMC无法初始化管理单元怎么办...
  14. thinkpadt410接口介绍_独家:ThinkPad T410与T400之细节对比
  15. python特征相关性热力图怎么画_百度热力图,带您探索城市的奥妙!
  16. 《测绘综合能力》真题易错本
  17. dos攻击与ddos攻击的区别
  18. Python文件读取
  19. xmmi - 晨星半导体公司MSTAR平台
  20. 5红5绿6蓝穿手链c语言,礼仪习题库(含答案)

热门文章

  1. DASH直播平台的搭建
  2. linux send与recv函数详解
  3. VC基于MSCOMM控件串口通讯
  4. 机器学习入门笔记:(4.3)SMO算法
  5. python创建实例时显示没有参数-OSError无法创建文件无效参数
  6. minifilter
  7. 一文读懂 Spring Boot、微服务架构和大数据治理三者之间的故事
  8. EF Core中关于System.Linq.Dynamic.Core的使用(转载)
  9. vue自定义指令截取图片中心显示
  10. 3YAdmin-专注通用权限控制与表单的后台管理系统模板