This commit is contained in:
阿沐 2022-04-22 15:26:39 +08:00
commit 98e9f73313
169 changed files with 7445 additions and 0 deletions

27
.gitignore vendored Normal file
View File

@ -0,0 +1,27 @@
# Compiled class file
*.class
# Log file
logs/
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
.idea
*.iml
*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
target/
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 MAKU
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

24
README.md Normal file
View File

@ -0,0 +1,24 @@
## 简介
**FastBoot**是采用SpringBoot、SpringSecurity、Mybatis-Plus等框架开发的一套企业级脚手架系统使用门槛极低且采用MIT开源协议完全免费开源可免费用于**商业项目**等场景。
## 使命
致力于打造成一套高质量、低BUG、易于上手、可维护性强的低代码开发脚手架系统。
## 软件需求
- JDK1.8
- MySQL8.0
- Maven3.0+
- Redis3.0+
## 环境搭建
- 下载项目源码一般通过git clone命令
- idea、eclipse需安装lombok插件不然会提示找不到get set方法
- 创建数据库fast_boot数据库编码为utf8mb4
- 执行db/mysql.sql文件初始化数据库脚本
- 修改application-dev.yml文件配置MySQL、Redis账号信息
- 在fast-boot目录下执行mvn clean install
## 本地启动
- 在fast-server工程里面运行ServerApplication.java则可启动项目
- 接口文档路径http://localhost:8080/doc.html
- 账号密码admin/admin

213
db/mysql.sql Normal file
View File

