springboot-29-security(二)用户角色权限控制
本博客基于上一个 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(二)用户角色权限控制相关推荐
- springboot +security +mybatis+thymeleaf 实现简单的用户 角色 权限(资源) 管理
1.用户 角色 资源的关系 2.实现思路 3.参考资料 Spring Boot Security +Redis 实现简单权限控制 将返回结果变成json 响应改客户端 在第六项 4.实现代码 ...
- 系统权限控制设计001---RBAC用户角色权限设计方案
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...
- 2.Spring Security 用户注销 与 Thymeleaf 权限控制
Spring Security 用户注销 与 Thymeleaf 权限控制 Spring Security 用户注销 1.上一篇<Spring Security 详细简绍与入门>中内存用户 ...
- RBAC用户角色权限设计方案
RBAC用户角色权限设计方案 转自http://www.cnblogs.com/zwq194/archive/2011/03/07/1974821.html RBAC(Role-Based Acces ...
- RBAC、控制权限设计、权限表设计 基于角色权限控制和基于资源权限控制的区别优劣
RBAC.控制权限设计.权限表设计 基于角色权限控制和基于资源权限控制的区别优劣 一.介绍 二.基于角色的权限设计 三.基于资源的权限设计 四.主体.资源.权限关系图 主体.资源.权限相关的数据模型 ...
- ThinkPHP的RBAC(基于角色权限控制)详解
ThinkPHP的RBAC(基于角色权限控制)详解 一.什么是RBAC 基于角色的访问控制(Role-Based Access Control)作为传统访问控制(自主访问,强制访问)的有前景的代替受到 ...
- SpringSecurity动态加载用户角色权限实现登录及鉴权
本文来说下SpringSecurity如何动态加载用户角色权限实现登录及鉴权 文章目录 概述 动态数据登录验证的基础知识 UserDetails与UserDetailsService接口 实现User ...
- java用户角色权限管理 只显示姓_扩展RBAC用户角色权限设计方案
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成"用 ...
- RBAC用户角色权限设计方案(转)
RBAC用户角色权限设计方案 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限 ...
最新文章
- HTTP协议/RTSP协议/RTMP协议的区别
- iOS:多线程技术GCD的使用
- flash代码_Flash如何对制作文件进行优化
- django 正则捕捉路径 re_path函数
- 泉州中考分数如何计算机,2019年泉州中考总分多少分,泉州中考考试科目设置
- BZOJ4435 : [Cerc2015]Juice Junctions
- 在线教育工具—白板系统的迭代1——bug监控排查
- oracle误删除数据之后的恢复方法
- VOC2007数据集详细分析
- 论文写作,word首页脚注不显示编号
- VS2017下搭建OPEN CASCADE
- Others13_在黑市里,苹果iPhone是这样被解锁的
- python核心编程电子书_Python核心编程 PDF 超清第3版
- php fpm 测试,PHP脚本FPM环境最大执行时间研究
- 这个 api 管理工具悄悄开源了,快来看看
- 在Linux中开机自动运行普通用户脚本程序
- 排名前6位的最流行的大数据框架,你在用哪一款?
- 史上最全电脑硬盘修复方法
- 【机器学习】逻辑斯蒂回归原理推导与求解
- go比python的优缺点