本博客基于上一个 http://www.cnblogs.com/wenbronk/p/7379865.html

增加了角色的权限表, 可以进行权限校验

一, 数据准备

1, 数据表建立

/*
Navicat MySQL Data Transfer
Source Server         : 本地
Source Host           : localhost:3306
Source Database       : test
Target Server Type    : MYSQL
Date: 2017-8-14 22:17:33
*/SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (`id` INT (32) NOT NULL AUTO_INCREMENT COMMENT '主键id',`username` varchar(32) DEFAULT NULL COMMENT '用户名',`password` varchar(32) DEFAULT NULL COMMENT '密码',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (`id` INT (32) NOT NULL AUTO_INCREMENT COMMENT '主键id',`name` varchar(32) DEFAULT NULL COMMENT '用户名',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for `sys_permission`
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (`id` INT (32) NOT NULL AUTO_INCREMENT COMMENT '主键id',`name` varchar(32) DEFAULT NULL COMMENT '用户名',`desc` VARCHAR (32) DEFAULT NULL COMMENT '描述',`url` VARCHAR (32) DEFAULT NULL COMMENT 'url',`pid` INT (32),PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;-- ----------------------------
-- Table structure for `sys_role_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',`sys_user_id` INT(32) NOT NULL COMMENT 'user_id',`sys_role_id` INT(32) NOT NULL COMMENT 'role_id',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;ALTER TABLE sys_role_user ADD CONSTRAINT sys_FK1 FOREIGN KEY(sys_user_id) REFERENCES sys_user(id);
ALTER TABLE sys_role_user ADD CONSTRAINT role_FK2 FOREIGN KEY(sys_role_id) REFERENCES sys_role(id);-- ----------------------------
-- Table structure for `sys_permission_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission_role`;
CREATE TABLE `sys_permission_role` (`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键id',`sys_role_id` INT(32) NOT NULL COMMENT 'role_id',`sys_permission_id` INT(32) NOT NULL COMMENT 'permission_id',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;
ALTER TABLE sys_permission_role ADD CONSTRAINT sys_FK3 FOREIGN KEY(sys_role_id) REFERENCES sys_role(id);
ALTER TABLE sys_permission_role ADD CONSTRAINT role_FK4 FOREIGN KEY(sys_permission_id) REFERENCES sys_permission(id);

2, 导入数据

insert into SYS_USER (id,username, password) values (1,'vini', '123');
insert into SYS_USER (id,username, password) values (2,'bronk', '123');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,sys_role_id) values(1,1);
insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_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;

3, mybatis实体, 其余2个和上一篇博客一样

SysPermission.groovy

package com.wenbronk.security.entity/*** Created by wenbronk on 2017/8/17.*/
class SysPermission {int idString nameString descString urlint pid
}

4, application.yml配置服务启动导入

和上个一样

二, security部分

东西比较多, 按流程来,

1, WebSecurityConfig.groovy 添加

http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)

最终代码为:

package com.wenbronk.security.security.configimport com.wenbronk.security.security.interceptor.MyFilterSecurityInterceptor
import com.wenbronk.security.security.service.CustomUserService
import org.springframework.beans.factory.annotation.Autowired
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.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.web.access.intercept.FilterSecurityInterceptorimport javax.inject.Inject
/*** Created by wenbronk on 2017/8/15.*/
@Configuration
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {@InjectCustomUserService customUserService;@AutowiredMyFilterSecurityInterceptor myFilterSecurityInterceptor@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserService);}@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)}
}

2, 请求会被拦截器拦截, MyFilterSecurityInterceptor,

package com.wenbronk.security.security.interceptorimport com.wenbronk.security.security.config.MyAccessDecisonManager
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.Componentimport javax.inject.Inject
import javax.servlet.*/*** Created by wenbronk on 2017/8/17.*/
@Component
class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {@InjectFilterInvocationSecurityMetadataSource securityMetadataSource@Autowiredpublic void setMyAccessDecisionManager(MyAccessDecisonManager myAccessDecisonManager) {super.setAccessDecisionManager(myAccessDecisonManager)}@Overridevoid init(FilterConfig filterConfig) throws ServletException {}/*** fi中有一个被拦截的url* 里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够*/@Overridevoid doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation(request, response, chain)invoke(fi)}void invoke(FilterInvocation filterInvocation) {InterceptorStatusToken token = super.beforeInvocation(filterInvocation)try {filterInvocation.getChain().doFilter(filterInvocation.getRequest(), filterInvocation.getResponse())} finally {super.afterInvocation(token, null)}}@Overridevoid destroy() {}@OverrideClass<?> getSecureObjectClass() {return FilterInvocation.class}@OverrideSecurityMetadataSource obtainSecurityMetadataSource() {return this.securityMetadataSource}
}

3, 拦截器会调用 MyInvocationSecurityMetaDataSource的 getAttribute方法 获取 filter的权限, 并且滴哦啊用 MyAccessDecisionManager的 decide 方法来校验是否拥有权限