@ -0,0 +1,213 @@
CREATE TABLE sys_user
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
username varchar(50) NOT NULL COMMENT '用户名',
password varchar(100) COMMENT '密码',
real_name varchar(50) COMMENT '姓名',
avatar varchar(200) COMMENT '头像',
gender tinyint COMMENT '性别 0男 1',
email varchar(100) COMMENT '邮箱',
mobile varchar(20) COMMENT '手机号',
org_id bigint COMMENT '机构ID',
super_admin tinyint COMMENT '超级管理员 0否 1',
status tinyint COMMENT '状态 0停用 1正常',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARSET = utf8mb4 COMMENT ='用户管理';
CREATE TABLE sys_org
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
pid bigint COMMENT '上级ID',
name varchar(50) COMMENT '机构名称',
sort int COMMENT '排序',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_pid (pid)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARSET = utf8mb4 COMMENT ='机构管理';
create table sys_role
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
name varchar(50) COMMENT '角色名称',
remark varchar(100) COMMENT '备注',
data_scope tinyint COMMENT '数据范围 0全部数据 1本部门及子部门数据 2本部门数据 3本人数据 4自定义数据',
org_id bigint COMMENT '机构ID',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_org_id (org_id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色管理';
create table sys_user_role
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
role_id bigint COMMENT '角色ID',
user_id bigint COMMENT '用户ID',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_role_id (role_id),
key idx_user_id (user_id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='用户角色关系';
CREATE TABLE sys_post
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
post_code varchar(100) COMMENT '岗位编码',
post_name varchar(100) COMMENT '岗位名称',
sort int COMMENT '排序',
status tinyint COMMENT '状态 0停用 1正常',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='岗位管理';
CREATE TABLE sys_user_post
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
user_id bigint COMMENT '用户ID',
post_id bigint COMMENT '岗位ID',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_user_id (user_id),
key idx_post_id (post_id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='用户岗位关系';
create table sys_menu
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
pid bigint COMMENT '上级ID一级菜单为0',
name varchar(200) COMMENT '菜单名称',
url varchar(200) COMMENT '菜单URL',
authority varchar(500) COMMENT '授权标识(多个用逗号分隔sys:menu:list,sys:menu:save)',
type tinyint COMMENT '类型 0菜单 1按钮 2接口',
open_style tinyint COMMENT '打开方式 0内部 1外部',
icon varchar(50) COMMENT '菜单图标',
sort int COMMENT '排序',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_pid (pid)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='菜单管理';
create table sys_role_menu
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
role_id bigint COMMENT '角色ID',
menu_id bigint COMMENT '菜单ID',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_role_id (role_id),
key idx_menu_id (menu_id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色菜单关系';
create table sys_role_data_scope
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
role_id bigint COMMENT '角色ID',
org_id bigint COMMENT '机构ID',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id),
key idx_role_id (role_id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='角色数据权限';
CREATE TABLE sys_oauth_client (
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
client_id varchar(256) NOT NULL COMMENT '客户端id',
client_secret varchar(256) COMMENT '客户端密钥',
resource_ids varchar(256) COMMENT '资源ids',
scope varchar(256) COMMENT '授权范围',
authorized_grant_types varchar(256) COMMENT '授权类型',
web_server_redirect_uri varchar(256) COMMENT '回调地址',
authorities varchar(256) COMMENT '权限标识',
access_token_validity int COMMENT '访问令牌有效期',
refresh_token_validity int COMMENT '刷新令牌有效期',
additional_information varchar(4096) COMMENT '附加信息',
autoapprove varchar(128) COMMENT '自动授权',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COMMENT='客户端管理';
create table sys_dict_type
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
dict_type varchar(100) NOT NULL COMMENT '字典类型',
dict_name varchar(255) NOT NULL COMMENT '字典名称',
remark varchar(255) COMMENT '备注',
sort int COMMENT '排序',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='字典类型';
create table sys_dict_data
(
id bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
dict_type_id bigint NOT NULL COMMENT '字典类型ID',
dict_label varchar(255) NOT NULL COMMENT '字典标签',
dict_value varchar(255) COMMENT '字典值',
remark varchar(255) COMMENT '备注',
sort int COMMENT '排序',
version int COMMENT '版本号',
deleted tinyint COMMENT '删除标识 0正常 1已删除',
creator bigint COMMENT '创建者',
create_time datetime COMMENT '创建时间',
updater bigint COMMENT '更新者',
update_time datetime COMMENT '更新时间',
primary key (id)
) ENGINE = InnoDB AUTO_INCREMENT = 10000 DEFAULT CHARACTER SET utf8mb4 COMMENT ='字典数据';
INSERT INTO sys_user (id, username, password, real_name, gender, email, mobile, status, org_id, super_admin, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'admin', '$2a$10$XCoT1x7oMt97bBVpz5fCz.AtsDm3WUliBO//FA61CHQM7wnicC6GK', 'admin', 0, 'babamu@126.com', '13612345678', 1, null, 1, 0, 0, 10000, now(), 10000, now());
INSERT INTO sys_oauth_client (id, client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove, version, deleted, creator, create_time, updater, update_time) VALUES (10000, 'web', '123456', '', 'all', '["authorization_code","password","implicit","client_credentials","refresh_token"]', 'https://gitee.com/makunet', NULL, 43200, 604800, NULL, 'true', 0, 0, 10000, now(), 10000, now());

View File

@ -0,0 +1,19 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>net.maku</groupId>
<artifactId>fast-boot</artifactId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fast-boot-framework</artifactId>
<packaging>jar</packaging>
<properties>
</properties>
<dependencies>
</dependencies>
</project>

View File

@ -0,0 +1,25 @@
package net.maku.framework.common.constant;
/**
* 常量
*
* @author 阿沐 babamu@126.com
*/
public interface Constant {
/**
* 根节点标识
*/
Long ROOT = 0L;
/**
* 当前页码
*/
String PAGE = "page";
/**
* 数据权限
*/
String DATA_SCOPE = "dataScope";
/**
* 超级管理员
*/
Integer SUPER_ADMIN = 1;
}

View File

@ -0,0 +1,13 @@
package net.maku.framework.common.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 基础Dao
*
* @author 阿沐 babamu@126.com
*/
public interface BaseDao<T> extends BaseMapper<T> {
}

View File

@ -0,0 +1,58 @@
package net.maku.framework.common.entity;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.util.Date;
/**
* Entity基类
*
* @author 阿沐 babamu@126.com
*/
@Data
public abstract class BaseEntity {
/**
* id
*/
@TableId
private Long id;
/**
* 创建者
*/
@TableField(fill = FieldFill.INSERT)
private Long creator;
/**
* 创建时间
*/
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/**
* 更新者
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Long updater;
/**
* 更新时间
*/
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/**
* 版本号
*/
@Version
@TableField(fill = FieldFill.INSERT)
private Integer version;
/**
* 删除标记
*/
@TableLogic
@TableField(fill = FieldFill.INSERT)
private Integer deleted;
}

View File

@ -0,0 +1,21 @@
package net.maku.framework.common.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 错误编码
*
* @author 阿沐 babamu@126.com
*/
@Getter
@AllArgsConstructor
public enum ErrorCode {
UNAUTHORIZED(401, "未授权,不能访问"),
FORBIDDEN(403, "没权限,禁止访问"),
INTERNAL_SERVER_ERROR(500, "服务器异常,请稍后再试"),
ACCOUNT_PASSWORD_ERROR(1001, "账号或密码错误");
private final int code;
private final String msg;
}

View File

@ -0,0 +1,37 @@
package net.maku.framework.common.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 自定义异常
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class FastException extends RuntimeException {
private static final long serialVersionUID = 1L;
private int code;
private String msg;
public FastException(String msg) {
super(msg);
this.code = ErrorCode.INTERNAL_SERVER_ERROR.getCode();
this.msg = msg;
}
public FastException(ErrorCode errorCode) {
super(errorCode.getMsg());
this.code = errorCode.getCode();
this.msg = errorCode.getMsg();
}
public FastException(String msg, Throwable e) {
super(msg, e);
this.code = ErrorCode.INTERNAL_SERVER_ERROR.getCode();
this.msg = msg;
}
}

View File

@ -0,0 +1,51 @@
package net.maku.framework.common.exception;
import lombok.extern.slf4j.Slf4j;
import net.maku.framework.common.utils.Result;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* 异常处理器
*
* @author 阿沐 babamu@126.com
*/
@Slf4j
@RestControllerAdvice
public class FastExceptionHandler {
/**
* 处理自定义异常
*/
@ExceptionHandler(FastException.class)
public Result<String> handleRenException(FastException ex){
return Result.error(ex.getCode(), ex.getMsg());
}
/**
* SpringMVC参数绑定Validator校验不正确
*/
@ExceptionHandler(BindException.class)
public Result<String> bindException(BindException ex) {
FieldError fieldError = ex.getFieldError();
assert fieldError != null;
return Result.error(fieldError.getDefaultMessage());
}
@ExceptionHandler(AccessDeniedException.class)
public Result<String> handleAccessDeniedException(Exception ex){
return Result.error(ErrorCode.FORBIDDEN);
}
@ExceptionHandler(Exception.class)
public Result<String> handleException(Exception ex){
return Result.error(ex.getMessage());
}
}

View File

@ -0,0 +1,52 @@
package net.maku.framework.common.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import org.apache.ibatis.reflection.MetaObject;
import java.util.Date;
/**
* mybatis-plus 自动填充字段
*
* @author 阿沐 babamu@126.com
*/
public class FieldMetaObjectHandler implements MetaObjectHandler {
private final static String CREATE_TIME = "createTime";
private final static String CREATOR = "creator";
private final static String UPDATE_TIME = "updateTime";
private final static String UPDATER = "updater";
private final static String ORG_ID = "orgId";
private final static String VERSION = "version";
private final static String DELETED = "deleted";
@Override
public void insertFill(MetaObject metaObject) {
UserDetail user = SecurityUser.getUser();
Date date = new Date();
// 创建者
strictInsertFill(metaObject, CREATOR, Long.class, user.getId());
// 创建时间
strictInsertFill(metaObject, CREATE_TIME, Date.class, date);
// 更新者
strictInsertFill(metaObject, UPDATER, Long.class, user.getId());
// 更新时间
strictInsertFill(metaObject, UPDATE_TIME, Date.class, date);
// 创建者所属机构
strictInsertFill(metaObject, ORG_ID, Long.class, user.getOrgId());
// 版本号
strictInsertFill(metaObject, VERSION, Integer.class, 0);
// 删除标识
strictInsertFill(metaObject, DELETED, Integer.class, 0);
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新者
strictUpdateFill(metaObject, UPDATER, Long.class, SecurityUser.getUserId());
// 更新时间
strictUpdateFill(metaObject, UPDATE_TIME, Date.class, new Date());
}
}

View File

@ -0,0 +1,16 @@
package net.maku.framework.common.interceptor;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* 数据范围
*
* @author 阿沐 babamu@126.com
*/
@Data
@AllArgsConstructor
public class DataScope {
private String sqlFilter;
}

View File

@ -0,0 +1,81 @@
package net.maku.framework.common.interceptor;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.extension.plugins.inner.InnerInterceptor;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import java.util.Map;
/**
* 数据权限
*
* @author 阿沐 babamu@126.com
*/
public class DataScopeInnerInterceptor implements InnerInterceptor {
@Override
public void beforeQuery(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
DataScope scope = getDataScope(parameter);
// 不进行数据过滤
if(scope == null || StrUtil.isBlank(scope.getSqlFilter())){
return;
}
// 拼接新SQL
String buildSql = getSelect(boundSql.getSql(), scope);
// 重写SQL
PluginUtils.mpBoundSql(boundSql).sql(buildSql);
}
private DataScope getDataScope(Object parameter){
if (parameter == null){
return null;
}
// 判断参数里是否有DataScope对象
if (parameter instanceof Map) {
Map<?, ?> parameterMap = (Map<?, ?>) parameter;
for (Map.Entry entry : parameterMap.entrySet()) {
if (entry.getValue() != null && entry.getValue() instanceof DataScope) {
return (DataScope) entry.getValue();
}
}
} else if (parameter instanceof DataScope) {
return (DataScope) parameter;
}
return null;
}
private String getSelect(String buildSql, DataScope scope){
try {
Select select = (Select) CCJSqlParserUtil.parse(buildSql);
PlainSelect plainSelect = (PlainSelect) select.getSelectBody();
Expression expression = plainSelect.getWhere();
if(expression == null){
plainSelect.setWhere(new StringValue(scope.getSqlFilter()));
}else{
AndExpression andExpression = new AndExpression(expression, new StringValue(scope.getSqlFilter()));
plainSelect.setWhere(andExpression);
}
return select.toString().replaceAll("'", "");
}catch (JSQLParserException e){
return buildSql;
}
}
}

View File

@ -0,0 +1,34 @@
package net.maku.framework.common.page;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
*
* @author 阿沐 babamu@126.com
*/
@Data
@Schema(name = "分页数据")
public class PageResult<T> implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(name = "总记录数")
private int total;
@Schema(name = "列表数据")
private List<T> list;
/**
* 分页
* @param list 列表数据
* @param total 总记录数
*/
public PageResult(List<T> list, long total) {
this.list = list;
this.total = (int)total;
}
}

View File

@ -0,0 +1,32 @@
package net.maku.framework.common.query;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
/**
* 查询公共参数
*
* @author 阿沐 babamu@126.com
*/
@Data
public class Query {
@NotNull(message = "页码不能为空")
@Min(value = 1, message = "页码最小值为 1")
@Schema(name = "当前页码", required = true)
Integer page;
@NotNull(message = "每页条数不能为空")
@Range(min = 1, max = 1000, message = "每页条数,取值范围 1-1000")
@Schema(name = "每页条数", required = true)
Integer limit;
@Schema(name = "排序字段")
String order;
@Schema(name = "是否升序")
boolean asc;
}

View File

@ -0,0 +1,13 @@
package net.maku.framework.common.service;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 基础服务接口所有Service接口都要继承
*
* @author 阿沐 babamu@126.com
*/
public interface BaseService<T> extends IService<T> {
}

View File

@ -0,0 +1,100 @@
package net.maku.framework.common.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.maku.framework.common.constant.Constant;
import net.maku.framework.common.interceptor.DataScope;
import net.maku.framework.common.query.Query;
import net.maku.framework.common.service.BaseService;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import java.util.List;
/**
* 基础服务类所有Service都要继承
*
* @author 阿沐 babamu@126.com
*/
public class BaseServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
/**
* 获取分页对象
* @param query 分页参数
*/
protected IPage<T> getPage(Query query) {
Page<T> page = new Page<>(query.getPage(), query.getLimit());
// 排序
if(StringUtils.isNotBlank(query.getOrder())){
if(query.isAsc()) {
return page.addOrder(OrderItem.asc(query.getOrder()));
}else {
return page.addOrder(OrderItem.desc(query.getOrder()));
}
}
return page;
}
/**
* 原生SQL 数据权限
* @param tableAlias 表别名多表关联时需要填写表别名
* @return 返回数据权限
*/
protected DataScope getDataScope(String tableAlias) {
UserDetail user = SecurityUser.getUser();
// 如果是超级管理员则不进行数据过滤
if(user.getSuperAdmin().equals(Constant.SUPER_ADMIN)) {
return null;
}
// 获取表的别名
if(StringUtils.isNotBlank(tableAlias)){
tableAlias += ".";
}
StringBuilder sqlFilter = new StringBuilder();
sqlFilter.append(" (");
// 数据权限范围
List<Long> dataScopeList = user.getDataScopeList();
// 全部数据权限
if (dataScopeList == null){
return null;
}
// 数据过滤
if(dataScopeList.size() > 0){
sqlFilter.append(tableAlias).append("org_id");
sqlFilter.append(" in(").append(StrUtil.join(",", dataScopeList)).append(")");
sqlFilter.append(" or ");
}
// 查询本人数据
sqlFilter.append(tableAlias).append("creator").append("=").append(user.getId());
sqlFilter.append(")");
return new DataScope(sqlFilter.toString());
}
/**
* MyBatis-Plus 数据权限
*/
protected void dataScopeWrapper(QueryWrapper<T> queryWrapper) {
DataScope dataScope = getDataScope(null);
if (dataScope != null){
queryWrapper.apply(dataScope.getSqlFilter());
}
}
}

View File

@ -0,0 +1,32 @@
package net.maku.framework.common.utils;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import net.maku.framework.common.exception.FastException;
/**
* 校验工具类
*
* @author 阿沐 babamu@126.com
*/
public class AssertUtils {
public static void isBlank(String str, String variable) {
if (StrUtil.isBlank(str)) {
throw new FastException(variable + "不能为空");
}
}
public static void isNull(Object object, String variable) {
if (object == null) {
throw new FastException(variable + "不能为空");
}
}
public static void isArrayEmpty(Object[] array, String variable) {
if(ArrayUtil.isEmpty(array)){
throw new FastException(variable + "不能为空");
}
}
}

View File

@ -0,0 +1,56 @@
package net.maku.framework.common.utils;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期处理
*
* @author 阿沐 babamu@126.com
*/
public class DateUtils {
/** 时间格式(yyyy-MM-dd) */
public final static String DATE_PATTERN = "yyyy-MM-dd";
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
/**
* 日期格式化 日期格式为yyyy-MM-dd
* @param date 日期
* @return 返回yyyy-MM-dd格式日期
*/
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
/**
* 日期格式化 日期格式为yyyy-MM-dd
* @param date 日期
* @param pattern 格式DateUtils.DATE_TIME_PATTERN
* @return 返回yyyy-MM-dd格式日期
*/
public static String format(Date date, String pattern) {
if(date != null){
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
/**
* 日期解析
* @param date 日期
* @param pattern 格式DateUtils.DATE_TIME_PATTERN
* @return 返回Date
*/
public static Date parse(String date, String pattern) {
try {
return new SimpleDateFormat(pattern).parse(date);
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -0,0 +1,55 @@
package net.maku.framework.common.utils;
import cn.hutool.core.util.StrUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* Http
*
* @author 阿沐 babamu@126.com
*/
public class HttpContextUtils {
public static HttpServletRequest getHttpServletRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if(requestAttributes == null){
return null;
}
return ((ServletRequestAttributes) requestAttributes).getRequest();
}
public static Map<String, String> getParameterMap(HttpServletRequest request) {
Enumeration<String> parameters = request.getParameterNames();
Map<String, String> params = new HashMap<>();
while (parameters.hasMoreElements()) {
String parameter = parameters.nextElement();
String value = request.getParameter(parameter);
if (StrUtil.isNotBlank(value)) {
params.put(parameter, value);
}
}
return params;
}
public static String getDomain(){
HttpServletRequest request = getHttpServletRequest();
StringBuffer url = request.getRequestURL();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).toString();
}
public static String getOrigin(){
HttpServletRequest request = getHttpServletRequest();
return request.getHeader(HttpHeaders.ORIGIN);
}
}

View File

@ -0,0 +1,68 @@
package net.maku.framework.common.utils;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
/**
* JSON 工具类
*
* @author 阿沐 babamu@126.com
*/
public class JsonUtils {
private static final ObjectMapper objectMapper = new ObjectMapper();
public static String toJsonString(Object object) {
try {
return objectMapper.writeValueAsString(object);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return null;
}
try {
return objectMapper.readValue(text, clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(byte[] bytes, Class<T> clazz) {
if (ArrayUtil.isEmpty(bytes)) {
return null;
}
try {
return objectMapper.readValue(bytes, clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> T parseObject(String text, TypeReference<T> typeReference) {
try {
return objectMapper.readValue(text, typeReference);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static <T> List<T> parseArray(String text, Class<T> clazz) {
if (StrUtil.isEmpty(text)) {
return new ArrayList<>();
}
try {
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,44 @@
package net.maku.framework.common.utils;
/**
* Redis Key管理
*
* @author 阿沐 babamu@126.com
*/
public class RedisKeys {
/**
* 验证码Key
*/
public static String getCaptchaKey(String key) {
return "sys:captcha:" + key;
}
/**
* 授权码Key
*/
public static String getOauthCode(String code) {
return "oauth:code:" + code;
}
/**
* 微信小程序授权key
*
* @param key
* @return
*/
public static String getWxMpAuthKey(String key) {
return "wx:mp:auth:" + key;
}
/**
* 微信小程序授权类型key
*
* @param key
* @return
*/
public static String getWxMpAuthTypeKey(String key) {
return "wx:mp:auth:type:" + key;
}
}

View File

@ -0,0 +1,118 @@
package net.maku.framework.common.utils;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* Redis工具类
*
* @author 阿沐 babamu@126.com
*/
@Component
public class RedisUtils {
@Resource
private RedisTemplate<String, Object> redisTemplate;
/** 默认过期时长为24小时单位秒 */
public final static long DEFAULT_EXPIRE = 60 * 60 * 24L;
/** 过期时长为1小时单位秒 */
public final static long HOUR_ONE_EXPIRE = 60 * 60 * 1L;
/** 过期时长为6小时单位秒 */
public final static long HOUR_SIX_EXPIRE = 60 * 60 * 6L;
/** 不设置过期时长 */
public final static long NOT_EXPIRE = -1L;
public void set(String key, Object value, long expire){
redisTemplate.opsForValue().set(key, value);
if(expire != NOT_EXPIRE){
expire(key, expire);
}
}
public void set(String key, Object value){
set(key, value, DEFAULT_EXPIRE);
}
public Object get(String key, long expire) {
Object value = redisTemplate.opsForValue().get(key);
if(expire != NOT_EXPIRE){
expire(key, expire);
}
return value;
}
public Object get(String key) {
return get(key, NOT_EXPIRE);
}
public void delete(String key) {
redisTemplate.delete(key);
}
public void delete(Collection<String> keys) {
redisTemplate.delete(keys);
}
public Object hGet(String key, String field) {
return redisTemplate.opsForHash().get(key, field);
}
public Map<String, Object> hGetAll(String key){
HashOperations<String, String, Object> hashOperations = redisTemplate.opsForHash();
return hashOperations.entries(key);
}
public void hMSet(String key, Map<String, Object> map){
hMSet(key, map, DEFAULT_EXPIRE);
}
public void hMSet(String key, Map<String, Object> map, long expire){
redisTemplate.opsForHash().putAll(key, map);
if(expire != NOT_EXPIRE){
expire(key, expire);
}
}
public void hSet(String key, String field, Object value) {
hSet(key, field, value, DEFAULT_EXPIRE);
}
public void hSet(String key, String field, Object value, long expire) {
redisTemplate.opsForHash().put(key, field, value);
if(expire != NOT_EXPIRE){
expire(key, expire);
}
}
public void expire(String key, long expire){
redisTemplate.expire(key, expire, TimeUnit.SECONDS);
}
public void hDel(String key, Object... fields){
redisTemplate.opsForHash().delete(key, fields);
}
public void leftPush(String key, Object value){
leftPush(key, value, DEFAULT_EXPIRE);
}
public void leftPush(String key, Object value, long expire){
redisTemplate.opsForList().leftPush(key, value);
if(expire != NOT_EXPIRE){
expire(key, expire);
}
}
public Object rightPop(String key){
return redisTemplate.opsForList().rightPop(key);
}
}

View File

@ -0,0 +1,52 @@
package net.maku.framework.common.utils;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import net.maku.framework.common.exception.ErrorCode;
/**
* 响应数据
*
* @author 阿沐 babamu@126.com
*/
@Data
@Schema(name = "响应")
public class Result<T> {
@Schema(name = "编码", description = "0表示成功其他值表示失败")
private int code = 0;
@Schema(name = "消息内容")
private String msg = "success";
@Schema(name = "响应数据")
private T data;
public static <T> Result<T> ok() {
return ok(null);
}
public static <T> Result<T> ok(T data) {
Result<T> result = new Result<>();
result.setData(data);
return result;
}
public static <T> Result<T> error() {
return error(ErrorCode.INTERNAL_SERVER_ERROR);
}
public static <T> Result<T> error(String msg) {
return error(ErrorCode.INTERNAL_SERVER_ERROR.getCode(), msg);
}
public static <T> Result<T> error(ErrorCode errorCode) {
return error(errorCode.getCode(), errorCode.getMsg());
}
public static <T> Result<T> error(int code, String msg) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMsg(msg);
return result;
}
}

View File

@ -0,0 +1,29 @@
package net.maku.framework.common.utils;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 树节点所有需要实现树节点的都需要继承该类
*
* @author 阿沐 babamu@126.com
*/
@Data
public class TreeNode<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 主键
*/
private Long id;
/**
* 上级ID
*/
private Long pid;
/**
* 子节点列表
*/
private List<T> children = new ArrayList<>();
}

View File

@ -0,0 +1,70 @@
package net.maku.framework.common.utils;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* 树形结构工具类菜单机构等
*
* @author 阿沐 babamu@126.com
*/
public class TreeUtils {
/**
* 根据pid构建树节点
*/
public static <T extends TreeNode> List<T> build(List<T> treeNodes, Long pid) {
// pid不能为空
AssertUtils.isNull(pid, "pid");
List<T> treeList = new ArrayList<>();
for(T treeNode : treeNodes) {
if (pid.equals(treeNode.getPid())) {
treeList.add(findChildren(treeNodes, treeNode));
}
}
return treeList;
}
/**
* 查找子节点
*/
private static <T extends TreeNode> T findChildren(List<T> treeNodes, T rootNode) {
for(T treeNode : treeNodes) {
if(rootNode.getId().equals(treeNode.getPid())) {
rootNode.getChildren().add(findChildren(treeNodes, treeNode));
}
}
return rootNode;
}
/**
* 构建树节点
*/
public static <T extends TreeNode> List<T> build(List<T> treeNodes) {
List<T> result = new ArrayList<>();
// list转map
Map<Long, T> nodeMap = new LinkedHashMap<>(treeNodes.size());
for(T treeNode : treeNodes){
nodeMap.put(treeNode.getId(), treeNode);
}
for(T node : nodeMap.values()) {
T parent = nodeMap.get(node.getPid());
if(parent != null && !(node.getId().equals(parent.getId()))){
parent.getChildren().add(node);
continue;
}
result.add(node);
}
return result;
}
}

View File

@ -0,0 +1,39 @@
package net.maku.framework.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import net.maku.framework.common.handler.FieldMetaObjectHandler;
import net.maku.framework.common.interceptor.DataScopeInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* mybatis-plus 配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
// 数据权限
mybatisPlusInterceptor.addInnerInterceptor(new DataScopeInnerInterceptor());
// 分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
// 乐观锁
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防止全表更新与删除
mybatisPlusInterceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return mybatisPlusInterceptor;
}
@Bean
public FieldMetaObjectHandler fieldMetaObjectHandler(){
return new FieldMetaObjectHandler();
}
}

View File

@ -0,0 +1,47 @@
package net.maku.framework.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
/**
* Redis配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
public class RedisConfig {
@Bean
public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer(){
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
// Key HashKey使用String序列化
template.setKeySerializer(RedisSerializer.string());
template.setHashKeySerializer(RedisSerializer.string());
// Value HashValue使用Jackson2JsonRedisSerializer序列化
template.setValueSerializer(jackson2JsonRedisSerializer());
template.setHashValueSerializer(jackson2JsonRedisSerializer());
template.setConnectionFactory(factory);
return template;
}
}

View File

@ -0,0 +1,43 @@
package net.maku.framework.config;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import org.springdoc.core.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Swagger配置
*
* @author 阿沐 dolinked@qq.com
*/
@Configuration
public class SwaggerConfig{
@Bean
public GroupedOpenApi userApi(){
String[] paths = { "/**" };
String[] packagedToMatch = { "net.maku" };
return GroupedOpenApi.builder().group("FastBoot")
.pathsToMatch(paths)
.packagesToScan(packagedToMatch).build();
}
@Bean
public OpenAPI customOpenAPI() {
Contact contact= new Contact();
contact.setName("阿沐 babamu@126.com");
return new OpenAPI().info(new Info()
.title("FastBoot")
.description( "FastBoot")
.contact(contact)
.version("1.0")
.termsOfService("https://gitee.com/makunet")
.license(new License().name("MIT")
.url("https://gitee.com/makunet")));
}
}

View File

@ -0,0 +1,62 @@
package net.maku.framework.config;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.ResourceHttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
import java.util.TimeZone;
/**
* Web MVC配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.maxAge(3600);
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
converters.add(new ResourceHttpMessageConverter());
converters.add(new AllEncompassingFormHttpMessageConverter());
converters.add(new StringHttpMessageConverter());
converters.add(jackson2HttpMessageConverter());
}
@Bean
public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
ObjectMapper mapper = new ObjectMapper();
// 忽略未知属性
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
// 统一日期格式转换不建议开启
//mapper.setDateFormat(new SimpleDateFormat(DateUtils.DATE_TIME_PATTERN));
mapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
converter.setObjectMapper(mapper);
return converter;
}
}

View File

@ -0,0 +1,74 @@
package net.maku.framework.security.config;
import lombok.AllArgsConstructor;
import net.maku.framework.security.exception.FastWebResponseExceptionTranslator;
import net.maku.framework.security.token.FastTokenEnhancer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* 认证服务器配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
@AllArgsConstructor
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final ClientDetailsService fastClientDetailsService;
private final UserDetailsService userDetailsService;
private final AuthorizationCodeServices redisAuthorizationCodeServices;
private final TokenStore tokenStore;
/**
* 配置客户端信息
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(fastClientDetailsService);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.DELETE);
// 密码模式
endpoints.authenticationManager(authenticationManager);
// 支持刷新令牌
endpoints.userDetailsService(userDetailsService);
// 令牌管理
endpoints.tokenStore(tokenStore);
// 令牌增强
endpoints.tokenEnhancer(tokenEnhancer());
// 登录或者鉴权失败时的返回信息
endpoints.exceptionTranslator(new FastWebResponseExceptionTranslator());
// 配置授权码模式存放在Redis中
endpoints.authorizationCodeServices(redisAuthorizationCodeServices);
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new FastTokenEnhancer();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security
.allowFormAuthenticationForClients()
.tokenKeyAccess("permitAll()") // 匿名可访问/oauth/token_key
.checkTokenAccess("isAuthenticated()") // 认证后可访问/oauth/check_token
;
}
}

View File

@ -0,0 +1,20 @@
package net.maku.framework.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 加密配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
public class PasswordConfig {
@Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}

View File

@ -0,0 +1,46 @@
package net.maku.framework.security.config;
import lombok.AllArgsConstructor;
import net.maku.framework.security.exception.SecurityAuthenticationEntryPoint;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
/**
* 资源服务器配置
*
* @author 阿沐 babamu@126.com
*/
@Configuration
@AllArgsConstructor
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenStore(tokenStore);
resources.authenticationEntryPoint(new SecurityAuthenticationEntryPoint());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.requestMatchers()
// 被保护的资源
.antMatchers("/sys/**", "/wx/mp/**")
.and()
.authorizeRequests()
.anyRequest().authenticated()
;
}
}

View File

@ -0,0 +1,25 @@
package net.maku.framework.security.config;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
/**
* TokenStore
*
* @author 阿沐 babamu@126.com
*/
@Configuration
@AllArgsConstructor
public class TokenStoreConfig {
private final RedisConnectionFactory redisConnectionFactory;
@Bean
public TokenStore tokenStore() {
// 使用redis存储token
return new RedisTokenStore(redisConnectionFactory);
}
}

View File

@ -0,0 +1,61 @@
package net.maku.framework.security.config;
import lombok.AllArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.OncePerRequestFilter;
/**
* Spring Security配置
*
* @author 阿沐 babamu@126.com
*/
@AllArgsConstructor
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
private final OncePerRequestFilter validateCodeFilter;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
/**
* 密码模式需要
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception{
return super.authenticationManager();
}
@Override
public void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
.formLogin()
.loginPage("/login")
.loginProcessingUrl("/login")
.and()
.authorizeRequests()
.antMatchers("/oauth/authorize").authenticated()
.anyRequest().permitAll()
.and().headers().frameOptions().disable()
.and().csrf().disable()
;
}
@Override
public void configure(WebSecurity web) {
web.ignoring().antMatchers(HttpMethod.OPTIONS);
}
}

View File

@ -0,0 +1,18 @@
package net.maku.framework.security.exception;
import org.springframework.security.core.AuthenticationException;
/**
* 认证异常类
*
* @author 阿沐 babamu@126.com
*/
public class FastAuthenticationException extends AuthenticationException {
public FastAuthenticationException(String msg, Throwable t) {
super(msg, t);
}
public FastAuthenticationException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,31 @@
package net.maku.framework.security.exception;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
/**
* 自定义异常
*
* @author 阿沐 babamu@126.com
*/
public class FastOAuth2Exception extends OAuth2Exception {
private String msg;
public FastOAuth2Exception(String msg) {
super(msg);
this.msg = msg;
}
public FastOAuth2Exception(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}

View File

@ -0,0 +1,78 @@
package net.maku.framework.security.exception;
import net.maku.framework.common.exception.ErrorCode;
import net.maku.framework.common.utils.Result;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.DefaultThrowableAnalyzer;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.ClientAuthenticationException;
import org.springframework.security.oauth2.common.exceptions.InsufficientScopeException;
import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.stereotype.Component;
import org.springframework.web.HttpRequestMethodNotSupportedException;
/**
* 登录或者鉴权失败时的返回信息
*
* @author 阿沐 babamu@126.com
*/
@Component
public class FastWebResponseExceptionTranslator implements WebResponseExceptionTranslator<OAuth2Exception> {
private final ThrowableAnalyzer throwableAnalyzer = new DefaultThrowableAnalyzer();
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) {
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
Exception exception = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, causeChain);
if (exception != null) {
return handleOAuth2Exception(new FastOAuth2Exception(e.getMessage(), e));
}
exception = (AccessDeniedException) throwableAnalyzer.getFirstThrowableOfType(AccessDeniedException.class, causeChain);
if (exception != null) {
return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception));
}
exception = (InvalidGrantException) throwableAnalyzer.getFirstThrowableOfType(InvalidGrantException.class, causeChain);
if (exception != null) {
return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception));
}
exception = (HttpRequestMethodNotSupportedException) throwableAnalyzer.getFirstThrowableOfType(HttpRequestMethodNotSupportedException.class, causeChain);
if (exception != null) {
return handleOAuth2Exception(new FastOAuth2Exception(exception.getMessage(), exception));
}
exception = (OAuth2Exception) throwableAnalyzer.getFirstThrowableOfType(OAuth2Exception.class, causeChain);
if (exception != null) {
return handleOAuth2Exception((OAuth2Exception) exception);
}
return handleOAuth2Exception(new FastOAuth2Exception(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase(), e));
}
private ResponseEntity<OAuth2Exception> handleOAuth2Exception(OAuth2Exception e) {
int status = e.getHttpErrorCode();
HttpHeaders headers = new HttpHeaders();
headers.set(HttpHeaders.CACHE_CONTROL, "no-store");
headers.set(HttpHeaders.PRAGMA, "no-cache");
if (status == HttpStatus.UNAUTHORIZED.value() || (e instanceof InsufficientScopeException)) {
headers.set(HttpHeaders.WWW_AUTHENTICATE, String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, e.getSummary()));
}
if (e instanceof ClientAuthenticationException) {
return new ResponseEntity<>(e, headers, HttpStatus.valueOf(status));
}
Result<String> result = Result.error(ErrorCode.ACCOUNT_PASSWORD_ERROR);
return new ResponseEntity(result, headers, HttpStatus.OK);
}
}

View File

@ -0,0 +1,29 @@
package net.maku.framework.security.exception;
import net.maku.framework.common.exception.ErrorCode;
import net.maku.framework.common.utils.HttpContextUtils;
import net.maku.framework.common.utils.JsonUtils;
import net.maku.framework.common.utils.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 匿名用户(token不存在错误)异常处理器
*
* @author 阿沐 babamu@126.com
*/
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
response.setContentType("application/json; charset=utf-8");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
response.getWriter().print(JsonUtils.toJsonString(Result.error(ErrorCode.UNAUTHORIZED)));
}
}

View File

@ -0,0 +1,31 @@
package net.maku.framework.security.handler;
import lombok.SneakyThrows;
import net.maku.framework.common.utils.HttpContextUtils;
import net.maku.framework.common.utils.JsonUtils;
import net.maku.framework.common.utils.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 认证失败处理器
*
* @author 阿沐 babamu@126.com
*/
@Component
public class UserAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@SneakyThrows
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
response.setContentType("application/json;charset=UTF-8");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Origin", HttpContextUtils.getOrigin());
response.getWriter().write(JsonUtils.toJsonString(Result.error(e.getMessage())));
}
}

View File

@ -0,0 +1,34 @@
package net.maku.framework.security.token;
import net.maku.framework.common.utils.Result;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import java.util.HashMap;
import java.util.Map;
/**
* 令牌
*
* @author 阿沐 babamu@126.com
*/
public class FastTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
if(accessToken instanceof DefaultOAuth2AccessToken){
DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;
// 增加额外信息
Map<String, Object> info = new HashMap<>();
info.put("code", new Result<>().getCode());
token.setAdditionalInformation(info);
return token;
}
return accessToken;
}
}

