本博客基于上一个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=; -- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` INT () NOT NULL AUTO_INCREMENT COMMENT '主键id',
`username` varchar() DEFAULT NULL COMMENT '用户名',
`password` varchar() DEFAULT NULL COMMENT '密码',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8; -- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` INT () NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar() DEFAULT NULL COMMENT '用户名',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8; -- ----------------------------
-- Table structure for `sys_permission`
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission` (
`id` INT () NOT NULL AUTO_INCREMENT COMMENT '主键id',
`name` varchar() DEFAULT NULL COMMENT '用户名',
`desc` VARCHAR () DEFAULT NULL COMMENT '描述',
`url` VARCHAR () DEFAULT NULL COMMENT 'url',
`pid` INT (),
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8; -- ----------------------------
-- Table structure for `sys_role_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (
`id` bigint() NOT NULL AUTO_INCREMENT COMMENT '主键id',
`sys_user_id` INT() NOT NULL COMMENT 'user_id',
`sys_role_id` INT() NOT NULL COMMENT 'role_id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= 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() NOT NULL AUTO_INCREMENT COMMENT '主键id',
`sys_role_id` INT() NOT NULL COMMENT 'role_id',
`sys_permission_id` INT() NOT NULL COMMENT 'permission_id',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT= 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 (,'vini', '');
insert into SYS_USER (id,username, password) values (,'bronk', ''); insert into SYS_ROLE(id,name) values(,'ROLE_ADMIN');
insert into SYS_ROLE(id,name) values(,'ROLE_USER'); insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(,);
insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(,); BEGIN;
INSERT INTO `sys_permission` VALUES ('', 'ROLE_HOME', 'home', '/', null),
('', 'ROLE_ADMIN', 'ABel', '/admin', null);
COMMIT; BEGIN;
INSERT INTO `sys_permission_role` VALUES ('', '', ''), ('', '', ''), ('', '', '');
COMMIT;

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

SysPermission.groovy

package com.wenbronk.security.entity

/**
* Created by wenbronk on 2017/8/17.
*/
class SysPermission {
int id
String name
String desc
String url
int pid
}

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

和上个一样

二, security部分

东西比较多, 按流程来,

1, WebSecurityConfig.groovy 添加

http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class)

最终代码为:

package com.wenbronk.security.security.config

import 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.FilterSecurityInterceptor import javax.inject.Inject
/**
* Created by wenbronk on 2017/8/15.
*/
@Configuration
@EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Inject
CustomUserService customUserService;
@Autowired
MyFilterSecurityInterceptor myFilterSecurityInterceptor @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserService);
} @Override
protected 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.interceptor

import 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.Component import javax.inject.Inject
import javax.servlet.* /**
* Created by wenbronk on 2017/8/17.
*/
@Component
class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter { @Inject
FilterInvocationSecurityMetadataSource securityMetadataSource @Autowired
public void setMyAccessDecisionManager(MyAccessDecisonManager myAccessDecisonManager) {
super.setAccessDecisionManager(myAccessDecisonManager)
} @Override
void init(FilterConfig filterConfig) throws ServletException { } /**
* fi中有一个被拦截的url
* 里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
//再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
*/
@Override
void 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)
}
} @Override
void destroy() { } @Override
Class<?> getSecureObjectClass() {
return FilterInvocation.class
} @Override
SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource
}
}

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

MyInvocationSecurityMetadataSource.groovy

package com.wenbronk.security.security.service

import 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.Service import javax.inject.Inject
import javax.servlet.http.HttpServletRequest /**
* Created by wenbronk on 2017/8/17.
*/
@Service
class MyInvocationSecurityMetadataSourceService implements FilterInvocationSecurityMetadataSource{ @Inject
SysPermissionMapper sysPermissionMapper /**
* 此方法是为了判定用户请求的url 是否在权限表中,
* 如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
*/
@Override
Collection<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
} @Override
Collection<ConfigAttribute> getAllConfigAttributes() {
return null
} @Override
boolean supports(Class<?> aClass) {
return true
}
}

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

MyAccessDecisionManger.groovy

package com.wenbronk.security.security.config

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.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)这个方法返回的结果,
*/
@Override
void decide(Authentication authentication, Object o, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
if (null == configAttributes || configAttributes.size() <= )
return
configAttributes.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')
} @Override
boolean supports(ConfigAttribute configAttribute) {
return true
} @Override
boolean supports(Class<?> aClass) {
return true
}
}

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

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

package com.wenbronk.security.security.service

import 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.Service import javax.inject.Inject
/**
* Created by wenbronk on 2017/8/15.
*/
@Service
class CustomUserService implements UserDetailsService { @Inject
SysUserMapper sysUserMapper
@Inject
SysPermissionMapper sysPermissionMapper @Override
UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
def sysUser = sysUserMapper.findByUserName(s) as SysUser
if (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{ @Override
void 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.tools

import 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 = ; i < charArray.length; i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = ; i < md5Bytes.length; i++) {
int val = ((int) md5Bytes[i]) & 0xff;
if (val < ) {
hexValue.append("");
} hexValue.append(Integer.toHexString(val));
}
return hexValue.toString();
} public static void main(String[] args) {
System.out.println(MD5Utils.encode("abel"));
}
}