MyInvocationSecurityMetadataSource.groovy

package com.wenbronk.security.security.serviceimport com.wenbronk.security.entity.SysPermission
import com.wenbronk.security.mapper.SysPermissionMapper
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.Serviceimport javax.inject.Inject
import javax.servlet.http.HttpServletRequest/*** Created by wenbronk on 2017/8/17.*/
@Service
class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource{@InjectSysPermissionMapper sysPermissionMapper/*** 此方法是为了判定用户请求的url 是否在权限表中,* 如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。*/@OverrideCollection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException {Map<String, Collection<ConfigAttribute>> map = loadResourceDefine()HttpServletRequest request = ((FilterInvocation) o).getHttpRequest()map.each {entry ->AntPathRequestMatcher matcher = new AntPathRequestMatcher(entry.getKey())if (matcher.matches(request)) {// 匹配, 返回给decide方法return entry.getValue()}}return null}/*** 加载权限表中所有的权限*/public Map<String, Collection<ConfigAttribute>> loadResourceDefine() {Map<String, Collection<ConfigAttribute>> map = new HashMap<>()List<SysPermission> permissions = sysPermissionMapper.findAll()permissions.each {permission ->List<ConfigAttribute> array = new ArrayList<>()// 此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。// 此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。ConfigAttribute cfg = new SecurityConfig(permission.getName())array.add(cfg)// 用权限的url作为key, 权限的名称集合为value
            map.put(permission.getUrl(), array);}return null}@OverrideCollection<ConfigAttribute> getAllConfigAttributes() {return null}@Overrideboolean supports(Class<?> aClass) {return true}
}

4, MyInvocationSecurityMetadataSource 查询数据库中url和所需权限的关系, 返回给 MyAccessDecisionManger

MyAccessDecisionManger.groovy

package com.wenbronk.security.security.configimport 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.stereotype.Service/*** Created by wenbronk on 2017/8/17.*/
@Service
class MyAccessDecisonManager implements AccessDecisionManager {/*** 判断是否拥有权限的决策方法* authentication 是CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.* object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();* configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,*/@Overridevoid decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {if (null == configAttributes || configAttributes.size() <=0 )returnconfigAttributes.each {configAttribute ->String needRole = configAttribute.getAttribute()authentication.getAuthorities().each {authority ->if (needRole.trim().equals(authority.getAuthority()))return}}throw new java.nio.file.AccessDeniedException('no right')}@Overrideboolean supports(ConfigAttribute configAttribute) {return true}@Overrideboolean supports(Class<?> aClass) {return true}
}

decide进行是否有权限的决策, 正常则返回, 没有就抛出异常

5, 最终在 customuserService进行权限和用户的装配, 准备返回给前端

package com.wenbronk.security.security.serviceimport com.wenbronk.security.entity.SysPermission
import com.wenbronk.security.entity.SysUser
import com.wenbronk.security.mapper.SysPermissionMapper
import com.wenbronk.security.mapper.SysUserMapper
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.Serviceimport javax.inject.Inject
/*** Created by wenbronk on 2017/8/15.*/
@Service
class CustomUserService implements UserDetailsService {@InjectSysUserMapper sysUserMapper@InjectSysPermissionMapper sysPermissionMapper@OverrideUserDetails loadUserByUsername(String s) throws UsernameNotFoundException {def sysUser = sysUserMapper.findByUserName(s) as SysUserif (sysUser != null) {List<SysPermission> permissions = sysPermissionMapper.findByAdminUserId(sysUser.getId())List<GrantedAuthority> grantedAuthorities = new ArrayList<>()permissions.each {permission ->if (permission != null && permission.getName() != null) {GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName())// 此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
                    grantedAuthorities.add(grantedAuthority)}}return new User(sysUser.getUsername(), sysUser.getPassword(), grantedAuthorities)}else {throw new UsernameNotFoundException('admin: ' + s + ' do not exits')}}
}

三: 页面部分

1, 页面转向config, 和上一篇的一样

@Configuration
class WebMvcConfig extends WebMvcConfigurerAdapter{@Overridevoid addViewControllers(ViewControllerRegistry registry) {registry.addViewController("/login").setViewName("login")
//        registry.addViewController("/home").setViewName("home")
    }
}

2, 更改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_USER 显示 --><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>

四, 密码进行加密

注意, 如果使用, 存储进数据库的密码也必须是同一个算法计算的密文

md5, 工具类