View File

@ -0,0 +1,33 @@
package net.maku.framework.security.user;
import org.springframework.security.core.context.SecurityContextHolder;
/**
* 用户
*
* @author 阿沐 babamu@126.com
*/
public class SecurityUser {
/**
* 获取用户信息
*/
public static UserDetail getUser() {
UserDetail user;
try {
user = (UserDetail)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}catch (Exception e){
return new UserDetail();
}
return user;
}
/**
* 获取用户ID
*/
public static Long getUserId() {
return getUser().getId();
}
}

View File

@ -0,0 +1,84 @@
package net.maku.framework.security.user;
import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
/**
* 登录用户信息
*
* @author 阿沐 babamu@126.com
*/
@Data
public class UserDetail implements UserDetails {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String password;
private String realName;
private String avatar;
private Integer gender;
private String email;
private String mobile;
private Long orgId;
private Integer status;
private Integer superAdmin;
private Date createTime;
/**
* 数据权限范围
*
* null表示全部数据权限
*/
private List<Long> dataScopeList;
/**
* 帐户是否过期
*/
private boolean isAccountNonExpired = true;
/**
* 帐户是否被锁定
*/
private boolean isAccountNonLocked = true;
/**
* 密码是否过期
*/
private boolean isCredentialsNonExpired = true;
/**
* 帐户是否可用
*/
private boolean isEnabled = true;
/**
* 拥有权限集合
*/
private Set<GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
@Override
public boolean isAccountNonExpired() {
return this.isAccountNonExpired;
}
@Override
public boolean isAccountNonLocked() {
return this.isAccountNonLocked;
}
@Override
public boolean isCredentialsNonExpired() {
return this.isCredentialsNonExpired;
}
@Override
public boolean isEnabled() {
return this.isEnabled;
}
}

