提交 d0d7deaf 编写于 作者: zlt2000's avatar zlt2000

增加多租户功能(应用隔离)

上级 d7e914c6
......@@ -27,8 +27,8 @@
* 基于`Spring Boot 2.0.X``Spring Cloud Finchley``Spring Cloud Alibaba`
* 主要针对解决微服务和业务开发时常见的**非功能性需求**
* 深度定制`Spring Security`真正实现了基于`RBAC``jwt``oauth2`的无状态统一权限认证的解决方案
* 提供应用管理,方便第三方系统接入
* 引入组件化的思想实现高内聚低耦合,项目代码简洁注释丰富上手容易
* 提供应用管理,方便第三方系统接入,支持多租户
* 引入组件化的思想实现高内聚低耦合并且高度可配置化
* 注重代码规范,严格控制包依赖,每个工程基本都是最小依赖
* 非常适合学习和企业中使用
......@@ -78,6 +78,7 @@
- nacos监控
- prometheus监控
* **业务基础功能支撑**
* 多租户(应用隔离)
* 高性能方法级幂等性支持
* RBAC权限管理,实现细粒度控制(方法、url级别)
* 快速实现导入、导出功能
......
......@@ -6,6 +6,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* 文件中心
......@@ -13,6 +14,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
*/
@EnableDiscoveryClient
@EnableConfigurationProperties(FileServerProperties.class)
@EnableFeignClients
@EnableFeignInterceptor
@SpringBootApplication
public class FileCenterApp {
......
package com.central.file.config;
import com.central.common.config.DefaultWebMvcConfig;
import org.springframework.context.annotation.Configuration;
/**
* @author zlt
* @date 2019/8/5
*/
@Configuration
public class WebMvcConfig extends DefaultWebMvcConfig {
}
......@@ -31,6 +31,9 @@ zlt:
description: 文件中心接口文档
version: 1.0
base-package: com.central.file.controller
#多租户配置
tenant:
enable: true
#fastDFS配置
fdfs:
......
package com.central;
import com.central.admin.properties.IndexProperties;
import com.central.common.annotation.EnableLoginArgResolver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
......@@ -11,7 +10,6 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
* @author zlt
* @date 2019/5/1
*/
@EnableLoginArgResolver
@EnableDiscoveryClient
@SpringBootApplication
@EnableConfigurationProperties(IndexProperties.class)
......
package com.central.common.config;
import org.springframework.context.annotation.Configuration;
/**
* @author zlt
* @date 2019/8/5
*/
@Configuration
public class WebMvcConfig extends DefaultWebMvcConfig {
}
package com.central;
import com.central.common.annotation.EnableLoginArgResolver;
import com.central.common.ribbon.annotation.EnableFeignInterceptor;
import com.central.search.annotation.EnableSearchClient;
import org.springframework.boot.SpringApplication;
......@@ -11,7 +10,6 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @author 作者 owen E-mail: 624191343@qq.com
*/
@EnableLoginArgResolver
@EnableDiscoveryClient
@EnableSearchClient
@EnableTransactionManagement
......
package com.central.user.config;
import com.central.common.config.DefaultWebMvcConfig;
import org.springframework.context.annotation.Configuration;
/**
* @author zlt
* @date 2019/8/5
*/
@Configuration
public class WebMvcConfig extends DefaultWebMvcConfig {
}
......@@ -28,8 +28,7 @@ public interface SysUserRoleMapper extends SuperMapper<SysRoleUser> {
* @param userId
* @return
*/
@Select("select r.* from sys_role_user ru inner join sys_role r on r.id = ru.role_id where ru.user_id = #{userId}")
List<SysRole> findRolesByUserId(Long userId);
List<SysRole> findRolesByUserId(@Param("userId") Long userId);
/**
* 根据用户ids 获取
......
......@@ -26,3 +26,10 @@ zlt:
second: 300
- key: user
second: 1800
#多租户配置
tenant:
enable: true
ignoreTables:
- sys_user
- sys_role_user
- sys_role_menu
\ No newline at end of file
......@@ -43,6 +43,7 @@
<if test="type != null">
and t.type = #{type}
</if>
and t.hidden = 0
ORDER BY sort ASC
</select>
</mapper>
\ No newline at end of file
......@@ -13,4 +13,9 @@
</if>
</where>
</delete>
<select id="findRolesByUserId" resultType="com.central.common.model.SysRole">
select r.* from sys_role r
inner join sys_role_user ru on r.id = ru.role_id and ru.user_id = #{userId}
</select>
</mapper>
\ No newline at end of file
package com.central.common.annotation;
import com.central.common.config.LoginArgResolverConfig;
import org.springframework.context.annotation.Import;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 在启动类上添加该注解来----开启自动登录用户对象注入
* Token转化SysUser
*
* @author zlt
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(LoginArgResolverConfig.class)
public @interface EnableLoginArgResolver {
}
package com.central.common.config;
import com.central.common.feign.UserService;
import com.central.common.interceptor.TenantInterceptor;
import com.central.common.resolver.ClientArgumentResolver;
import com.central.common.resolver.TokenArgumentResolver;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import java.util.List;
/**
* 默认SpringMVC拦截器
*
* @author zlt
* @date 2019/8/5
*/
public class DefaultWebMvcConfig extends WebMvcConfigurationSupport {
@Autowired
private UserService userService;
/**
* 配置SpringMVC拦截器,添加租户拦截器
*/
@Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TenantInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
/**
* Token参数解析
*
* @param argumentResolvers 解析类
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
//注入用户信息
argumentResolvers.add(new TokenArgumentResolver(userService));
//注入应用信息
argumentResolvers.add(new ClientArgumentResolver());
}
}
......@@ -97,4 +97,9 @@ public interface CommonConstant {
String DEF_USER_PASSWORD = "123456";
String LOCK_KEY_PREFIX = "LOCK_KEY:";
/**
* 租户id参数
*/
String TENANT_ID_PARAM = "tenantId";
}
......@@ -27,8 +27,9 @@ public interface SecurityConstants {
String ROLE_HEADER = "x-role-header";
/**
* 应用信息头
* 租户信息头(应用)
*/
String TENANT_HEADER = "x-tenant-header";
String CLIENT_HEADER = "x-client-header";
/**
......
package com.central.common.interceptor;
import cn.hutool.core.util.StrUtil;
import com.central.common.constant.CommonConstant;
import com.central.common.constant.SecurityConstants;
import com.central.common.utils.TenantContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 租户拦截器
*
* @author zlt
* @date 2019/8/5
*/
public class TenantInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//优先获取请求参数中的tenantId值
String tenantId = request.getParameter(CommonConstant.TENANT_ID_PARAM);
if (StrUtil.isEmpty(tenantId)) {
tenantId = request.getHeader(SecurityConstants.TENANT_HEADER);
}
//保存租户id
if(StrUtil.isNotEmpty(tenantId)){
TenantContextHolder.setTenant(tenantId);
}
return true;
}
}
package com.central.common.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import java.util.ArrayList;
import java.util.List;
/**
* 多租户配置
* @author zlt
* @date 2019/8/5
*/
@Setter
@Getter
@ConfigurationProperties(prefix = "zlt.tenant")
@RefreshScope
public class TenantProperties {
/**
* 是否开启多租户
*/
private Boolean enable = false;
/**
* 配置不进行多租户隔离的表名
*/
private List<String> ignoreTables = new ArrayList<>();
/**
* 配置不进行多租户隔离的sql
* 需要配置mapper的全路径如:com.central.user.mapper.SysUserMapper.findList
*/
private List<String> ignoreSqls = new ArrayList<>();
}
......@@ -44,7 +44,7 @@ public class ClientArgumentResolver implements HandlerMethodArgumentResolver {
NativeWebRequest nativeWebRequest,
WebDataBinderFactory webDataBinderFactory) {
HttpServletRequest request = nativeWebRequest.getNativeRequest(HttpServletRequest.class);
String clientId = request.getHeader(SecurityConstants.CLIENT_HEADER);
String clientId = request.getHeader(SecurityConstants.TENANT_HEADER);
if (StrUtil.isBlank(clientId)) {
log.warn("resolveArgument error clientId is empty");
}
......
package com.central.common.utils;
/**
* 租户holder
*
* @author zlt
* @date 2019/8/5
*/
public class TenantContextHolder {
private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void setTenant(String tenant) {
CONTEXT.set(tenant);
}
public static String getTenant() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
......@@ -12,6 +12,11 @@
<artifactId>zlt-db-spring-boot-starter</artifactId>
<description>数据库通用组件</description>
<dependencies>
<dependency>
<groupId>com.zlt</groupId>
<artifactId>zlt-common-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
......
package com.central.db.config;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
import com.central.common.properties.TenantProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Profile;
......@@ -13,12 +20,30 @@ import org.springframework.context.annotation.Profile;
*/
@Import(DateMetaObjectHandler.class)
public class DefaultMybatisPlusConfig {
@Autowired
private TenantHandler tenantHandler;
@Autowired
private ISqlParserFilter sqlParserFilter;
@Autowired
private TenantProperties tenantProperties;
/**
* 分页插件,自动识别数据库类型
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
boolean enableTenant = tenantProperties.getEnable();
//是否开启多租户隔离
if (enableTenant) {
TenantSqlParser tenantSqlParser = new TenantSqlParser()
.setTenantHandler(tenantHandler);
paginationInterceptor.setSqlParserList(CollUtil.toList(tenantSqlParser));
paginationInterceptor.setSqlParserFilter(sqlParserFilter);
}
return paginationInterceptor;
}
/**
......
package com.central.db.config;
import com.baomidou.mybatisplus.core.parser.ISqlParserFilter;
import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
import com.central.common.utils.TenantContextHolder;
import com.central.common.properties.TenantProperties;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.NullValue;
import net.sf.jsqlparser.expression.StringValue;
import org.apache.ibatis.mapping.MappedStatement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
/**
* 多租户自动配置
*
* @author zlt
* @date 2019/8/5
*/
@EnableConfigurationProperties(TenantProperties.class)
public class TenantAutoConfigure {
@Autowired
private TenantProperties tenantProperties;
@Bean
public TenantHandler tenantHandler() {
return new TenantHandler() {
/**
* 获取租户id
*/
@Override
public Expression getTenantId() {
String tenant = TenantContextHolder.getTenant();
if (tenant != null) {
return new StringValue(TenantContextHolder.getTenant());
}
return new NullValue();
}
/**
* 获取租户列名
*/
@Override
public String getTenantIdColumn() {
return "tenant_id";
}
/**
* 过滤不需要根据租户隔离的表
* @param tableName 表名
*/
@Override
public boolean doTableFilter(String tableName) {
return tenantProperties.getIgnoreTables().stream().anyMatch(
(e) -> e.equalsIgnoreCase(tableName)
);
}
};
}
/**
* 过滤不需要根据租户隔离的MappedStatement
*/
@Bean
public ISqlParserFilter sqlParserFilter() {
return metaObject -> {
MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
return tenantProperties.getIgnoreSqls().stream().anyMatch(
(e) -> e.equalsIgnoreCase(ms.getId())
);
};
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.central.db.config.TenantAutoConfigure
......@@ -3,6 +3,7 @@ package com.central.common.ribbon.config;
import cn.hutool.core.util.StrUtil;
import com.central.common.constant.CommonConstant;
import com.central.common.constant.SecurityConstants;
import com.central.common.utils.TenantContextHolder;
import feign.RequestInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.web.context.request.RequestContextHolder;
......@@ -28,14 +29,16 @@ public class FeignInterceptorConfig {
.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//传递access_token,无网关隔离时需要传递
/*String token = extractHeaderToken(request);
//传递access_token,无网络隔离时需要传递
/*
String token = extractHeaderToken(request);
if (StrUtil.isEmpty(token)) {
token = request.getParameter(CommonConstant.ACCESS_TOKEN);
}
if (StrUtil.isNotEmpty(token)) {
template.header(CommonConstant.TOKEN_HEADER, CommonConstant.BEARER_TYPE + " " + token);
}*/
}
*/
//传递username
String username = request.getHeader(SecurityConstants.USER_HEADER);
......@@ -50,9 +53,9 @@ public class FeignInterceptorConfig {
}
//传递client
String client = request.getHeader(SecurityConstants.CLIENT_HEADER);
if (StrUtil.isNotEmpty(client)) {
template.header(SecurityConstants.CLIENT_HEADER, client);
String tenant = TenantContextHolder.getTenant();
if (StrUtil.isNotEmpty(tenant)) {
template.header(SecurityConstants.TENANT_HEADER, tenant);
}
};
return requestInterceptor;
......
......@@ -16,11 +16,13 @@ CREATE TABLE `file_info` (
`source` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `createTime`(`create_time`) USING BTREE
`tenant_id` varchar(32) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
KEY `idx_create_time` (`create_time`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of file_info
-- ----------------------------
INSERT INTO `file_info` VALUES ('2c95b54f4d8356cf8ab40802f496df83', '头像.png', 1, 'image/png', 1290, 'http://pkqtmn0p1.bkt.clouddn.com/头像.png', 'http://pkqtmn0p1.bkt.clouddn.com/头像.png', 'QINIU', '2019-01-08 17:05:36', '2019-01-08 17:05:36');
INSERT INTO `file_info` VALUES ('2c95b54f4d8356cf8ab40802f496df83', '头像.png', 1, 'image/png', 1290, 'http://pkqtmn0p1.bkt.clouddn.com/头像.png', 'http://pkqtmn0p1.bkt.clouddn.com/头像.png', 'QINIU', '2019-01-08 17:05:36', '2019-01-08 17:05:36', 'webApp');
......@@ -28,6 +28,6 @@ CREATE TABLE `oauth_client_details` (
-- ----------------------------
-- Records of oauth_client_details
-- ----------------------------
INSERT INTO `oauth_client_details` VALUES (1, 'app', NULL, '$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO', 'app', 'app', 'password,refresh_token', NULL, NULL, 3600, NULL, '{}', 'true', NULL, NULL, '移动端');
INSERT INTO `oauth_client_details` VALUES (2, 'webApp', NULL, '$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72', 'webApp', 'app', 'authorization_code,password,refresh_token,client_credentials', NULL, NULL, 3600, NULL, '{}', 'true', NULL, NULL, 'pc端');
INSERT INTO `oauth_client_details` VALUES (1, 'webApp', NULL, '$2a$10$06msMGYRH8nrm4iVnKFNKOoddB8wOwymVhbUzw/d3ZixD7Nq8ot72', 'webApp', 'app', 'authorization_code,password,refresh_token,client_credentials', NULL, NULL, 3600, NULL, '{}', 'true', NULL, NULL, 'pc端');
INSERT INTO `oauth_client_details` VALUES (2, 'app', NULL, '$2a$10$i3F515wEDiB4Gvj9ym9Prui0dasRttEUQ9ink4Wpgb4zEDCAlV8zO', 'app', 'app', 'password,refresh_token', NULL, NULL, 3600, NULL, '{}', 'true', NULL, NULL, '移动端');
INSERT INTO `oauth_client_details` VALUES (3, 'zlt', NULL, '$2a$10$/o.wuORzVcXaezmYVzwYMuoY7qeWXBALwQmkskXD/7C6rqfCyPrna', 'zlt', 'all', 'authorization_code,password,refresh_token,client_credentials', 'http://127.0.0.1:8080/singleLogin', NULL, 3600, 28800, '{}', 'true', '2018-12-27 00:50:30', '2018-12-27 00:50:30', '第三方应用');
\ No newline at end of file
......@@ -20,10 +20,10 @@ CREATE TABLE `sys_user` (
`company` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`open_id` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
`is_del` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
INDEX `username`(`username`) USING BTREE,
INDEX `mobile`(`mobile`) USING BTREE,
INDEX `open_id`(`open_id`) USING BTREE
PRIMARY KEY (`id`),
KEY `idx_username` (`username`),
KEY `idx_mobile` (`mobile`),
KEY `idx_open_id` (`open_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 27 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
......@@ -52,17 +52,20 @@ CREATE TABLE `sys_role` (
`name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '角色名',
`create_time` datetime(0) NULL DEFAULT NULL,
`update_time` datetime(0) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
INDEX `code`(`code`) USING BTREE
`tenant_id` varchar(32) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
KEY `idx_code` (`code`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'ADMIN', '管理员', '2017-11-17 16:56:59', '2018-09-19 09:39:10');
INSERT INTO `sys_role` VALUES (2, 'test', '测试', '2018-09-17 10:15:51', '2018-11-15 01:49:14');
INSERT INTO `sys_role` VALUES (3, '11', '11', '2018-11-15 01:49:19', '2018-11-15 01:49:19');
INSERT INTO `sys_role` VALUES (4, '123', '1235', '2018-11-15 23:33:39', '2018-12-24 23:53:33');
INSERT INTO `sys_role` VALUES (1, 'ADMIN', '管理员', '2017-11-17 16:56:59', '2018-09-19 09:39:10', 'webApp');
INSERT INTO `sys_role` VALUES (2, 'test', '测试', '2018-09-17 10:15:51', '2018-11-15 01:49:14', 'webApp');
INSERT INTO `sys_role` VALUES (3, '11', '11', '2018-11-15 01:49:19', '2018-11-15 01:49:19', 'webApp');
INSERT INTO `sys_role` VALUES (4, 'shop_admin', '商城管理员', '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 'zlt');
INSERT INTO `sys_role` VALUES (5, 'app_admin', '移动管理员', '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 'app');
-- ----------------------------
-- Table structure for sys_role_user
......@@ -71,7 +74,7 @@ DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (
`user_id` int(11) NOT NULL,
`role_id` int(11) NOT NULL,
PRIMARY KEY (`user_id`, `role_id`) USING BTREE
PRIMARY KEY (`user_id`, `role_id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
......@@ -88,7 +91,7 @@ INSERT INTO `sys_role_user` VALUES (8, 2);
INSERT INTO `sys_role_user` VALUES (9, 3);
INSERT INTO `sys_role_user` VALUES (10, 3);
INSERT INTO `sys_role_user` VALUES (11, 4);
INSERT INTO `sys_role_user` VALUES (12, 4);
INSERT INTO `sys_role_user` VALUES (12, 5);
-- ----------------------------
-- Table structure for sys_menu
......@@ -107,40 +110,47 @@ CREATE TABLE `sys_menu` (
`update_time` datetime(0) NULL,
`type` tinyint(1) NOT NULL,
`hidden` tinyint(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
INDEX `parent_id`(`parent_id`) USING BTREE
`tenant_id` varchar(32) DEFAULT '' COMMENT '租户字段',
PRIMARY KEY (`id`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE = InnoDB AUTO_INCREMENT = 62 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_menu
-- ----------------------------
INSERT INTO `sys_menu` VALUES (2, 12, '用户管理', '#!user', 'system/user.html', NULL, 'layui-icon-friends', 2, '2017-11-17 16:56:59', '2018-09-19 11:26:14', 1, 0);
INSERT INTO `sys_menu` VALUES (3, 12, '角色管理', '#!role', 'system/role.html', NULL, 'layui-icon-user', 3, '2017-11-17 16:56:59', '2019-01-14 15:34:40', 1, 0);
INSERT INTO `sys_menu` VALUES (4, 12, '菜单管理', '#!menus', 'system/menus.html', NULL, 'layui-icon-menu-fill', 4, '2017-11-17 16:56:59', '2018-09-03 02:23:47', 1, 0);
INSERT INTO `sys_menu` VALUES (9, 37, '文件中心', '#!files', 'files/files.html', NULL, 'layui-icon-file', 3, '2017-11-17 16:56:59', '2019-01-17 20:18:44', 1, 0);
INSERT INTO `sys_menu` VALUES (10, 37, '文档中心', '#!swagger', 'http://127.0.0.1:9900/swagger-ui.html', NULL, 'layui-icon-app', 4, '2017-11-17 16:56:59', '2019-01-17 20:18:48', 1, 0);
INSERT INTO `sys_menu` VALUES (11, 12, '我的信息', '#!myInfo', 'system/myInfo.html', NULL, '', 10, '2017-11-17 16:56:59', '2018-09-02 06:12:24', 1, 1);
INSERT INTO `sys_menu` VALUES (12, -1, '认证管理', 'javascript:;', '', NULL, 'layui-icon-set', 1, '2017-11-17 16:56:59', '2018-12-13 15:02:49', 1, 0);
INSERT INTO `sys_menu` VALUES (35, 12, '应用管理', '#!app', 'attestation/app.html', NULL, 'layui-icon-link', 5, '2017-11-17 16:56:59', '2019-01-14 15:35:15', 1, 0);
INSERT INTO `sys_menu` VALUES (37, -1, '系统管理', 'javascript:;', '', NULL, 'layui-icon-set', 2, '2018-08-25 10:41:58', '2019-01-23 14:01:58', 1, 0);
INSERT INTO `sys_menu` VALUES (62, 63, '应用监控', '#!admin', 'http://127.0.0.1:6500/#/wallboard', NULL, 'layui-icon-chart-screen', 3, '2019-01-08 15:32:19', '2019-01-17 20:22:44', 1, 0);
INSERT INTO `sys_menu` VALUES (63, -1, '系统监控', 'javascript:;', '', NULL, 'layui-icon-set', 2, '2019-01-10 18:35:05', '2019-01-10 18:35:05', 1, 0);
INSERT INTO `sys_menu` VALUES (64, 63, '系统日志', '#!sysLog', 'log/sysLog.html', NULL, 'layui-icon-file-b', 1, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0);
INSERT INTO `sys_menu` VALUES (65, 37, '代码生成器', '#!generator', 'generator/list.html', NULL, 'layui-icon-template', 2, '2019-01-14 00:47:36', '2019-01-23 14:06:31', 1, 0);
INSERT INTO `sys_menu` VALUES (66, 63, '慢查询SQL', '#!slowQueryLog', 'log/slowQueryLog.html', NULL, 'layui-icon-snowflake', 2, '2019-01-16 12:00:27', '2019-01-16 15:32:31', 1, 0);
INSERT INTO `sys_menu` VALUES (67, -1, '任务管理', '#!job', 'http://127.0.0.1:8081/', NULL, 'layui-icon-date', 3, '2019-01-17 20:18:22', '2019-01-23 14:01:53', 1, 0);
INSERT INTO `sys_menu` VALUES (68, 63, '应用吞吐量监控', '#!sentinel', 'http://127.0.0.1:6999', NULL, 'layui-icon-chart', 4, '2019-01-22 16:31:55', '2019-01-22 16:34:03', 1, 0);
INSERT INTO `sys_menu` VALUES (69, 37, '配置中心', '#!nacos', 'http://127.0.0.1:8848/nacos', NULL, 'layui-icon-tabs', 1, '2019-01-23 14:06:10', '2019-01-23 14:06:10', 1, 0);
INSERT INTO `sys_menu` VALUES (70, 63, 'APM监控', '#!apm', 'http://127.0.0.1:8080', null, 'layui-icon-engine', 5, '2019-02-27 10:31:55', '2019-02-27 10:31:55', 1, 0);
INSERT INTO `sys_menu` VALUES (71, -1, '搜索管理', 'javascript:;', '', NULL, 'layui-icon-set', 3, '2018-08-25 10:41:58', '2019-01-23 15:07:07', 1, 0);
INSERT INTO `sys_menu` VALUES (72, 71, '索引管理', '#!index', 'search/index_manager.html', NULL, 'layui-icon-template', 1, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0);
INSERT INTO `sys_menu` VALUES (73, 71, '用户搜索', '#!userSearch', 'search/user_search.html', NULL, 'layui-icon-user', 2, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0);
INSERT INTO `sys_menu` VALUES (74, 12, 'Token管理', '#!tokens', 'system/tokens.html', NULL, 'layui-icon-unlink', 6, '2019-07-11 16:56:59', '2019-07-11 16:56:59', 1, 0);
INSERT INTO `sys_menu` VALUES (75, 2, '用户列表', '/api-user/users', 'user-list', 'GET', null, 1, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0);
INSERT INTO `sys_menu` VALUES (76, 2, '查询用户角色', '/api-user/roles', 'user-roles', 'GET', null, 2, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0);
INSERT INTO `sys_menu` VALUES (77, 2, '用户添加', '/api-user/users/saveOrUpdate', 'user-btn-add', 'POST', null, 3, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0);
INSERT INTO `sys_menu` VALUES (78, 2, '用户导出', '/api-user/users/export', 'user-btn-export', 'POST', null, 4, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0);
INSERT INTO `sys_menu` VALUES (79, 2, '用户导入', '/api-user/users/import', 'user-btn-import', 'POST', null, 5, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0);
INSERT INTO `sys_menu` VALUES (2, 12, '用户管理', '#!user', 'system/user.html', NULL, 'layui-icon-friends', 2, '2017-11-17 16:56:59', '2018-09-19 11:26:14', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (3, 12, '角色管理', '#!role', 'system/role.html', NULL, 'layui-icon-user', 3, '2017-11-17 16:56:59', '2019-01-14 15:34:40', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (4, 12, '菜单管理', '#!menus', 'system/menus.html', NULL, 'layui-icon-menu-fill', 4, '2017-11-17 16:56:59', '2018-09-03 02:23:47', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (9, 37, '文件中心', '#!files', 'files/files.html', NULL, 'layui-icon-file', 3, '2017-11-17 16:56:59', '2019-01-17 20:18:44', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (10, 37, '文档中心', '#!swagger', 'http://127.0.0.1:9900/swagger-ui.html', NULL, 'layui-icon-app', 4, '2017-11-17 16:56:59', '2019-01-17 20:18:48', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (11, 12, '我的信息', '#!myInfo', 'system/myInfo.html', NULL, '', 10, '2017-11-17 16:56:59', '2018-09-02 06:12:24', 1, 1, 'webApp');
INSERT INTO `sys_menu` VALUES (12, -1, '认证管理', 'javascript:;', '', NULL, 'layui-icon-set', 1, '2017-11-17 16:56:59', '2018-12-13 15:02:49', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (35, 12, '应用管理', '#!app', 'attestation/app.html', NULL, 'layui-icon-link', 5, '2017-11-17 16:56:59', '2019-01-14 15:35:15', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (37, -1, '系统管理', 'javascript:;', '', NULL, 'layui-icon-set', 2, '2018-08-25 10:41:58', '2019-01-23 14:01:58', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (62, 63, '应用监控', '#!admin', 'http://127.0.0.1:6500/#/wallboard', NULL, 'layui-icon-chart-screen', 3, '2019-01-08 15:32:19', '2019-01-17 20:22:44', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (63, -1, '系统监控', 'javascript:;', '', NULL, 'layui-icon-set', 2, '2019-01-10 18:35:05', '2019-01-10 18:35:05', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (64, 63, '系统日志', '#!sysLog', 'log/sysLog.html', NULL, 'layui-icon-file-b', 1, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (65, 37, '代码生成器', '#!generator', 'generator/list.html', NULL, 'layui-icon-template', 2, '2019-01-14 00:47:36', '2019-01-23 14:06:31', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (66, 63, '慢查询SQL', '#!slowQueryLog', 'log/slowQueryLog.html', NULL, 'layui-icon-snowflake', 2, '2019-01-16 12:00:27', '2019-01-16 15:32:31', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (67, -1, '任务管理', '#!job', 'http://127.0.0.1:8081/', NULL, 'layui-icon-date', 3, '2019-01-17 20:18:22', '2019-01-23 14:01:53', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (68, 63, '应用吞吐量监控', '#!sentinel', 'http://127.0.0.1:6999', NULL, 'layui-icon-chart', 4, '2019-01-22 16:31:55', '2019-01-22 16:34:03', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (69, 37, '配置中心', '#!nacos', 'http://127.0.0.1:8848/nacos', NULL, 'layui-icon-tabs', 1, '2019-01-23 14:06:10', '2019-01-23 14:06:10', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (70, 63, 'APM监控', '#!apm', 'http://127.0.0.1:8080', null, 'layui-icon-engine', 5, '2019-02-27 10:31:55', '2019-02-27 10:31:55', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (71, -1, '搜索管理', 'javascript:;', '', NULL, 'layui-icon-set', 3, '2018-08-25 10:41:58', '2019-01-23 15:07:07', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (72, 71, '索引管理', '#!index', 'search/index_manager.html', NULL, 'layui-icon-template', 1, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (73, 71, '用户搜索', '#!userSearch', 'search/user_search.html', NULL, 'layui-icon-user', 2, '2019-01-10 18:35:55', '2019-01-12 00:27:20', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (74, 12, 'Token管理', '#!tokens', 'system/tokens.html', NULL, 'layui-icon-unlink', 6, '2019-07-11 16:56:59', '2019-07-11 16:56:59', 1, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (75, 2, '用户列表', '/api-user/users', 'user-list', 'GET', null, 1, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (76, 2, '查询用户角色', '/api-user/roles', 'user-roles', 'GET', null, 2, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (77, 2, '用户添加', '/api-user/users/saveOrUpdate', 'user-btn-add', 'POST', null, 3, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (78, 2, '用户导出', '/api-user/users/export', 'user-btn-export', 'POST', null, 4, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (79, 2, '用户导入', '/api-user/users/import', 'user-btn-import', 'POST', null, 5, '2019-07-29 16:56:59', '2019-07-29 16:56:59', 2, 0, 'webApp');
INSERT INTO `sys_menu` VALUES (80, -1, '用户管理', '#!user', '', NULL, NULL, 1, '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 1, 0, 'zlt');
INSERT INTO `sys_menu` VALUES (81, -1, '商品管理', '#!product', '', NULL, NULL, 2, '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 1, 0, 'zlt');
INSERT INTO `sys_menu` VALUES (82, -1, '支付管理', '#!pay', '', NULL, NULL, 3, '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 1, 0, 'zlt');
INSERT INTO `sys_menu` VALUES (83, -1, '交易管理', '#!trading', '', NULL, NULL, 4, '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 1, 0, 'zlt');
INSERT INTO `sys_menu` VALUES (84, -1, '系统管理', '#!system', '', NULL, NULL, 1, '2019-08-06 20:02:12.604', '2019-08-06 20:02:12.604', 1, 0, 'app');
-- ----------------------------
-- Table structure for sys_role_menu
......@@ -149,7 +159,7 @@ DROP TABLE IF EXISTS `sys_role_menu`;
CREATE TABLE `sys_role_menu` (
`role_id` int(11) NOT NULL,
`menu_id` int(11) NOT NULL,
PRIMARY KEY (`role_id`, `menu_id`) USING BTREE
PRIMARY KEY (`role_id`, `menu_id`)
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
......@@ -191,4 +201,10 @@ INSERT INTO `sys_role_menu` VALUES (2, 35);
INSERT INTO `sys_role_menu` VALUES (3, 2);
INSERT INTO `sys_role_menu` VALUES (3, 3);
INSERT INTO `sys_role_menu` VALUES (3, 4);
INSERT INTO `sys_role_menu` VALUES (3, 12);
\ No newline at end of file
INSERT INTO `sys_role_menu` VALUES (3, 12);
INSERT INTO `sys_role_menu` VALUES (3, 12);
INSERT INTO `sys_role_menu` VALUES (4, 80);
INSERT INTO `sys_role_menu` VALUES (4, 81);
INSERT INTO `sys_role_menu` VALUES (4, 82);
INSERT INTO `sys_role_menu` VALUES (4, 83);
INSERT INTO `sys_role_menu` VALUES (5, 84);
\ No newline at end of file
......@@ -51,7 +51,7 @@ public class UserInfoHeaderFilter extends ZuulFilter {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.addZuulRequestHeader(SecurityConstants.USER_ID_HEADER, String.valueOf(userId));
ctx.addZuulRequestHeader(SecurityConstants.USER_HEADER, username);
ctx.addZuulRequestHeader(SecurityConstants.CLIENT_HEADER, clientId);
ctx.addZuulRequestHeader(SecurityConstants.TENANT_HEADER, clientId);
ctx.addZuulRequestHeader(SecurityConstants.ROLE_HEADER, CollectionUtil.join(authentication.getAuthorities(), ","));
}
return null;
......
package com.central;
import com.central.common.annotation.EnableLoginArgResolver;
import com.central.common.ribbon.annotation.EnableFeignInterceptor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
......@@ -11,9 +11,9 @@ import org.springframework.session.data.redis.config.annotation.web.http.EnableR
* @author zlt
*/
@EnableFeignClients
@EnableFeignInterceptor
@EnableDiscoveryClient
@EnableRedisHttpSession
@EnableLoginArgResolver
@SpringBootApplication
public class UaaServerApp {
public static void main(String[] args) {
......
package com.central.oauth.config;
import com.central.common.constant.SecurityConstants;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @author zlt
* @date 2018-12-21 21:12:18
*/
@Configuration
public class KaptchaConfig {
private static final String KAPTCHA_BORDER = "kaptcha.border";
private static final String KAPTCHA_TEXTPRODUCER_FONT_COLOR = "kaptcha.textproducer.font.color";
private static final String KAPTCHA_TEXTPRODUCER_CHAR_SPACE = "kaptcha.textproducer.char.space";
private static final String KAPTCHA_IMAGE_WIDTH = "kaptcha.image.width";
private static final String KAPTCHA_IMAGE_HEIGHT = "kaptcha.image.height";
private static final String KAPTCHA_TEXTPRODUCER_CHAR_LENGTH = "kaptcha.textproducer.char.length";
private static final Object KAPTCHA_IMAGE_FONT_SIZE = "kaptcha.textproducer.font.size";
@Bean
public DefaultKaptcha producer() {
Properties properties = new Properties();
properties.put(KAPTCHA_BORDER, SecurityConstants.DEFAULT_IMAGE_BORDER);
properties.put(KAPTCHA_TEXTPRODUCER_FONT_COLOR, SecurityConstants.DEFAULT_COLOR_FONT);
properties.put(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, SecurityConstants.DEFAULT_CHAR_SPACE);
properties.put(KAPTCHA_IMAGE_WIDTH, SecurityConstants.DEFAULT_IMAGE_WIDTH);
properties.put(KAPTCHA_IMAGE_HEIGHT, SecurityConstants.DEFAULT_IMAGE_HEIGHT);
properties.put(KAPTCHA_IMAGE_FONT_SIZE, SecurityConstants.DEFAULT_IMAGE_FONT_SIZE);
properties.put(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, SecurityConstants.DEFAULT_IMAGE_LENGTH);
Config config = new Config(properties);
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
defaultKaptcha.setConfig(config);
return defaultKaptcha;
}
}
package com.central.oauth.config;
import com.central.common.config.DefaultWebMvcConfig;
import org.springframework.context.annotation.Configuration;
/**
* @author zlt
* @date 2019/8/5
*/
@Configuration
public class WebMvcConfig extends DefaultWebMvcConfig {
}
......@@ -40,9 +40,9 @@ public class ClientController {
@GetMapping("/all")
@ApiOperation(value = "所有应用")
public List<Client> allClient() {
public Result<List<Client>> allClient() {
PageResult<Client> page = clientService.listClent(Maps.newHashMap(), false);
return page.getData();
return Result.succeed(page.getData());
}
@DeleteMapping("/{id}")
......
......@@ -2,6 +2,7 @@ package com.central.oauth.controller;
import com.central.common.constant.SecurityConstants;
import com.central.common.utils.ResponseUtil;
import com.central.common.utils.TenantContextHolder;
import com.central.oauth2.common.token.MobileAuthenticationToken;
import com.central.oauth2.common.token.OpenIdAuthenticationToken;
import com.central.oauth2.common.util.AuthUtils;
......@@ -90,6 +91,8 @@ public class OAuth2Controller {
String clientSecret = clientInfos[1];
ClientDetails clientDetails = getClient(clientId, clientSecret);
//保存租户id
TenantContextHolder.setTenant(clientId);
TokenRequest tokenRequest = new TokenRequest(MapUtils.EMPTY_MAP, clientId, clientDetails.getScope(), "customer");
OAuth2Request oAuth2Request = tokenRequest.createOAuth2Request(clientDetails);
Authentication authentication = authenticationManager.authenticate(token);
......
......@@ -23,9 +23,9 @@ public class TokensController {
@Autowired
private ITokensService tokensService;
@GetMapping("/list")
@GetMapping("")
@ApiOperation(value = "token列表")
public PageResult<TokenVo> list(@RequestParam Map<String, Object> params, @LoginClient String clientId) {
return tokensService.listTokens(params, clientId);
public PageResult<TokenVo> list(@RequestParam Map<String, Object> params, String tenantId) {
return tokensService.listTokens(params, tenantId);
}
}
......@@ -41,15 +41,13 @@
<if test="params.searchKey != null and params.searchKey != ''">
and client_id like concat('%', #{params.searchKey}, '%')
</if>
</where>
</sql>
<select id="findList" resultType="com.central.oauth.model.Client">
select id , client_id, client_name , resource_ids ,
client_secret ,
client_secret_str ,
web_server_redirect_uri from oauth_client_details t
select id, client_id, client_name, resource_ids
, client_secret, client_secret_str, web_server_redirect_uri
from oauth_client_details
<include refid="where"/>
</select>
</mapper>
\ No newline at end of file
......@@ -87,7 +87,7 @@
data: obj.field,
type: 'POST',
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Basic ' + window.btoa("webApp:webApp"));
xhr.setRequestHeader('Authorization', 'Basic ' + window.btoa(config.clientId + ":" + config.clientSecret));
},
success: function (data) {
//console.log(JSON.stringify(data));
......
......@@ -18,6 +18,8 @@ layui.define(function (exports) {
var config = {
base_server: apiUrl,
tableName: 'easyweb', // 存储表名
clientId: 'webApp', // 应用id
clientSecret: 'webApp', // 应用秘钥
autoRender: false, // 窗口大小改变后是否自动重新渲染表格,解决layui数据表格非响应式的问题,目前实现的还不是很好,暂时关闭该功能
pageTabs: true, // 是否开启多标签
// 获取缓存的token
......
......@@ -8,7 +8,8 @@
</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
搜索:<input id="menus-edit-search" class="layui-input search-input" type="text" placeholder="输入关键字"/>&emsp;
所属应用:<select id="menu_clients" lay-filter="menu_clients"></select>
&emsp;搜索:<input id="menus-edit-search" class="layui-input search-input" type="text" placeholder="输入关键字"/>&emsp;
<button id="menus-btn-search" class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜索</button>
<button id="menus-btn-add" class="layui-btn icon-btn"><i class="layui-icon">&#xe654;</i>添加</button>
<button id="menus-btn-expand" class="layui-btn">全部展开</button>
......@@ -30,14 +31,22 @@
<script>
layui.use(['form', 'table', 'util', 'config', 'admin', 'formSelects', 'treetable'],function () {
var table = layui.table;
var layer = layui.layer;
var admin = layui.admin;
var treetable = layui.treetable;
var config = layui.config;
let table = layui.table;
let layer = layui.layer;
let admin = layui.admin;
let treetable = layui.treetable;
let config = layui.config;
let form = layui.form;
// 渲染表格
var renderTable = function () {
var renderTable = function (param) {
if (param) {
param.access_token = config.getToken().access_token;
} else {
param = {
access_token: config.getToken().access_token
};
}
treetable.render({
treeColIndex: 1,
treeSpid: -1,
......@@ -45,9 +54,7 @@
treePidName: 'parentId',
elem: '#menus-table',
url: config.base_server + 'api-user/menus/findAlls',
where: {
access_token: config.getToken().access_token
},
where: param,
page: false,
cols: [[
{type: 'numbers'},
......@@ -58,10 +65,10 @@
{field: 'sort', width: 80, align: 'center', title: '排序号'},
{
field: 'type', width: 80, align: 'center', templet: function (d) {
if (d.type == 2) {
if (d.type === 2) {
return '<span class="layui-badge layui-bg-gray">资源</span>';
}
if (d.parentId == -1) {
if (d.parentId === -1) {
return '<span class="layui-badge layui-bg-blue">目录</span>';
} else {
return '<span class="layui-badge-rim">菜单</span>';
......@@ -72,8 +79,28 @@
]]
});
};
renderTable();
renderTable({tenantId: config.clientId});
// 获取应用列表
layer.load(2);
admin.req('api-uaa/clients/all', {}, function (data) {
layer.closeAll('loading');
if (0 === data.resp_code) {
let selected = false;
$.each(data.datas,function(index,item){
if (config.clientId === item.clientId) {
selected = true;
} else {
selected = false;
}
//往下拉菜单里添加元素
$('#menu_clients').append(new Option(item.clientName, item.clientId, false, selected));
})
form.render();
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
}, 'GET');
// 工具条点击事件
table.on('tool(menus-table)', function (obj) {
......@@ -85,38 +112,40 @@
} else if (layEvent === 'del') {
layer.confirm('确定删除此菜单吗?', function () {
layer.load(2);
admin.req('api-user/menus/'+obj.data.id, {}, function (data) {
let tenantId = $('#menu_clients').val();
admin.req('api-user/menus/'+obj.data.id+'?tenantId='+tenantId, {}, function (data) {
layer.closeAll('loading');
if (0 == data.resp_code) {
if (0 === data.resp_code) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
renderTable();
renderTable({tenantId: tenantId});
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
}, 'DELETE');
});
}
});
// 显示编辑弹窗
var showEditModel = function (data) {
let tenantId = $('#menu_clients').val();
let title = data ? '修改菜单' : '添加菜单';
if (data){
data.type = data.type.toString();
data.hidden = data.hidden.toString();
} else {
data = {};
}
var title = data ? '修改菜单' : '添加菜单';
data.tenantId = tenantId;
admin.putTempData('t_menus', data);
admin.popupCenter({
title: title,
path: 'pages/system/menus_form.html',
finish: function () {
renderTable();
renderTable({tenantId: tenantId});
}
});
};
// 添加按钮点击事件
......@@ -131,16 +160,16 @@
$('#menus-table').next('.treeTable').find('.layui-table-body tbody tr td').each(function () {
$(this).css('background-color', 'transparent');
var text = $(this).text();
if (keyword != '' && text.indexOf(keyword) >= 0) {
if (keyword !== '' && text.indexOf(keyword) >= 0) {
$(this).css('background-color', 'rgba(250,230,160,0.5)');
if (searchCount == 0) {
if (searchCount === 0) {
$('.layui-tab-item.layui-show').stop(true);
$('.layui-tab-item.layui-show').animate({scrollTop: $(this).offset().top - 150}, 500);
}
searchCount++;
}
});
if (keyword != '' && searchCount == 0) {
if (keyword !== '' && searchCount === 0) {
layer.msg("没有匹配结果", {icon: 5, time: 500});
} else {
treetable.expandAll('#menus-table');
......@@ -154,5 +183,10 @@
$('#menus-btn-fold').click(function () {
treetable.foldAll('#menus-table');
});
// 应用下来框点击事件
form.on('select(menu_clients)', function(data){
renderTable({tenantId: data.value});
});
});
</script>
\ No newline at end of file
......@@ -95,16 +95,16 @@
form.render('select', 'menus-form');
};
// 回显menu数据
let menus = admin.getTempData('t_menus');
// 获取一级菜单
layer.load(2);
admin.req('api-user/menus/findOnes', {}, function (data) {
admin.req('api-user/menus/findOnes', {tenantId: menus.tenantId}, function (data) {
layer.closeAll('loading');
if (0 == data.code) {
$.each(data.data,function(index,item){
$('#parentId').append(new Option(item.name,item.id));//往下拉菜单里添加元素
})
// 回显menu数据
var menus = admin.getTempData('t_menus');
$('#menus-form').attr('method', 'POST');
if (menus) {
form.val('menus-form', menus);
......@@ -119,8 +119,8 @@
// 表单提交事件
form.on('submit(menus-form-submit)', function (data) {
layer.load(2);
admin.req('api-user/menus/saveOrUpdate', JSON.stringify(data.field), function (data) {
if (data.resp_code == 0) {
admin.req('api-user/menus/saveOrUpdate?tenantId='+menus.tenantId, JSON.stringify(data.field), function (data) {
if (data.resp_code === 0) {
layer.closeAll('loading');
layer.msg(data.resp_msg, {icon: 1, time: 500});
admin.finishPopupCenter();
......
......@@ -10,7 +10,8 @@
</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
搜索:
所属应用:<select id="role_clients" lay-filter="role_clients"></select>
&emsp;搜索:
<select id="role-search-key">
<option value="">-请选择-</option>
<option value="name">角色名称</option>
......@@ -87,6 +88,27 @@
]]
});
// 获取应用列表
layer.load(2);
admin.req('api-uaa/clients/all', {}, function (data) {
layer.closeAll('loading');
if (0 === data.resp_code) {
let selected = false;
$.each(data.datas,function(index,item){
if (config.clientId === item.clientId) {
selected = true;
} else {
selected = false;
}
//往下拉菜单里添加元素
$('#role_clients').append(new Option(item.clientName, item.clientId, false, selected));
})
form.render();
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
}, 'GET');
// 添加按钮点击事件
$('#role-btn-add').click(function () {
showEditModel();
......@@ -94,11 +116,12 @@
// 表单提交事件
form.on('submit(role-form-submit)', function (data) {
let tenantId = $('#role_clients').val();
layer.load(2);
admin.req('api-user/roles/saveOrUpdate', JSON.stringify(data.field), function (data) {
admin.req('api-user/roles/saveOrUpdate?tenantId='+tenantId, JSON.stringify(data.field), function (data) {
layer.closeAll('loading');
console.log(data);
if (data.resp_code == 0) {
if (data.resp_code === 0) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
table.reload('role-table');
layer.closeAll('page');
......@@ -152,11 +175,12 @@
// 删除
var doDelete = function (obj) {
layer.confirm('确定要删除吗?', function (i) {
let tenantId = $('#role_clients').val();
layer.close(i);
layer.load(2);
admin.req('api-user/roles/' + obj.data.id, {}, function (data) {
admin.req('api-user/roles/' + obj.data.id+'?tenantId='+tenantId, {}, function (data) {
layer.closeAll('loading');
if (data.resp_code == 0) {
if (data.resp_code === 0) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
obj.del();
} else {
......@@ -169,6 +193,7 @@
// 菜单管理
var showMenuDialog = function (roleId) {
let tenantId = $('#role_clients').val();
layer.open({
type: 1,
title: '菜单管理',
......@@ -188,7 +213,7 @@
}
}
};
admin.req('api-user/menus/'+roleId+'/menus', {}, function (data) {
admin.req('api-user/menus/'+roleId+'/menus', {tenantId: tenantId}, function (data) {
$.fn.zTree.init($('#treeMenu'), setting, data);
layer.closeAll('loading');
}, 'GET');
......@@ -206,7 +231,7 @@
data.roleId = roleId;
data.menuIds = ids;
admin.req('api-user/menus/granted', JSON.stringify(data) , function (data) {
admin.req('api-user/menus/granted?tenantId='+tenantId, JSON.stringify(data) , function (data) {
layer.closeAll('loading');
if (0 == data.resp_code) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
......@@ -218,6 +243,11 @@
}
});
}
// 应用下来框点击事件
form.on('select(role_clients)', function(data){
table.reload('role-table', {where: {tenantId: data.value}});
});
});
</script>
\ No newline at end of file
<!DOCTYPE html>
<html class="bg-white">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>角色权限分配</title>
<base href="${ctxPath}">
<link rel="stylesheet" href="/assets/libs/layui/css/layui.css"/>
<link rel="stylesheet" href="/assets/css/admin.css"/>
<link rel="stylesheet" href="/assets/libs/zTree/css/zTreeStyle/zTreeStyle.css"/>
</head>
<body>
<div style="height: 350px;overflow-y: auto;overflow-x: hidden;">
<input id="roleId" type="hidden" value="${roleId}">
<ul id="treeAuth" class="ztree" style="padding: 20px 0px 20px 40px;"></ul>
</div>
<div class="text-right" style="padding-top: 10px;padding-right: 25px;">
<button class="layui-btn layui-btn-primary" ew-event="closeDialog">取消</button>
<button id="btnSave" class="layui-btn">保存</button>
</div>
<!-- js部分 -->
<script type="text/javascript" src="/assets/libs/jquery/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="/assets/libs/layui/layui.js"></script>
<script type="text/javascript" src="/assets/libs/zTree/js/jquery.ztree.all-3.5.min.js"></script>
<script type="text/javascript" src="/assets/js/common.js"></script>
<script>
layui.use(['layer', 'admin'], function () {
var $ = layui.jquery;
var layer = layui.layer;
var admin = layui.admin;
var roleId = $('#roleId').val();
layer.load(2);
var setting = {
check: {enable: true},
data: {
simpleData: {enable: true}
}
};
$.get('authTree', {
roleId: roleId
}, function (data) {
$.fn.zTree.init($('#treeAuth'), setting, data);
layer.closeAll('loading');
}, 'json');
// 保存按钮点击事件
$('#btnSave').click(function () {
layer.load(2);
var treeObj = $.fn.zTree.getZTreeObj('treeAuth');
var nodes = treeObj.getCheckedNodes(true);
var ids = new Array();
for (var i = 0; i < nodes.length; i++) {
ids[i] = nodes[i].id;
}
$.post('updateRoleAuth', {
roleId: roleId,
authIds: JSON.stringify(ids)
}, function (data) {
layer.closeAll('loading');
if (200 == data.code) {
top.layer.msg(data.msg, {icon: 1});
// 关闭当前iframe弹出层
parent.layer.close(parent.layer.getFrameIndex(window.name));
} else {
top.layer.msg(data.msg, {icon: 2});
}
}, 'json');
});
});
</script>
</body>
</html>
\ No newline at end of file
<!-- role表单弹窗 -->
<form id="role-form" lay-filter="role-form" class="layui-form model-form">
<input name="id" type="hidden"/>
<div class="layui-form-item">
<label class="layui-form-label">权限</label>
<div class="layui-input-block">
<select name="roleIds" xm-select="roleIds" lay-verify="required">
</select>
</div>
</div>
<div class="layui-form-item model-form-footer">
<button class="layui-btn layui-btn-primary" ew-event="closeDialog" type="button">取消</button>
<button class="layui-btn" lay-filter="role-form-submit" lay-submit>保存</button>
</div>
</form>
<script>
layui.use(['layer', 'admin', 'form', 'formSelects'], function () {
var layer = layui.layer;
var admin = layui.admin;
var form = layui.form;
var formSelects = layui.formSelects;
var role = admin.getTempData('t_role');
// 获取所有权限
layer.load(2);
admin.req('api-user/permissions/'+role.id+'/permissions', {}, function (data) {
layer.closeAll('loading');
var roleSelectData = new Array();
for (var i = 0; i < data.length; i++) {
roleSelectData.push({name: data[i].name, value: data[i].id});
}
formSelects.data('roleIds', 'local', {arr: roleSelectData});
// 回显user数据
$('#role-form').attr('method', 'POST');
form.val('role-form', role);
var rds = new Array();
for (var i = 0; i < data.length; i++) {
if (data[i].checked){
rds.push(data[i].id);
}
}
formSelects.value('roleIds', rds);
}, 'GET');
// 表单提交事件
form.on('submit(role-form-submit)', function (data) {
layer.load(2);
data.roleId = data.field.id;
data.authIds = data.field.roleIds.split(",");
console.log(data);
admin.req('api-user/permissions/granted', JSON.stringify(data), function (data) {
layer.closeAll('loading');
if (data.resp_code == 0) {
layer.msg(data.resp_msg, {icon: 1, time: 500});
admin.finishPopupCenter();
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
}, $('#role-form').attr('method'));
return false;
});
});
</script>
\ No newline at end of file
......@@ -8,7 +8,8 @@
</div>
<div class="layui-card-body">
<div class="layui-form toolbar">
搜索:<input id="tokens-edit-search" class="layui-input search-input" type="text" placeholder="输入用户名"/>&emsp;
所属应用:<select id="token_clients" lay-filter="token_clients"></select>
&emsp;搜索:<input id="tokens-edit-search" class="layui-input search-input" type="text" placeholder="输入用户名"/>&emsp;
<button id="tokens-btn-search" class="layui-btn icon-btn"><i class="layui-icon">&#xe615;</i>搜索</button>
</div>
......@@ -23,19 +24,21 @@
</script>
<script>
layui.use(['table', 'util', 'config', 'admin'],function () {
layui.use(['form', 'table', 'util', 'config', 'admin'],function () {
let table = layui.table;
let config = layui.config;
let layer = layui.layer;
let util = layui.util;
let admin = layui.admin;
let form = layui.form;
// 渲染表格
table.render({
elem: '#tokens-table',
url: config.base_server + 'api-uaa/tokens/list',
url: config.base_server + 'api-uaa/tokens',
method: 'GET',
headers:{'Authorization': 'bearer ' + config.getToken().access_token},
where: {tenantId: config.clientId},
page: true,
cols: [[
{type: 'numbers'},
......@@ -52,6 +55,27 @@
]]
});
// 获取应用列表
layer.load(2);
admin.req('api-uaa/clients/all', {}, function (data) {
layer.closeAll('loading');
if (0 === data.resp_code) {
let selected = false;
$.each(data.datas,function(index,item){
if (config.clientId === item.clientId) {
selected = true;
} else {
selected = false;
}
//往下拉菜单里添加元素
$('#token_clients').append(new Option(item.clientName, item.clientId, false, selected));
})
form.render();
} else {
layer.msg(data.resp_msg, {icon: 2, time: 500});
}
}, 'GET');
// 工具条点击事件
table.on('tool(tokens-table)', function (obj) {
if (obj.event === 'del') { // 删除
......@@ -75,7 +99,12 @@
// 搜索按钮点击事件
$('#tokens-btn-search').click(function () {
var key = $('#tokens-edit-search').val();
table.reload('tokens-table', {where: {username: key}});
table.reload('tokens-table', {where: {username: key, tenantId: $('#token_clients').val()}});
});
// 应用下来框点击事件
form.on('select(token_clients)', function(data){
table.reload('tokens-table', {where: {tenantId: data.value}});
});
});
</script>
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册