package com.wenbronk.security.toolsimport java.security.MessageDigest/*** Created by wenbronk on 2017/8/17.*/
class MD5Utils {private static final String SALT = "tamboo";public static String encode(String password) {password = password + SALT;MessageDigest md5 = null;try {md5 = MessageDigest.getInstance("MD5");} catch (Exception e) {throw new RuntimeException(e);}char[] charArray = password.toCharArray();byte[] byteArray = new byte[charArray.length];for (int i = 0; i < charArray.length; i++)byteArray[i] = (byte) charArray[i];byte[] md5Bytes = md5.digest(byteArray);StringBuffer hexValue = new StringBuffer();for (int i = 0; i < md5Bytes.length; i++) {int val = ((int) md5Bytes[i]) & 0xff;if (val < 16) {hexValue.append("0");}hexValue.append(Integer.toHexString(val));}return hexValue.toString();}public static void main(String[] args) {System.out.println(MD5Utils.encode("abel"));}
}

2, 修改 webSecurityConfig的加密方法

@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserService()).passwordEncoder(new PasswordEncoder(){@Overridepublic String encode(CharSequence rawPassword) {return MD5Util.encode((String)rawPassword);}@Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {return encodedPassword.equals(MD5Util.encode((String)rawPassword));}}); //user Details Service验证}

BCrypt的强hash算法

BCrypt强哈希方法 每次加密的结果都不一样。但是存贮其中一次加密结果 也能够验证成功

1, 修改WebSecurityConfig

    @Autowiredprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(customUserService).passwordEncoder(new BCryptPasswordEncoder());}

2, 进行加密

  public SysUser create(User u user){//进行加密BCryptPasswordEncoder encoder =new BCryptPasswordEncoder();sysUser.setPassword(encoder.encode(user.getRawPassword().trim()));userDao.create(user);return sysUser;

原博客地址:

http://blog.csdn.net/u012373815/article/details/54633046

http://blog.csdn.net/u012373815/article/details/60465776

springboot-29-security(二)用户角色权限控制相关推荐

  1. springboot +security +mybatis+thymeleaf 实现简单的用户 角色 权限(资源) 管理

    1.用户 角色 资源的关系 2.实现思路 3.参考资料 Spring Boot Security   +Redis 实现简单权限控制 将返回结果变成json 响应改客户端    在第六项 4.实现代码 ...

  2. 系统权限控制设计001---RBAC用户角色权限设计方案

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

  3. 2.Spring Security 用户注销 与 Thymeleaf 权限控制

    Spring Security 用户注销 与 Thymeleaf 权限控制 Spring Security 用户注销 1.上一篇<Spring Security 详细简绍与入门>中内存用户 ...

  4. RBAC用户角色权限设计方案

    RBAC用户角色权限设计方案 转自http://www.cnblogs.com/zwq194/archive/2011/03/07/1974821.html RBAC(Role-Based Acces ...

  5. RBAC、控制权限设计、权限表设计 基于角色权限控制和基于资源权限控制的区别优劣

    RBAC.控制权限设计.权限表设计 基于角色权限控制和基于资源权限控制的区别优劣 一.介绍 二.基于角色的权限设计 三.基于资源的权限设计 四.主体.资源.权限关系图 主体.资源.权限相关的数据模型 ...

  6. ThinkPHP的RBAC(基于角色权限控制)详解

    ThinkPHP的RBAC(基于角色权限控制)详解 一.什么是RBAC 基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到 ...

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

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

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

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

  9. RBAC用户角色权限设计方案(转)

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

最新文章

  1. HTTP协议/RTSP协议/RTMP协议的区别
  2. iOS:多线程技术GCD的使用
  3. flash代码_Flash如何对制作文件进行优化
  4. django 正则捕捉路径 re_path函数
  5. 泉州中考分数如何计算机,2019年泉州中考总分多少分,泉州中考考试科目设置
  6. BZOJ4435 : [Cerc2015]Juice Junctions
  7. 在线教育工具—白板系统的迭代1——bug监控排查
  8. oracle误删除数据之后的恢复方法
  9. VOC2007数据集详细分析
  10. 论文写作,word首页脚注不显示编号
  11. VS2017下搭建OPEN CASCADE
  12. Others13_在黑市里,苹果iPhone是这样被解锁的
  13. python核心编程电子书_Python核心编程 PDF 超清第3版
  14. php fpm 测试,PHP脚本FPM环境最大执行时间研究
  15. 这个 api 管理工具悄悄开源了,快来看看
  16. 在Linux中开机自动运行普通用户脚本程序
  17. 排名前6位的最流行的大数据框架,你在用哪一款?
  18. 史上最全电脑硬盘修复方法
  19. 【机器学习】逻辑斯蒂回归原理推导与求解
  20. go比python的优缺点

热门文章

  1. Linux之alias命令
  2. Android 屏幕刷新机制
  3. Windwos Server 2008 R2 DHCP服务
  4. Git合并最近的commit
  5. centos7 服务器安装nginx,mysql,php
  6. Java Web开发应用中要掌握的一些感念 疯狂JAVA
  7. 开源WEB服务器-lighttpd 1.4.24发布
  8. 22.案例实战:把springboot的接口,自动生成接口文档
  9. c语言中英互译程序,c语言怎么翻译? 程序怎么运行?
  10. python全栈之巅_Python 迭代器、生成器详解 - Python全栈之巅