25
fast-boot-system/pom.xml Normal file
View File

@ -0,0 +1,25 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>net.maku</groupId>
<artifactId>fast-boot</artifactId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>fast-boot-system</artifactId>
<packaging>jar</packaging>
<properties>
</properties>
<dependencies>
<dependency>
<groupId>net.maku</groupId>
<artifactId>fast-boot-framework</artifactId>
<version>1.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,57 @@
package net.maku.security.filter;
import lombok.AllArgsConstructor;
import net.maku.framework.security.handler.UserAuthenticationFailureHandler;
import net.maku.security.service.CaptchaService;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 验证码过滤器
*
* @author 阿沐 babamu@126.com
*/
@Component
@AllArgsConstructor
public class ValidateCodeFilter extends OncePerRequestFilter {
private final static String OAUTH_TOKEN_URL = "/oauth/token";
private final CaptchaService captchaService;
private final UserAuthenticationFailureHandler authenticationFailureHandler;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if(request.getServletPath().equals(OAUTH_TOKEN_URL)
&& request.getMethod().equalsIgnoreCase("POST")
&& "password".equalsIgnoreCase(request.getParameter("grant_type"))) {
try {
// 校验验证码
validate(request);
}catch (AuthenticationException e) {
// 失败处理器
authenticationFailureHandler.onAuthenticationFailure(request, response, e);
return;
}
}
filterChain.doFilter(request, response);
}
private void validate(HttpServletRequest request) {
String key = request.getParameter("key");
String captcha = request.getParameter("captcha");
boolean flag = captchaService.validate(key, captcha);
// if(!flag) {
// throw new FastAuthenticationException("验证码错误");
// }
}
}

View File

@ -0,0 +1,72 @@
package net.maku.security.service;
import cn.hutool.core.util.StrUtil;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.RedisKeys;
import net.maku.framework.common.utils.RedisUtils;
import org.springframework.stereotype.Service;
/**
* 验证码
*
* @author 阿沐 babamu@126.com
*/
@Service
@AllArgsConstructor
public class CaptchaService {
private final RedisUtils redisUtils;
/**
* 生成验证码
* @param key key
* @return 返回base64图片验证码
*/
public String generate(String key) {
// 生成验证码
SpecCaptcha captcha = new SpecCaptcha(150, 40);
captcha.setLen(5);
captcha.setCharType(Captcha.TYPE_DEFAULT);
// 保存到缓存
key = RedisKeys.getCaptchaKey(key);
redisUtils.set(key, captcha.text(), 300);
return captcha.toBase64();
}
/**
* 验证码效验
* @param key key
* @param code 验证码
* @return true成功 false失败
*/
public boolean validate(String key, String code) {
if(StrUtil.isBlank(key) || StrUtil.isBlank(code)){
return false;
}
// 获取验证码
String captcha = getCache(key);
// 效验成功
if(code.equalsIgnoreCase(captcha)){
return true;
}
return false;
}
private String getCache(String key){
key = RedisKeys.getCaptchaKey(key);
String captcha = (String)redisUtils.get(key);
// 删除验证码
if(captcha != null){
redisUtils.delete(key);
}
return captcha;
}
}

View File