2, 修改 webSecurityConfig的加密方法

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

BCrypt的强hash算法

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

1, 修改WebSecurityConfig

    @Autowired
protected 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. MVC开发模式下的用户角色权限控制

    前提: MVC开发模式 大概思想: 1.在MVC开发模式下,每个功能都对应着不同的控制器或操作方法名(如修改密码功能可能对应着User/changepd),把每个功能对应的控制器名和操作方法名存到数据 ...

  2. 简单的RBAC用户角色权限控制

    Java web项目中,无论项目是大是小,或多或少都会涉及到用户访问权限的控制,权限管理总体的设计思路就是,不该看的不看,不该做的不做!据我目前的了解,我所知道的几种实现访问权限控制的方式有: JQu ...

  3. springboot+shiro+redis(单机redis版)整合教程-续(添加动态角色权限控制)

    相关教程: 1. springboot+shiro整合教程 2. springboot+shiro+redis(单机redis版)整合教程 3. springboot+shiro+redis(集群re ...

  4. SpringBoot集成Spring Security(5)——权限控制

    在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了. 为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是 ...

  5. 【shiro】2.spring整合shiro,注解控制shiro用户/角色/权限And/OR,没有权限跳转到固定页面

    这几天粗浅的把shiro整合到spring中,并且注解控制shiro用户/角色/权限And/OR 步骤: 1.首先maven搭建web项目 2.创建数据库 user/role/authority 其中 ...

  6. springboot + 注解 + 拦截器 + JWT 实现角色权限控制

    1.关于JWT,参考: (1)10分钟了解JSON Web令牌(JWT) (2)认识JWT (3)基于jwt的token验证 2.JWT的JAVA实现 Java中对JWT的支持可以考虑使用JJWT开源 ...

  7. rbac(基于角色权限控制)-------权限管理

    权限管理 创建一个rbac和app的应用,这个rbac主要是用来存放权限的,全称叫做基于角色权限控制 一.先看配置文件合适不,给创建的rbac在配置文件里面设置一下 找到INSTALLED_APPS= ...

  8. [转]扩展RBAC用户角色权限设计方案

    原文地址:http://www.iteye.com/topic/930648 RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地 ...

  9. 扩展RBAC用户角色权限设计方案

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

随机推荐

  1. 图像像素转换 8-bit 16-bit 32-bit游戏效果

    https://www.ipcfun.com/8bit-you-xi-hua-mian-fu-yuan-3d-li-ti-tu.html https://bbs.csdn.net/wap/topics ...

  2. 一个封存Id与状态对应键值的神器,BigInteger的setBit和testBit用法实例

    1,首先描述一下应用场景 比如,我们要对菜单做权限,控制不同角色菜单显示与不显示,角色为经理时,我们需要菜单id为 4,7,13,24的菜单显示,别的菜单不显示. 就是说,这时候我们要把4,7,13, ...

  3. poj1741(点分模板)

    #include<iostream> #include<cstring> #include<cmath> #include<cstdio> #inclu ...

  4. set_error_handler

    set_error_handler这个函数的作用是为了防止错误路径泄露 何为错误路径泄露呢? 我们写程序,难免会有问题,而PHP遇到错误时,就会给出出错脚本的位置.行数和原因 有很多人说,这并没有什么 ...

  5. 一个前端小白,关于vue\react等框架下table的应用总结

    出来实习一个月多,对于前端,运用相关的最多的就是table,想总结一下先关的内容 一.table提供的功能 1.显示表 2.可编辑:分为可编辑行和可编辑块,但是原理都一样就是设置一个flag,true ...

  6. java基础知识-逻辑运算符

    /*首先申明:逻辑运算符的操作数都是布尔型表达式*/ /* 演示逻辑运算符 & :两个操作数都为真的时候结果为真 | :两个操作数只要有一个为真,结果就为真 && :短路与,左 ...

  7. ListView 指定显示最后一行,scrollView显示最底部

    实现方式: 一. mListView.setSelection(adapter.getCount()-1); 二.在ListView的xml添加以下属性: android:stackFromBotto ...

  8. 如何将Excel 图表导出

    简单分三步: Step1: Alt+ F11 --> 调出 VBA: Step2: Ctrl+G (开关键)—>调出立即窗口: Step3:  在立即窗口输入  activesheet.C ...

  9. MGW PCI Framework Architecture

    MGW执行SWBT/FT cases是主要是利用Ant项目. Ant的概念 可能有些读者并不连接什么是Ant以及入可使用它,但只要使用通过Linux系统得读者,应该知道make这个命令.当编译Linu ...

  10. ionic 图片轮播ion-slide-box问题

    1.使用ion-slide可以实现图片轮播,但是如果在html中仅仅增加ion-slide是远远不够的,会出现两个问题: (注:使用的是angularjs.首先需要在,js文件中注入:$ionicSl ...