@ -0,0 +1,82 @@
package net.maku.security.service;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.JsonUtils;
import net.maku.system.dao.SysOauthClientDao;
import net.maku.system.entity.SysOauthClientEntity;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.Map;
/**
* ClientDetailsService
*
* @author 阿沐 babamu@126.com
*/
@Service
@AllArgsConstructor
public class FastClientDetailsService implements ClientDetailsService {
private final SysOauthClientDao sysOauthClientDao;
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
SysOauthClientEntity oauthClient = sysOauthClientDao.getByClientId(clientId);
return clientDetailsMapper(oauthClient);
}
private ClientDetails clientDetailsMapper(SysOauthClientEntity entity) {
BaseClientDetails client = new BaseClientDetails();
client.setClientId(entity.getClientId());
// 密码前追加 {noop} 前缀表示密码是明文
client.setClientSecret(String.format("{noop}%s", entity.getClientSecret()));
if (ArrayUtil.isNotEmpty(entity.getAuthorizedGrantTypes())) {
client.setAuthorizedGrantTypes(CollUtil.newArrayList(entity.getAuthorizedGrantTypes()));
}
if (StrUtil.isNotBlank(entity.getAuthorities())) {
client.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(entity.getAuthorities()));
}
if (StrUtil.isNotBlank(entity.getResourceIds())) {
client.setResourceIds(StringUtils.commaDelimitedListToSet(entity.getResourceIds()));
}
if (StrUtil.isNotBlank(entity.getWebServerRedirectUri())) {
client.setRegisteredRedirectUri(StringUtils.commaDelimitedListToSet(entity.getWebServerRedirectUri()));
}
if (StrUtil.isNotBlank(entity.getScope())) {
client.setScope(StringUtils.commaDelimitedListToSet(entity.getScope()));
}
if (StrUtil.isNotBlank(entity.getAutoapprove())) {
client.setAutoApproveScopes(StringUtils.commaDelimitedListToSet(entity.getAutoapprove()));
}
if (entity.getAccessTokenValidity() != null) {
client.setAccessTokenValiditySeconds(entity.getAccessTokenValidity());
}
if (entity.getRefreshTokenValidity() != null) {
client.setRefreshTokenValiditySeconds(entity.getRefreshTokenValidity());
}
if (StrUtil.isNotBlank(entity.getAdditionalInformation())) {
Map<String, Object> map = JsonUtils.parseObject(entity.getAdditionalInformation(), Map.class);
client.setAdditionalInformation(map);
}
return client;
}
}

View File

@ -0,0 +1,111 @@
package net.maku.security.service;
import lombok.AllArgsConstructor;
import net.maku.framework.common.exception.ErrorCode;
import net.maku.framework.common.exception.FastException;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.dao.SysRoleDao;
import net.maku.system.dao.SysRoleDataScopeDao;
import net.maku.system.dao.SysUserDao;
import net.maku.system.entity.SysUserEntity;
import net.maku.system.enums.DataScopeEnum;
import net.maku.system.enums.UserStatusEnum;
import net.maku.system.service.SysMenuService;
import net.maku.system.service.SysOrgService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* UserDetailsService
*
* @author 阿沐 babamu@126.com
*/
@Service
@AllArgsConstructor
public class FastUserDetailsService implements UserDetailsService {
private final SysMenuService sysMenuService;
private final SysOrgService sysOrgService;
private final SysUserDao sysUserDao;
private final SysRoleDao sysRoleDao;
private final SysRoleDataScopeDao sysRoleDataScopeDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUserEntity userEntity = sysUserDao.getByUsername(username);
if(userEntity == null) {
throw new FastException(ErrorCode.ACCOUNT_PASSWORD_ERROR);
}
// 转换成UserDetail对象
UserDetail userDetail = SysUserConvert.INSTANCE.convertDetail(userEntity);
// 告诉spring-security密码使用的bcrypt加密
userDetail.setPassword(String.format("{bcrypt}%s", userDetail.getPassword()));
// 账号不可用
if(userEntity.getStatus() == UserStatusEnum.DISABLE.getValue()){
userDetail.setEnabled(false);
}
// 数据权限范围
List<Long> dataScopeList = getDataScope(userDetail);
userDetail.setDataScopeList(dataScopeList);
// 用户权限列表
Set<GrantedAuthority> authorities = getUserAuthority(userDetail);
userDetail.setAuthorities(authorities);
return userDetail;
}
private List<Long> getDataScope(UserDetail userDetail){
Integer dataScope = sysRoleDao.getDataScopeByUserId(userDetail.getId());
if (dataScope == null){
return new ArrayList<>();
}
if (dataScope.equals(DataScopeEnum.ALL.getValue())) {
// 全部数据权限则返回null
return null;
} else if (dataScope.equals(DataScopeEnum.DEPT_AND_CHILD.getValue())) {
// 本部门及子部门数据
List<Long> dataScopeList = sysOrgService.getSubOrgIdList(userDetail.getOrgId());
// 自定义数据权限范围
dataScopeList.addAll(sysRoleDataScopeDao.getDataScopeList(userDetail.getId()));
return dataScopeList;
} else if (dataScope.equals(DataScopeEnum.DEPT_ONLY.getValue())) {
// 本部门数据
List<Long> dataScopeList = new ArrayList<>();
dataScopeList.add(userDetail.getOrgId());
// 自定义数据权限范围
dataScopeList.addAll(sysRoleDataScopeDao.getDataScopeList(userDetail.getId()));
return dataScopeList;
}
return new ArrayList<>();
}
private Set<GrantedAuthority> getUserAuthority(UserDetail user) {
// 获取用户权限标识
Set<String> permsSet = sysMenuService.getUserAuthority(user);
// 封装权限标识
Set<GrantedAuthority> authorities = new HashSet<>();
authorities.addAll(permsSet.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
return authorities;
}
}

View File

@ -0,0 +1,32 @@
package net.maku.security.service;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.RedisKeys;
import net.maku.framework.common.utils.RedisUtils;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.code.RandomValueAuthorizationCodeServices;
import org.springframework.stereotype.Service;
/**
* 基于Redis的授权码模式
*
* @author 阿沐 babamu@126.com
*/
@Service
@AllArgsConstructor
public class RedisAuthorizationCodeServices extends RandomValueAuthorizationCodeServices {
private final RedisUtils redisUtils;
@Override
protected void store(String code, OAuth2Authentication authentication) {
String key = RedisKeys.getOauthCode(code);
redisUtils.set(key, authentication);
}
@Override
public OAuth2Authentication remove(String code) {
String key = RedisKeys.getOauthCode(code);
return (OAuth2Authentication)redisUtils.get(key);
}
}

View File

@ -0,0 +1,77 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.utils.Result;
import net.maku.system.convert.SysDictDataConvert;
import net.maku.system.entity.SysDictDataEntity;
import net.maku.system.service.SysDictDataService;
import net.maku.system.vo.dict.data.SysDictDataPostVO;
import net.maku.system.vo.dict.data.SysDictDataPutVO;
import net.maku.system.vo.dict.data.SysDictDataQuery;
import net.maku.system.vo.dict.data.SysDictDataVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 字典数据
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/dict/data")
@Tag(name="字典数据")
@AllArgsConstructor
public class SysDictDataController {
private final SysDictDataService sysDictDataService;
@GetMapping("page")
@Operation(summary = "分页")
//@PreAuthorize("hasAuthority('sys:dict:page')")
public Result<PageResult<SysDictDataVO>> page(@Valid SysDictDataQuery query){
PageResult<SysDictDataVO> page = sysDictDataService.page(query);
return Result.ok(page);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:dict:info')")
public Result<SysDictDataVO> get(@PathVariable("id") Long id){
SysDictDataEntity entity = sysDictDataService.getById(id);
return Result.ok(SysDictDataConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:dict:save')")
public Result<String> save(@RequestBody @Valid SysDictDataPostVO vo){
sysDictDataService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:dict:update')")
public Result<String> update(@RequestBody @Valid SysDictDataPutVO vo){
sysDictDataService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:dict:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysDictDataService.delete(idList);
return Result.ok();
}
}

View File

@ -0,0 +1,86 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.utils.Result;
import net.maku.system.convert.SysDictTypeConvert;
import net.maku.system.entity.SysDictTypeEntity;
import net.maku.system.service.SysDictTypeService;
import net.maku.system.vo.dict.SysDictVO;
import net.maku.system.vo.dict.type.SysDictTypePostVO;
import net.maku.system.vo.dict.type.SysDictTypePutVO;
import net.maku.system.vo.dict.type.SysDictTypeQuery;
import net.maku.system.vo.dict.type.SysDictTypeVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 字典类型
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/dict/type")
@Tag(name="字典类型")
@AllArgsConstructor
public class SysDictTypeController {
private final SysDictTypeService sysDictTypeService;
@GetMapping("page")
@Operation(summary = "分页")
//@PreAuthorize("hasAuthority('sys:dict:page')")
public Result<PageResult<SysDictTypeVO>> page(@Valid SysDictTypeQuery query){
PageResult<SysDictTypeVO> page = sysDictTypeService.page(query);
return Result.ok(page);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:dict:info')")
public Result<SysDictTypeVO> get(@PathVariable("id") Long id){
SysDictTypeEntity entity = sysDictTypeService.getById(id);
return Result.ok(SysDictTypeConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:dict:save')")
public Result<String> save(@RequestBody @Valid SysDictTypePostVO vo){
sysDictTypeService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:dict:update')")
public Result<String> update(@RequestBody @Valid SysDictTypePutVO vo){
sysDictTypeService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:dict:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysDictTypeService.delete(idList);
return Result.ok();
}
@GetMapping("all")
@Operation(summary = "全部字典数据")
public Result<List<SysDictVO>> all(){
List<SysDictVO> dictList = sysDictTypeService.getDictList();
return Result.ok(dictList);
}
}

View File

@ -0,0 +1,103 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.Result;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.convert.SysMenuConvert;
import net.maku.system.entity.SysMenuEntity;
import net.maku.system.enums.MenuTypeEnum;
import net.maku.system.service.SysMenuService;
import net.maku.system.vo.menu.SysMenuPostVO;
import net.maku.system.vo.menu.SysMenuPutVO;
import net.maku.system.vo.menu.SysMenuVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
import java.util.Set;
/**
* 菜单管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/menu")
@Tag(name="菜单管理")
@AllArgsConstructor
public class SysMenuController {
private final SysMenuService sysMenuService;
@GetMapping("nav")
@Operation(summary = "导航列表")
public Result<List<SysMenuVO>> nav(){
UserDetail user = SecurityUser.getUser();
List<SysMenuVO> list = sysMenuService.getUserMenuList(user, MenuTypeEnum.MENU.getValue());
return Result.ok(list);
}
@GetMapping("authority")
@Operation(summary = "用户权限标识")
public Result<Set<String>> authority(){
UserDetail user = SecurityUser.getUser();
Set<String> set = sysMenuService.getUserAuthority(user);
return Result.ok(set);
}
@GetMapping("list")
@Operation(summary = "菜单列表")
@Parameter(name = "type", description = "菜单类型 0菜单 1按钮 2接口 null全部")
public Result<List<SysMenuVO>> list(Integer type){
List<SysMenuVO> list = sysMenuService.getMenuList(type);
return Result.ok(list);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:menu:info')")
public Result<SysMenuVO> get(@PathVariable("id") Long id){
SysMenuEntity entity = sysMenuService.getById(id);
return Result.ok(SysMenuConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:menu:save')")
public Result<String> save(@RequestBody @Valid SysMenuPostVO vo){
sysMenuService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:menu:update')")
public Result<String> update(@RequestBody @Valid SysMenuPutVO vo){
sysMenuService.update(vo);
return Result.ok();
}
@DeleteMapping("{id}")
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:menu:delete')")
public Result<String> delete(@PathVariable("id") Long id){
// 判断是否有子菜单或按钮
Long count = sysMenuService.getSubMenuCount(id);
if(count > 0){
return Result.error("存在子菜单");
}
sysMenuService.delete(id);
return Result.ok();
}
}

View File

@ -0,0 +1,76 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.query.Query;
import net.maku.framework.common.utils.Result;
import net.maku.system.convert.SysOauthClientConvert;
import net.maku.system.entity.SysOauthClientEntity;
import net.maku.system.service.SysOauthClientService;
import net.maku.system.vo.oauth.SysOauthClientPostVO;
import net.maku.system.vo.oauth.SysOauthClientPutVO;
import net.maku.system.vo.oauth.SysOauthClientVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 客户端管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/client")
@Tag(name="客户端管理")
@AllArgsConstructor
public class SysOauthClientController {
private final SysOauthClientService sysOauthClientService;
@GetMapping("page")
@Operation(summary = "分页")
//@PreAuthorize("hasAuthority('sys:client:page')")
public Result<PageResult<SysOauthClientVO>> page(@Valid Query query){
PageResult<SysOauthClientVO> page = sysOauthClientService.page(query);
return Result.ok(page);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:client:info')")
public Result<SysOauthClientVO> get(@PathVariable("id") Long id){
SysOauthClientEntity entity = sysOauthClientService.getById(id);
return Result.ok(SysOauthClientConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:client:save')")
public Result<String> save(@RequestBody SysOauthClientPostVO vo){
sysOauthClientService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:client:update')")
public Result<String> update(@RequestBody @Valid SysOauthClientPutVO vo){
sysOauthClientService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:client:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysOauthClientService.delete(idList);
return Result.ok();
}
}

View File

@ -0,0 +1,65 @@
package net.maku.system.controller;
import cn.hutool.core.lang.UUID;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.Result;
import net.maku.security.service.CaptchaService;
import org.springframework.http.HttpHeaders;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2RefreshToken;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 认证管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("oauth")
@Tag(name="认证管理")
@AllArgsConstructor
public class SysOauthController {
private final CaptchaService captchaService;
private final TokenStore tokenStore;
@GetMapping("captcha")
@Operation(summary = "验证码")
public Result<Map<String, Object>> captcha() {
// 生成key
String key = UUID.randomUUID().toString();
// 生成base64验证码
String image = captchaService.generate(key);
// 封装返回数据
Map<String, Object> data = new HashMap<>();
data.put("key", key);
data.put("image", image);
return Result.ok(data);
}
@PostMapping("logout")
@Operation(summary = "退出")
public Result<String> logout(HttpServletRequest request) {
String access_token = request.getHeader(HttpHeaders.AUTHORIZATION).replace("Bearer ", "");
OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(access_token);
if (oAuth2AccessToken != null) {
tokenStore.removeAccessToken(oAuth2AccessToken);
OAuth2RefreshToken oAuth2RefreshToken = oAuth2AccessToken.getRefreshToken();
tokenStore.removeRefreshToken(oAuth2RefreshToken);
tokenStore.removeAccessTokenUsingRefreshToken(oAuth2RefreshToken);
}
return Result.ok();
}
}

View File

@ -0,0 +1,75 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.utils.Result;
import net.maku.system.convert.SysOrgConvert;
import net.maku.system.entity.SysOrgEntity;
import net.maku.system.service.SysOrgService;
import net.maku.system.vo.org.SysOrgPostVO;
import net.maku.system.vo.org.SysOrgPutVO;
import net.maku.system.vo.org.SysOrgVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 机构管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/org")
@Tag(name="机构管理")
@AllArgsConstructor
public class SysOrgController {
private final SysOrgService sysOrgService;
@GetMapping("list")
@Operation(summary = "列表")
//@PreAuthorize("hasAuthority('sys:org:list')")
public Result<List<SysOrgVO>> list(){
List<SysOrgVO> list = sysOrgService.getList();
return Result.ok(list);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:org:info')")
public Result<SysOrgVO> get(@PathVariable("id") Long id){
SysOrgEntity entity = sysOrgService.getById(id);
return Result.ok(SysOrgConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:org:save')")
public Result<String> save(@RequestBody @Valid SysOrgPostVO vo){
sysOrgService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:org:update')")
public Result<String> update(@RequestBody @Valid SysOrgPutVO vo){
sysOrgService.update(vo);
return Result.ok();
}
@DeleteMapping("{id}")
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:org:delete')")
public Result<String> delete(@PathVariable("id") Long id){
sysOrgService.delete(id);
return Result.ok();
}
}

View File

@ -0,0 +1,85 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.utils.Result;
import net.maku.system.convert.SysPostConvert;
import net.maku.system.entity.SysPostEntity;
import net.maku.system.service.SysPostService;
import net.maku.system.vo.post.SysPostPostVO;
import net.maku.system.vo.post.SysPostPutVO;
import net.maku.system.vo.post.SysPostQuery;
import net.maku.system.vo.post.SysPostVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 岗位管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/post")
@Tag(name="岗位管理")
@AllArgsConstructor
public class SysPostController {
private final SysPostService sysPostService;
@GetMapping("page")
@Operation(summary = "分页")
//@PreAuthorize("hasAuthority('sys:post:page')")
public Result<PageResult<SysPostVO>> page(@Valid SysPostQuery query){
PageResult<SysPostVO> page = sysPostService.page(query);
return Result.ok(page);
}
@GetMapping("list")
@Operation(summary = "列表")
public Result<List<SysPostVO>> list(){
List<SysPostVO> list = sysPostService.getList();
return Result.ok(list);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:post:info')")
public Result<SysPostVO> get(@PathVariable("id") Long id){
SysPostEntity entity = sysPostService.getById(id);
return Result.ok(SysPostConvert.INSTANCE.convert(entity));
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:post:save')")
public Result<String> save(@RequestBody SysPostPostVO vo){
sysPostService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:post:update')")
public Result<String> update(@RequestBody @Valid SysPostPutVO vo){
sysPostService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:post:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysPostService.delete(idList);
return Result.ok();
}
}

View File

@ -0,0 +1,116 @@
package net.maku.system.controller;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.utils.Result;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.convert.SysRoleConvert;
import net.maku.system.entity.SysRoleEntity;
import net.maku.system.service.SysMenuService;
import net.maku.system.service.SysRoleDataScopeService;
import net.maku.system.service.SysRoleMenuService;
import net.maku.system.service.SysRoleService;
import net.maku.system.vo.menu.SysMenuVO;
import net.maku.system.vo.role.SysRolePostVO;
import net.maku.system.vo.role.SysRolePutVO;
import net.maku.system.vo.role.SysRoleQuery;
import net.maku.system.vo.role.SysRoleVO;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 角色管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/role")
@Tag(name="角色管理")
@AllArgsConstructor
public class SysRoleController {
private final SysRoleService sysRoleService;
private final SysRoleMenuService sysRoleMenuService;
private final SysRoleDataScopeService sysRoleDataScopeService;
private final SysMenuService sysMenuService;
@GetMapping("page")
@Operation(summary = "分页")
//@PreAuthorize("hasAuthority('sys:role:page')")
public Result<PageResult<SysRoleVO>> page(@Valid SysRoleQuery query){
PageResult<SysRoleVO> page = sysRoleService.page(query);
return Result.ok(page);
}
@GetMapping("list")
@Operation(summary = "列表")
//@PreAuthorize("hasAuthority('sys:role:list')")
public Result<List<SysRoleVO>> list(){
List<SysRoleVO> list = sysRoleService.getList(new SysRoleQuery());
return Result.ok(list);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:role:info')")
public Result<SysRolePostVO> get(@PathVariable("id") Long id){
SysRoleEntity entity = sysRoleService.getById(id);
// 转换对象
SysRolePostVO role = SysRoleConvert.INSTANCE.convert(entity);
// 查询角色对应的菜单
List<Long> menuIdList = sysRoleMenuService.getMenuIdList(id);
role.setMenuIdList(menuIdList);
// 查询角色对应的数据权限
List<Long> orgIdList = sysRoleDataScopeService.getOrgIdList(id);
role.setOrgIdList(orgIdList);
return Result.ok(role);
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:role:save')")
public Result<String> save(@RequestBody @Valid SysRolePostVO vo){
sysRoleService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:role:update')")
public Result<String> update(@RequestBody @Valid SysRolePutVO vo){
sysRoleService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:role:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysRoleService.delete(idList);
return Result.ok();
}
@GetMapping("menu")
@Operation(summary = "角色菜单")
//@PreAuthorize("hasAuthority('sys:role:menu')")
public Result<List<SysMenuVO>> menu(){
UserDetail user = SecurityUser.getUser();
List<SysMenuVO> list = sysMenuService.getUserMenuList(user, null);
return Result.ok(list);
}
}

View File

@ -0,0 +1,131 @@
package net.maku.system.controller;
import cn.hutool.core.util.StrUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.utils.Result;
import net.maku.framework.security.user.SecurityUser;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.convert.SysUserConvert;
import net.maku.system.entity.SysUserEntity;
import net.maku.system.service.SysUserPostService;
import net.maku.system.service.SysUserRoleService;
import net.maku.system.service.SysUserService;
import net.maku.system.vo.user.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* 用户管理
*
* @author 阿沐 babamu@126.com
*/
@RestController
@RequestMapping("sys/user")
@AllArgsConstructor
@Tag(name="用户管理")
public class SysUserController {
private final SysUserService sysUserService;
private final SysUserRoleService sysUserRoleService;
private final SysUserPostService sysUserPostService;
private final PasswordEncoder passwordEncoder;
@GetMapping("page")
@Operation(summary = "分页")
public Result<PageResult<SysUserVO>> page(@Valid SysUserQuery query){
PageResult<SysUserVO> page = sysUserService.page(query);
return Result.ok(page);
}
@GetMapping("{id}")
@Operation(summary = "信息")
//@PreAuthorize("hasAuthority('sys:user:info')")
public Result<SysUserVO> get(@PathVariable("id") Long id){
SysUserEntity entity = sysUserService.getById(id);
SysUserVO vo = SysUserConvert.INSTANCE.convert(entity);
// 用户角色列表
List<Long> roleIdList = sysUserRoleService.getRoleIdList(id);
vo.setRoleIdList(roleIdList);
// 用户岗位列表
List<Long> postIdList = sysUserPostService.getPostIdList(id);
vo.setPostIdList(postIdList);
return Result.ok(vo);
}
@GetMapping("info")
@Operation(summary = "登录用户")
public Result<SysUserVO> info(){
SysUserVO user = SysUserConvert.INSTANCE.convert(SecurityUser.getUser());
return Result.ok(user);
}
@PutMapping("password")
@Operation(summary = "修改密码")
public Result<String> password(@RequestBody @Valid SysUserPasswordVO vo){
// 原密码不正确
UserDetail user = SecurityUser.getUser();
if(!passwordEncoder.matches(vo.getPassword(), user.getPassword())){
return Result.error("原密码不正确");
}
// 修改密码
sysUserService.updatePassword(user.getId(), passwordEncoder.encode(vo.getNewPassword()));
return Result.ok();
}
@PostMapping
@Operation(summary = "保存")
//@PreAuthorize("hasAuthority('sys:user:save')")
public Result<String> save(@RequestBody @Valid SysUserPostVO vo){
// 新增密码不能为空
if (StrUtil.isBlank(vo.getPassword())){
Result.error("密码不能为空");
}
// 密码加密
vo.setPassword(passwordEncoder.encode(vo.getPassword()));
// 保存
sysUserService.save(vo);
return Result.ok();
}
@PutMapping
@Operation(summary = "修改")
//@PreAuthorize("hasAuthority('sys:user:update')")
public Result<String> update(@RequestBody @Valid SysUserPutVO vo){
// 如果密码不为空则进行加密处理
if(StrUtil.isBlank(vo.getPassword())){
vo.setPassword(null);
}else{
vo.setPassword(passwordEncoder.encode(vo.getPassword()));
}
sysUserService.update(vo);
return Result.ok();
}
@DeleteMapping
@Operation(summary = "删除")
//@PreAuthorize("hasAuthority('sys:user:delete')")
public Result<String> delete(@RequestBody List<Long> idList){
sysUserService.delete(idList);
return Result.ok();
}
}

View File

@ -0,0 +1,24 @@
package net.maku.system.convert;
import net.maku.system.entity.SysDictDataEntity;
import net.maku.system.vo.dict.data.SysDictDataPostVO;
import net.maku.system.vo.dict.data.SysDictDataPutVO;
import net.maku.system.vo.dict.data.SysDictDataVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysDictDataConvert {
SysDictDataConvert INSTANCE = Mappers.getMapper(SysDictDataConvert.class);
SysDictDataEntity convert(SysDictDataPostVO vo);
SysDictDataEntity convert(SysDictDataPutVO vo);
SysDictDataVO convert(SysDictDataEntity entity);
List<SysDictDataVO> convertList(List<SysDictDataEntity> list);
}

View File

@ -0,0 +1,24 @@
package net.maku.system.convert;
import net.maku.system.entity.SysDictTypeEntity;
import net.maku.system.vo.dict.type.SysDictTypePostVO;
import net.maku.system.vo.dict.type.SysDictTypePutVO;
import net.maku.system.vo.dict.type.SysDictTypeVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysDictTypeConvert {
SysDictTypeConvert INSTANCE = Mappers.getMapper(SysDictTypeConvert.class);
SysDictTypeEntity convert(SysDictTypePostVO vo);
SysDictTypeEntity convert(SysDictTypePutVO vo);
SysDictTypeVO convert(SysDictTypeEntity entity);
List<SysDictTypeVO> convertList(List<SysDictTypeEntity> list);
}

View File

@ -0,0 +1,25 @@
package net.maku.system.convert;
import net.maku.system.entity.SysMenuEntity;
import net.maku.system.vo.menu.SysMenuPostVO;
import net.maku.system.vo.menu.SysMenuPutVO;
import net.maku.system.vo.menu.SysMenuVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysMenuConvert {
SysMenuConvert INSTANCE = Mappers.getMapper(SysMenuConvert.class);
SysMenuEntity convert(SysMenuPostVO vo);
SysMenuEntity convert(SysMenuPutVO vo);
SysMenuVO convert(SysMenuEntity entity);
List<SysMenuVO> convertList(List<SysMenuEntity> list);
}

View File

@ -0,0 +1,25 @@
package net.maku.system.convert;
import net.maku.system.entity.SysOauthClientEntity;
import net.maku.system.vo.oauth.SysOauthClientPostVO;
import net.maku.system.vo.oauth.SysOauthClientPutVO;
import net.maku.system.vo.oauth.SysOauthClientVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysOauthClientConvert {
SysOauthClientConvert INSTANCE = Mappers.getMapper(SysOauthClientConvert.class);
SysOauthClientEntity convert(SysOauthClientPostVO vo);
SysOauthClientEntity convert(SysOauthClientPutVO vo);
SysOauthClientVO convert(SysOauthClientEntity entity);
List<SysOauthClientVO> convertList(List<SysOauthClientEntity> list);
}

View File

@ -0,0 +1,25 @@
package net.maku.system.convert;
import net.maku.system.entity.SysOrgEntity;
import net.maku.system.vo.org.SysOrgPostVO;
import net.maku.system.vo.org.SysOrgPutVO;
import net.maku.system.vo.org.SysOrgVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysOrgConvert {
SysOrgConvert INSTANCE = Mappers.getMapper(SysOrgConvert.class);
SysOrgEntity convert(SysOrgPostVO vo);
SysOrgEntity convert(SysOrgPutVO vo);
SysOrgVO convert(SysOrgEntity entity);
List<SysOrgVO> convertList(List<SysOrgEntity> list);
}

View File

@ -0,0 +1,25 @@
package net.maku.system.convert;
import net.maku.system.entity.SysPostEntity;
import net.maku.system.vo.post.SysPostPostVO;
import net.maku.system.vo.post.SysPostPutVO;
import net.maku.system.vo.post.SysPostVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysPostConvert {
SysPostConvert INSTANCE = Mappers.getMapper(SysPostConvert.class);
SysPostEntity convert(SysPostPostVO vo);
SysPostEntity convert(SysPostPutVO vo);
SysPostVO convert(SysPostEntity entity);
List<SysPostVO> convertList(List<SysPostEntity> list);
}

View File

@ -0,0 +1,24 @@
package net.maku.system.convert;
import net.maku.system.entity.SysRoleEntity;
import net.maku.system.vo.role.SysRolePostVO;
import net.maku.system.vo.role.SysRolePutVO;
import net.maku.system.vo.role.SysRoleVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysRoleConvert {
SysRoleConvert INSTANCE = Mappers.getMapper(SysRoleConvert.class);
SysRoleEntity convert(SysRolePostVO vo);
SysRoleEntity convert(SysRolePutVO vo);
SysRoleVO convert(SysRoleEntity entity);
List<SysRoleVO> convertList(List<SysRoleEntity> list);
}

View File

@ -0,0 +1,30 @@
package net.maku.system.convert;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.entity.SysUserEntity;
import net.maku.system.vo.user.SysUserPostVO;
import net.maku.system.vo.user.SysUserPutVO;
import net.maku.system.vo.user.SysUserVO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface SysUserConvert {
SysUserConvert INSTANCE = Mappers.getMapper(SysUserConvert.class);
SysUserEntity convert(SysUserPostVO vo);
SysUserEntity convert(SysUserPutVO vo);
SysUserVO convert(SysUserEntity entity);
SysUserVO convert(UserDetail userDetail);
UserDetail convertDetail(SysUserEntity entity);
List<SysUserVO> convertList(List<SysUserEntity> list);
}

View File

@ -0,0 +1,15 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysDictDataEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 字典数据
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysDictDataDao extends BaseDao<SysDictDataEntity> {
}

View File

@ -0,0 +1,15 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysDictTypeEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 字典类型
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysDictTypeDao extends BaseDao<SysDictTypeEntity> {
}

View File

@ -0,0 +1,44 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysMenuEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 菜单管理
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysMenuDao extends BaseDao<SysMenuEntity> {
/**
* 查询所有菜单列表
*
* @param type 菜单类型
*/
List<SysMenuEntity> getMenuList(@Param("type") Integer type);
/**
* 查询用户菜单列表
*
* @param userId 用户ID
* @param type 菜单类型
*/
List<SysMenuEntity> getUserMenuList(@Param("userId") Long userId, @Param("type") Integer type);
/**
* 查询用户权限列表
* @param userId 用户ID
*/
List<String> getUserAuthorityList(@Param("userId") Long userId);
/**
* 查询所有权限列表
*/
List<String> getAuthorityList();
}

View File

@ -0,0 +1,19 @@
package net.maku.system.dao;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysOauthClientEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 客户端管理
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysOauthClientDao extends BaseDao<SysOauthClientEntity> {
default SysOauthClientEntity getByClientId(String clientId){
return this.selectOne(new QueryWrapper<SysOauthClientEntity>().eq("client_id", clientId));
}
}

View File

@ -0,0 +1,25 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysOrgEntity;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
import java.util.Map;
/**
* 机构管理
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysOrgDao extends BaseDao<SysOrgEntity> {
List<SysOrgEntity> getList(Map<String, Object> params);
/**
* 获取所有机构的idpid列表
*/
List<SysOrgEntity> getIdAndPidList();
}

View File

@ -0,0 +1,15 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysPostEntity;
import org.apache.ibatis.annotations.Mapper;
/**
* 岗位管理
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysPostDao extends BaseDao<SysPostEntity> {
}

View File

@ -0,0 +1,21 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysRoleEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* 角色管理
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysRoleDao extends BaseDao<SysRoleEntity> {
/**
* 根据用户ID获取用户最大的数据范围
*/
Integer getDataScopeByUserId(@Param("userId") Long userId);
}

View File

@ -0,0 +1,28 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysRoleDataScopeEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 角色数据权限
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysRoleDataScopeDao extends BaseDao<SysRoleDataScopeEntity> {
/**
* 根据角色ID获取机构ID列表
*/
List<Long> getOrgIdList(@Param("roleId") Long roleId);
/**
* 获取用户的数据权限列表
*/
List<Long> getDataScopeList(@Param("userId") Long userId);
}

View File

@ -0,0 +1,22 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysRoleMenuEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 角色与菜单对应关系
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysRoleMenuDao extends BaseDao<SysRoleMenuEntity> {
/**
* 根据角色ID获取菜单ID列表
*/
List<Long> getMenuIdList(@Param("roleId") Long roleId);
}

View File

@ -0,0 +1,31 @@
package net.maku.system.dao;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysUserEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
* 系统用户
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysUserDao extends BaseDao<SysUserEntity> {
List<SysUserEntity> getList(Map<String, Object> params);
SysUserEntity getById(@Param("id") Long id);
default SysUserEntity getByUsername(String username){
return this.selectOne(new QueryWrapper<SysUserEntity>().eq("username", username));
}
default SysUserEntity getByMobile(String mobile){
return this.selectOne(new QueryWrapper<SysUserEntity>().eq("mobile", mobile));
}
}

View File

@ -0,0 +1,23 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysUserPostEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户岗位关系
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysUserPostDao extends BaseDao<SysUserPostEntity> {
/**
* 岗位ID列表
* @param userId 用户ID
*/
List<Long> getPostIdList(@Param("userId") Long userId);
}

View File

@ -0,0 +1,25 @@
package net.maku.system.dao;
import net.maku.framework.common.dao.BaseDao;
import net.maku.system.entity.SysUserRoleEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 用户角色关系
*
* @author 阿沐 babamu@126.com
*/
@Mapper
public interface SysUserRoleDao extends BaseDao<SysUserRoleEntity> {
/**
* 角色ID列表
* @param userId 用户ID
*
* @return 返回角色ID列表
*/
List<Long> getRoleIdList(@Param("userId") Long userId);
}

View File

@ -0,0 +1,37 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 数据字典
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_dict_data")
public class SysDictDataEntity extends BaseEntity {
/**
* 字典类型ID
*/
private Long dictTypeId;
/**
* 字典标签
*/
private String dictLabel;
/**
* 字典值
*/
private String dictValue;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private Integer sort;
}

View File

@ -0,0 +1,33 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 字典类型
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_dict_type")
public class SysDictTypeEntity extends BaseEntity {
/**
* 字典类型
*/
private String dictType;
/**
* 字典名称
*/
private String dictName;
/**
* 备注
*/
private String remark;
/**
* 排序
*/
private Integer sort;
}

View File

@ -0,0 +1,50 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 菜单管理
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_menu")
public class SysMenuEntity extends BaseEntity {
/**
* 上级ID一级菜单为0
*/
private Long pid;
/**
* 菜单名称
*/
private String name;
/**
* 菜单URL
*/
private String url;
/**
* 授权标识(多个用逗号分隔sys:menu:list,sys:menu:save)
*/
private String authority;
/**
* 类型 0菜单 1按钮 2接口
*/
private Integer type;
/**
* 打开方式 0内部 1外部
*/
private Integer openStyle;
/**
* 菜单图标
*/
private String icon;
/**
* 排序
*/
private Integer sort;
}

View File

@ -0,0 +1,64 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 客户端管理
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName(value = "sys_oauth_client", autoResultMap = true)
public class SysOauthClientEntity extends BaseEntity {
/**
* 客户端ID
*/
private String clientId;
/**
* 客户端密钥
*/
private String clientSecret;
/**
* 资源ids
*/
private String resourceIds;
/**
* 授权范围
*/
private String scope;
/**
* 授权类型
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private String[] authorizedGrantTypes;
/**
* 回调地址
*/
private String webServerRedirectUri;
/**
* 权限标识
*/
private String authorities;
/**
* 访问令牌有效期
*/
private Integer accessTokenValidity;
/**
* 刷新令牌有效期
*/
private Integer refreshTokenValidity;
/**
* 附加信息
*/
private String additionalInformation;
/**
* 自动授权
*/
private String autoapprove;
}

View File

@ -0,0 +1,35 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 机构管理
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_org")
public class SysOrgEntity extends BaseEntity {
/**
* 上级ID
*/
private Long pid;
/**
* 机构名称
*/
private String name;
/**
* 排序
*/
private Integer sort;
/**
* 上级名称
*/
@TableField(exist = false)
private String parentName;
}

View File

@ -0,0 +1,34 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 岗位管理
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_post")
public class SysPostEntity extends BaseEntity {
/**
* 岗位编码
*/
private String postCode;
/**
* 岗位名称
*/
private String postName;
/**
* 排序
*/
private Integer sort;
/**
* 状态 0停用 1正常
*/
private Integer status;
}

View File

@ -0,0 +1,26 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 角色数据权限
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_role_data_scope")
public class SysRoleDataScopeEntity extends BaseEntity {
/**
* 角色ID
*/
private Long roleId;
/**
* 机构ID
*/
private Long orgId;
}

View File

@ -0,0 +1,37 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
import net.maku.system.enums.DataScopeEnum;
/**
* 角色
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_role")
public class SysRoleEntity extends BaseEntity {
/**
* 角色名称
*/
private String name;
/**
* 备注
*/
private String remark;
/**
* 数据范围 {@link DataScopeEnum}
*/
private Integer dataScope;
/**
* 机构ID
*/
@TableField(fill = FieldFill.INSERT)
private Long orgId;
}

View File

@ -0,0 +1,26 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 角色菜单关系
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_role_menu")
public class SysRoleMenuEntity extends BaseEntity {
/**
* 角色ID
*/
private Long roleId;
/**
* 菜单ID
*/
private Long menuId;
}

View File

@ -0,0 +1,59 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
import net.maku.system.enums.UserStatusEnum;
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("sys_user")
public class SysUserEntity extends BaseEntity {
/**
* 用户名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 姓名
*/
private String realName;
/**
* 头像
*/
private String avatar;
/**
* 性别 0 1
*/
private Integer gender;
/**
* 邮箱
*/
private String email;
/**
* 手机号
*/
private String mobile;
/**
* 机构ID
*/
private Long orgId;
/**
* 超级管理员 0 1
*/
private Integer superAdmin;
/**
* 状态 {@link UserStatusEnum}
*/
private Integer status;
/**
* 机构名称
*/
@TableField(exist=false)
private String orgName;
}

View File

@ -0,0 +1,25 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 用户岗位关系
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_user_post")
public class SysUserPostEntity extends BaseEntity {
/**
* 用户ID
*/
private Long userId;
/**
* 岗位ID
*/
private Long postId;
}

View File

@ -0,0 +1,28 @@
package net.maku.system.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.maku.framework.common.entity.BaseEntity;
/**
* 用户角色关系
*
* @author 阿沐 babamu@126.com
*/
@Data
@EqualsAndHashCode(callSuper=false)
@TableName("sys_user_role")
public class SysUserRoleEntity extends BaseEntity {
private static final long serialVersionUID = 1L;
/**
* 角色ID
*/
private Long roleId;
/**
* 用户ID
*/
private Long userId;
}

View File

@ -0,0 +1,35 @@
package net.maku.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 数据范围枚举
*/
@Getter
@AllArgsConstructor
public enum DataScopeEnum {
/**
* 全部数据
*/
ALL(0),
/**
* 本部门及子部门数据
*/
DEPT_AND_CHILD(1),
/**
* 本部门数据
*/
DEPT_ONLY(2),
/**
* 本人数据
*/
SELF(3),
/**
* 自定义数据
*/
CUSTOM(4);
private final Integer value;
}

View File

@ -0,0 +1,29 @@
package net.maku.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 菜单类型枚举
*
* @author 阿沐 babamu@126.com
*/
@Getter
@AllArgsConstructor
public enum MenuTypeEnum {
/**
* 菜单
*/
MENU(0),
/**
* 按钮
*/
BUTTON(1),
/**
* 接口
*/
INTERFACE(2);
private final int value;
}

View File

@ -0,0 +1,16 @@
package net.maku.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 超级管理员枚举
*/
@Getter
@AllArgsConstructor
public enum SuperAdminEnum {
YES(1),
NO(0);
private final Integer value;
}

View File

@ -0,0 +1,24 @@
package net.maku.system.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户状态
*
* @author 阿沐 babamu@126.com
*/
@Getter
@AllArgsConstructor
public enum UserStatusEnum {
/**
* 停用
*/
DISABLE(0),
/**
* 正常
*/
ENABLED(1);
private final int value;
}

View File

@ -0,0 +1,28 @@
package net.maku.system.service;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.service.BaseService;
import net.maku.system.entity.SysDictDataEntity;
import net.maku.system.vo.dict.data.SysDictDataPostVO;
import net.maku.system.vo.dict.data.SysDictDataPutVO;
import net.maku.system.vo.dict.data.SysDictDataQuery;
import net.maku.system.vo.dict.data.SysDictDataVO;
import java.util.List;
/**
* 数据字典
*
* @author 阿沐 babamu@126.com
*/
public interface SysDictDataService extends BaseService<SysDictDataEntity> {
PageResult<SysDictDataVO> page(SysDictDataQuery query);
void save(SysDictDataPostVO vo);
void update(SysDictDataPutVO vo);
void delete(List<Long> idList);
}

View File

@ -0,0 +1,34 @@
package net.maku.system.service;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.service.BaseService;
import net.maku.system.entity.SysDictTypeEntity;
import net.maku.system.vo.dict.SysDictVO;
import net.maku.system.vo.dict.type.SysDictTypePostVO;
import net.maku.system.vo.dict.type.SysDictTypePutVO;
import net.maku.system.vo.dict.type.SysDictTypeQuery;
import net.maku.system.vo.dict.type.SysDictTypeVO;
import java.util.List;
/**
* 数据字典
*
* @author 阿沐 babamu@126.com
*/
public interface SysDictTypeService extends BaseService<SysDictTypeEntity> {
PageResult<SysDictTypeVO> page(SysDictTypeQuery query);
void save(SysDictTypePostVO vo);
void update(SysDictTypePutVO vo);
void delete(List<Long> idList);
/**
* 获取全部字典列表
*/
List<SysDictVO> getDictList();
}

View File

@ -0,0 +1,52 @@
package net.maku.system.service;
import net.maku.framework.common.service.BaseService;
import net.maku.framework.security.user.UserDetail;
import net.maku.system.entity.SysMenuEntity;
import net.maku.system.vo.menu.SysMenuPostVO;
import net.maku.system.vo.menu.SysMenuPutVO;
import net.maku.system.vo.menu.SysMenuVO;
import java.util.List;
import java.util.Set;
/**
* 菜单管理
*
* @author 阿沐 babamu@126.com
*/
public interface SysMenuService extends BaseService<SysMenuEntity> {
void save(SysMenuPostVO vo);
void update(SysMenuPutVO vo);
void delete(Long id);
/**
* 菜单列表
*
* @param type 菜单类型
*/
List<SysMenuVO> getMenuList(Integer type);
/**
* 用户菜单列表
*
* @param user 用户
* @param type 菜单类型
*/
List<SysMenuVO> getUserMenuList(UserDetail user, Integer type);
/**
* 获取子菜单的数量
* @param pid 父菜单ID
*/
Long getSubMenuCount(Long pid);
/**
* 获取用户权限列表
*/
Set<String> getUserAuthority(UserDetail user);
}

View File

@ -0,0 +1,27 @@
package net.maku.system.service;
import net.maku.framework.common.page.PageResult;
import net.maku.framework.common.query.Query;
import net.maku.framework.common.service.BaseService;
import net.maku.system.entity.SysOauthClientEntity;
import net.maku.system.vo.oauth.SysOauthClientPostVO;
import net.maku.system.vo.oauth.SysOauthClientPutVO;
import net.maku.system.vo.oauth.SysOauthClientVO;
import java.util.List;
/**
* 客户端管理
*
* @author 阿沐 babamu@126.com
*/
public interface SysOauthClientService extends BaseService<SysOauthClientEntity> {
PageResult<SysOauthClientVO> page(Query query);
void save(SysOauthClientPostVO vo);
void update(SysOauthClientPutVO vo);
void delete(List<Long> idList);
}

View File

@ -0,0 +1,31 @@
package net.maku.system.service;
import net.maku.framework.common.service.BaseService;
import net.maku.system.entity.SysOrgEntity;
import net.maku.system.vo.org.SysOrgPostVO;
import net.maku.system.vo.org.SysOrgPutVO;
import net.maku.system.vo.org.SysOrgVO;
import java.util.List;
/**
* 机构管理
*
* @author 阿沐 babamu@126.com
*/
public interface SysOrgService extends BaseService<SysOrgEntity> {
List<SysOrgVO> getList();
void save(SysOrgPostVO vo);
void update(SysOrgPutVO vo);
void delete(Long id);
/**
* 根据机构ID获取子机构ID列表(包含本机构ID)
* @param id 机构ID
*/
List<Long> getSubOrgIdList(Long id);
}

Some files were not shown because too many files have changed in this diff Show More