diff --git a/common/common-generator/src/main/java/cn/bunny/common/generator/NewCodeGet.java b/common/common-generator/src/main/java/cn/bunny/common/generator/NewCodeGet.java index 27d0fe9..ad2d290 100644 --- a/common/common-generator/src/main/java/cn/bunny/common/generator/NewCodeGet.java +++ b/common/common-generator/src/main/java/cn/bunny/common/generator/NewCodeGet.java @@ -10,16 +10,17 @@ import java.util.Collections; public class NewCodeGet { // 数据连接 - public static final String sqlHost = "jdbc:mysql://106.15.251.123:3305/bunny_docs?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true"; + public static final String sqlHost = "jdbc:mysql://192.168.3.98:3304/auth_admin?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true"; // 作者名称 public static final String author = "Bunny"; // 公共路径 - public static final String outputDir = "F:\\web项目\\PC\\BunnyNote\\BunnyBBS-server\\service\\service-web"; + public static final String outputDir = "D:\\MyFolder\\auth-admin\\auth-server-java\\service"; + // public static final String outputDir = "D:\\Project\\web\\PC\\auth\\auth-server\\services"; // 实体类名称 public static final String entity = "Bunny"; public static void main(String[] args) { - Generation("article"); + Generation("sys_router"); } /** @@ -38,27 +39,25 @@ public class NewCodeGet { // 指定输出目录 .outputDir(outputDir + "/src/main/java"); }) - .packageConfig(builder -> { - builder.entity(entity)// 实体类包名 - // TODO 父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名 - .parent("cn.bunny.service.web") - .controller("controller")// 控制层包名 - .mapper("mapper")// mapper层包名 - .service("service")// service层包名 - .serviceImpl("service.impl")// service实现类包名 - // 自定义mapper.xml文件输出目录 - .pathInfo(Collections.singletonMap(OutputFile.xml, outputDir + "/src/main/resources/mapper")); - }) + .packageConfig(builder -> builder.entity(entity)// 实体类包名 + // 父包名。如果为空,将下面子包名必须写全部, 否则就只需写子包名 + .parent("cn.bunny.services") + .controller("controller")// 控制层包名 + .mapper("mapper")// mapper层包名 + .service("service")// service层包名 + .serviceImpl("service.impl")// service实现类包名 + // 自定义mapper.xml文件输出目录 + .pathInfo(Collections.singletonMap(OutputFile.xml, outputDir + "/src/main/resources/mapper"))) .strategyConfig(builder -> { // 设置要生成的表名 builder.addInclude(tableName) - //.addTablePrefix("sys_")// TODO 设置表前缀过滤 + .addTablePrefix("sys_") .entityBuilder() .enableLombok() .enableChainModel() .naming(NamingStrategy.underline_to_camel)// 数据表映射实体命名策略:默认下划线转驼峰underline_to_camel .columnNaming(NamingStrategy.underline_to_camel)// 表字段映射实体属性命名规则:默认null,不指定按照naming执行 - .idType(IdType.AUTO)// TODO 添加全局主键类型 + .idType(IdType.ASSIGN_ID)// 添加全局主键类型 .formatFileName("%s")// 格式化实体名称,%s取消首字母I, .mapperBuilder() .mapperAnnotation(Mapper.class)// 开启mapper注解 @@ -72,12 +71,6 @@ public class NewCodeGet { .controllerBuilder() .enableRestStyle(); }) - // .injectionConfig(consumer -> { - // Map customFile = new HashMap<>(); - // // 配置DTO(需要的话)但是需要有能配置Dto的模板引擎,比如freemarker,但是这里我们用的VelocityEngine,因此不多作介绍 - // customFile.put(outputDir, "/src/main/resources/templates/entityDTO.java.ftl"); - // consumer.customFile(customFile); - // }) .execute(); } } diff --git a/common/common-generator/src/main/java/cn/bunny/common/generator/OldCodeGet.java b/common/common-generator/src/main/java/cn/bunny/common/generator/OldCodeGet.java deleted file mode 100644 index d43819c..0000000 --- a/common/common-generator/src/main/java/cn/bunny/common/generator/OldCodeGet.java +++ /dev/null @@ -1,57 +0,0 @@ -package cn.bunny.common.generator; - -public class OldCodeGet { - public static void main(String[] args) { - // // 1、创建代码生成器 - // AutoGenerator mpg = new AutoGenerator(); - // - // // 2、全局配置 - // // 全局配置 - // GlobalConfig gc = new GlobalConfig(); - // // TODO 需要修改路径名称 - // gc.setOutputDir("F:\\web项目\\Bunny-Cli\\Java\\java-template\\service" + "/src/main/java"); - // gc.setServiceName("%sService"); // 去掉Service接口的首字母I - // gc.setAuthor("bunny"); - // gc.setOpen(false); - // mpg.setGlobalConfig(gc); - // - // // 3、数据源配置 - // DataSourceConfig dsc = new DataSourceConfig(); - // // TODO 需要修改数据库 - // dsc.setUrl("jdbc:mysql://106.15.251.123:3305/guigu-oa?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true"); - // dsc.setDriverName("com.mysql.cj.jdbc.Driver"); - // dsc.setUsername("root"); - // dsc.setPassword("02120212"); - // dsc.setDbType(DbType.MYSQL); - // mpg.setDataSource(dsc); - // - // // 4、包配置 - // PackageConfig pc = new PackageConfig(); - // pc.setParent("cn.bunny"); - // // TODO 需要修改模块名 - // pc.setModuleName("service"); - // pc.setController("controller"); - // pc.setService("service"); - // pc.setMapper("mapper"); - // mpg.setPackageInfo(pc); - // - // // 5、策略配置 - // StrategyConfig strategy = getStrategyConfig(); - // mpg.setStrategy(strategy); - // - // // 6、执行 - // mpg.execute(); - // } - // - // private static StrategyConfig getStrategyConfig() { - // StrategyConfig strategy = new StrategyConfig(); - // // TODO 要生成的表 - // strategy.setInclude("sys_menu", "sys_role_menu"); - // strategy.setNaming(NamingStrategy.underline_to_camel);// 数据库表映射到实体的命名策略 - // strategy.setColumnNaming(NamingStrategy.underline_to_camel);// 数据库表字段映射到实体的命名策略 - // strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作 - // strategy.setRestControllerStyle(true); // restful api风格控制器 - // strategy.setControllerMappingHyphenStyle(true); // url中驼峰转连字符 - // return strategy; - } -} diff --git a/common/pom.xml b/common/pom.xml index 38add34..91af6ed 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -3,7 +3,7 @@ 4.0.0 cn.bunny - bunny-template + auth-server-java 0.0.1-SNAPSHOT diff --git a/dao/pom.xml b/dao/pom.xml index a5efe1d..41ebece 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -3,7 +3,7 @@ 4.0.0 cn.bunny - bunny-template + auth-server-java 0.0.1-SNAPSHOT diff --git a/dao/src/main/java/cn/bunny/dao/entity/system/Router.java b/dao/src/main/java/cn/bunny/dao/entity/system/Router.java index 3bf4443..a8f0076 100644 --- a/dao/src/main/java/cn/bunny/dao/entity/system/Router.java +++ b/dao/src/main/java/cn/bunny/dao/entity/system/Router.java @@ -1,26 +1,42 @@ package cn.bunny.dao.entity.system; import cn.bunny.dao.entity.BaseEntity; +import com.alibaba.fastjson2.annotation.JSONField; import com.baomidou.mybatisplus.annotation.TableName; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.Setter; import lombok.experimental.Accessors; +/** + *

+ * + *

+ * + * @author Bunny + * @since 2024-09-27 + */ @Getter @Setter @Accessors(chain = true) @TableName("sys_router") -@ApiModel(value = "Router对象", description = "系统菜单表") +@ApiModel(value = "Router对象", description = "系统路由表") public class Router extends BaseEntity { + @ApiModelProperty("在项目中路径") - private String routerPath; + private String path; @ApiModelProperty("路由名称") private String routeName; @ApiModelProperty("父级id") + @JsonProperty("parentId") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) private Long parentId; @ApiModelProperty("路由title") @@ -34,4 +50,5 @@ public class Router extends BaseEntity { @ApiModelProperty("是否显示") private Boolean visible; -} \ No newline at end of file + +} diff --git a/dao/src/main/java/cn/bunny/dao/vo/common/KvData.java b/dao/src/main/java/cn/bunny/dao/vo/common/KvData.java new file mode 100644 index 0000000..314302a --- /dev/null +++ b/dao/src/main/java/cn/bunny/dao/vo/common/KvData.java @@ -0,0 +1,38 @@ +package cn.bunny.dao.vo.common; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ApiModel(value = "KvData对象", description = "基础键值对数据") +public class KvData { + @ApiModelProperty(value = "id", name = "主键") + @JsonProperty("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Long id; + + @ApiModelProperty("值内容") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Object value; + + @ApiModelProperty("值内容") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Object key; + + @ApiModelProperty("显示内容") + private String label; +} diff --git a/dao/src/main/java/cn/bunny/dao/vo/common/TreeSelectVo.java b/dao/src/main/java/cn/bunny/dao/vo/common/TreeSelectVo.java new file mode 100644 index 0000000..9b94f80 --- /dev/null +++ b/dao/src/main/java/cn/bunny/dao/vo/common/TreeSelectVo.java @@ -0,0 +1,25 @@ +package cn.bunny.dao.vo.common; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@ApiModel(value = "TreeSelectList对象", description = "树形结构数据") +public class TreeSelectVo extends KvData { + + @ApiModelProperty("父级id") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Long parentId; + + @ApiModelProperty("子级内容") + private List children; +} \ No newline at end of file diff --git a/dao/src/main/java/cn/bunny/dao/vo/router/RouterControllerVo.java b/dao/src/main/java/cn/bunny/dao/vo/router/RouterControllerVo.java new file mode 100644 index 0000000..e69a40c --- /dev/null +++ b/dao/src/main/java/cn/bunny/dao/vo/router/RouterControllerVo.java @@ -0,0 +1,46 @@ +package cn.bunny.dao.vo.router; + +import cn.bunny.dao.vo.BaseVo; +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.*; + +import java.util.List; + +@EqualsAndHashCode(callSuper = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ApiModel(value = "RouterControllerVo对象", description = "路由管理端返回对象") +public class RouterControllerVo extends BaseVo { + + @ApiModelProperty("在项目中路径") + private String path; + + @ApiModelProperty("路由名称") + private String routeName; + + @ApiModelProperty("父级id") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Long parentId; + + @ApiModelProperty("title名称") + private String title; + + @ApiModelProperty("图标") + private String icon; + + @ApiModelProperty("等级") + private Integer routerRank; + + @ApiModelProperty("是否显示") + private Boolean visible; + + @ApiModelProperty("子路由") + private List children; +} diff --git a/dao/src/main/java/cn/bunny/dao/vo/router/RouterMeta.java b/dao/src/main/java/cn/bunny/dao/vo/router/RouterMeta.java new file mode 100644 index 0000000..2dbd2d5 --- /dev/null +++ b/dao/src/main/java/cn/bunny/dao/vo/router/RouterMeta.java @@ -0,0 +1,33 @@ +package cn.bunny.dao.vo.router; + +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ApiModel(value = "UserRouterMetaVo对象", description = "系统属性内容") +public class RouterMeta { + + @ApiModelProperty(value = "图标") + private String icon; + + @ApiModelProperty(value = "标题") + private String title; + + @ApiModelProperty(value = "排序权重") + private Integer rank; + + @ApiModelProperty(value = "角色列表") + private List roles; + + @ApiModelProperty(value = "权限列表") + private List auths; +} diff --git a/dao/src/main/java/cn/bunny/dao/vo/router/UserRouterVo.java b/dao/src/main/java/cn/bunny/dao/vo/router/UserRouterVo.java new file mode 100644 index 0000000..638fb32 --- /dev/null +++ b/dao/src/main/java/cn/bunny/dao/vo/router/UserRouterVo.java @@ -0,0 +1,47 @@ +package cn.bunny.dao.vo.router; + +import com.alibaba.fastjson2.annotation.JSONField; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import io.swagger.annotations.ApiModel; +import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ApiModel(value = "UserRouterVo对象", description = "系统菜单表") +public class UserRouterVo { + @Schema(name = "id", title = "主键") + @JsonProperty("id") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Long id; + + @ApiModelProperty("父级id") + @JsonProperty("parentId") + @JsonFormat(shape = JsonFormat.Shape.STRING) + @JSONField(serializeUsing = ToStringSerializer.class) + private Long parentId; + + @ApiModelProperty("在项目中路径") + private String path; + + @ApiModelProperty("路由名称") + @JsonProperty("name") + private String routeName; + + @ApiModelProperty("meta内容") + private RouterMeta meta; + + @ApiModelProperty("子路由") + private List children; +} diff --git a/dao/src/main/java/cn/bunny/dao/vo/user/LoginVo.java b/dao/src/main/java/cn/bunny/dao/vo/user/LoginVo.java index c7cd305..b41f259 100644 --- a/dao/src/main/java/cn/bunny/dao/vo/user/LoginVo.java +++ b/dao/src/main/java/cn/bunny/dao/vo/user/LoginVo.java @@ -4,6 +4,7 @@ import cn.bunny.dao.vo.BaseVo; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; +import java.util.ArrayList; import java.util.List; /** @@ -16,8 +17,8 @@ import java.util.List; @Builder @Schema(name = "LoginVo对象", title = "登录成功返回内容", description = "登录成功返回内容") public class LoginVo extends BaseVo { - @Schema(name = "nickName", title = "昵称") - private String nickName; + @Schema(name = "nickname", title = "昵称") + private String nickname; @Schema(name = "username", title = "用户名") private String username; @@ -40,24 +41,12 @@ public class LoginVo extends BaseVo { @Schema(name = "personDescription", title = "个人描述") private String personDescription; - @Schema(name = "articleMode", title = "文章显示模式") - private String articleMode; - - @Schema(name = "layout", title = "页面布局方式") - private String layout; - @Schema(name = "lastLoginIp", title = "最后登录IP") private String lastLoginIp; @Schema(name = "lastLoginIpAddress", title = "最后登录ip地址") private String lastLoginIpAddress; - @Schema(name = "totalIntegral", title = "积分") - private Integer totalIntegral; - - @Schema(name = "currentIntegral", title = "当前积分") - private Integer currentIntegral; - @Schema(name = "status", title = "1:禁用 0:正常") private Byte status; @@ -71,8 +60,9 @@ public class LoginVo extends BaseVo { private String expires; @Schema(name = "roleList", title = "角色列表") - private List roleList; + private List roles = new ArrayList<>(); @Schema(name = "powerList", title = "权限列表") - private List powerList; + private List permissions = new ArrayList<>(); + } \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0bf395a..21511a3 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ cn.bunny - bunny-template + auth-server-java 0.0.1-SNAPSHOT pom bunny-template diff --git a/service/pom.xml b/service/pom.xml index 06caa80..3214574 100644 --- a/service/pom.xml +++ b/service/pom.xml @@ -3,7 +3,7 @@ 4.0.0 cn.bunny - bunny-template + auth-server-java 0.0.1-SNAPSHOT diff --git a/service/src/main/java/cn/bunny/services/controller/RouterController.java b/service/src/main/java/cn/bunny/services/controller/RouterController.java index 4d13fcf..d0f9fe8 100644 --- a/service/src/main/java/cn/bunny/services/controller/RouterController.java +++ b/service/src/main/java/cn/bunny/services/controller/RouterController.java @@ -1,9 +1,17 @@ package cn.bunny.services.controller; +import cn.bunny.dao.pojo.result.Result; +import cn.bunny.dao.vo.router.UserRouterVo; +import cn.bunny.services.service.RouterService; +import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.List; + /** *

* 系统菜单表 前端控制器 @@ -17,4 +25,13 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("admin/router") public class RouterController { + @Autowired + private RouterService routerService; + + @Operation(summary = "获取用户菜单", description = "获取用户菜单") + @GetMapping("getRouterAsync") + public Result> getRouterAsync() { + List voList = routerService.getRouterAsync(); + return Result.success(voList); + } } diff --git a/service/src/main/java/cn/bunny/services/factory/UserFactory.java b/service/src/main/java/cn/bunny/services/factory/UserFactory.java index 1bd965b..28501f5 100644 --- a/service/src/main/java/cn/bunny/services/factory/UserFactory.java +++ b/service/src/main/java/cn/bunny/services/factory/UserFactory.java @@ -18,8 +18,9 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; @Component @Transactional @@ -51,15 +52,30 @@ public class UserFactory { DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(LocalDateTimeConstant.YYYY_MM_DD_HH_MM_SS_SLASH); String expires = plusDay.format(dateTimeFormatter); + // 查找用户橘色 + List roles = roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).toList(); + List permissions = new ArrayList<>(); + + boolean isAdmin = roles.stream().anyMatch(role -> role.equals("admin")); + + if (isAdmin) { + permissions.add("*"); + permissions.add("*::*"); + permissions.add("*::*::*"); + } else { + permissions = powerMapper.selectListByUserId(userId).stream().map(Power::getPowerCode).toList(); + } + // 构建返回对象 LoginVo loginVo = new LoginVo(); BeanUtils.copyProperties(user, loginVo); + loginVo.setNickname(user.getNickName()); loginVo.setToken(token); loginVo.setRefreshToken(token); loginVo.setLastLoginIp(IpUtil.getCurrentUserIpAddress().getRemoteAddr()); loginVo.setLastLoginIpAddress(IpUtil.getCurrentUserIpAddress().getIpRegion()); - loginVo.setRoleList(roleMapper.selectListByUserId(userId).stream().map(Role::getRoleCode).collect(Collectors.toList())); - loginVo.setPowerList(powerMapper.selectListByUserId(userId).stream().map(Power::getPowerCode).collect(Collectors.toList())); + loginVo.setRoles(roles); + loginVo.setPermissions(permissions); loginVo.setUpdateUser(userId); loginVo.setExpires(expires); diff --git a/service/src/main/java/cn/bunny/services/mapper/PowerMapper.java b/service/src/main/java/cn/bunny/services/mapper/PowerMapper.java index 71a2de3..4e4de1c 100644 --- a/service/src/main/java/cn/bunny/services/mapper/PowerMapper.java +++ b/service/src/main/java/cn/bunny/services/mapper/PowerMapper.java @@ -24,4 +24,12 @@ public interface PowerMapper extends BaseMapper { */ @NotNull List selectListByUserId(long userId); + + /** + * * 根据权限码查询可以访问URL + * + * @param powerCodes 权限码 + * @return 权限列表 + */ + List selectListByPowerCodes(List powerCodes); } diff --git a/service/src/main/java/cn/bunny/services/mapper/RouterMapper.java b/service/src/main/java/cn/bunny/services/mapper/RouterMapper.java index 1ec2630..0776098 100644 --- a/service/src/main/java/cn/bunny/services/mapper/RouterMapper.java +++ b/service/src/main/java/cn/bunny/services/mapper/RouterMapper.java @@ -4,15 +4,32 @@ import cn.bunny.dao.entity.system.Router; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** *

- * 系统菜单表 Mapper 接口 + * Mapper 接口 *

* * @author Bunny - * @since 2024-09-26 + * @since 2024-09-27 */ @Mapper public interface RouterMapper extends BaseMapper { + /** + * * 根据用户id查找路由内容 + * + * @param userId 用户id + * @return 路由列表 + */ + List selectListByUserId(Long userId); + + /** + * * 递归查询所有父级Id,直到查询到父级Id为0 + * + * @param ids id列表 + * @return 路由列表 + */ + List selectParentListByRouterId(List ids); } diff --git a/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java b/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java index 2c80402..21a876e 100644 --- a/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java +++ b/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java @@ -76,7 +76,7 @@ public class WebSecurityConfig { .addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, redisTemplate, customUserDetailsService), UsernamePasswordAuthenticationFilter.class) // 其它权限鉴权过滤器 .addFilterAt(new NoTokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class) - .addFilterAt(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class) + .addFilterAt(new TokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class) // 自定义密码加密器和用户登录 .passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService); diff --git a/service/src/main/java/cn/bunny/services/security/filter/NoTokenAuthenticationFilter.java b/service/src/main/java/cn/bunny/services/security/filter/NoTokenAuthenticationFilter.java index 735be2f..db3cf7b 100644 --- a/service/src/main/java/cn/bunny/services/security/filter/NoTokenAuthenticationFilter.java +++ b/service/src/main/java/cn/bunny/services/security/filter/NoTokenAuthenticationFilter.java @@ -8,10 +8,12 @@ import cn.bunny.dao.pojo.constant.RedisUserConstant; import cn.bunny.dao.pojo.result.Result; import cn.bunny.dao.pojo.result.ResultCodeEnum; import cn.bunny.dao.vo.user.LoginVo; +import com.alibaba.fastjson2.JSON; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.jetbrains.annotations.NotNull; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.web.filter.OncePerRequestFilter; @@ -25,7 +27,7 @@ public class NoTokenAuthenticationFilter extends OncePerRequestFilter { } @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { // 判断是否有 token String token = request.getHeader("token"); if (token == null) { @@ -40,10 +42,11 @@ public class NoTokenAuthenticationFilter extends OncePerRequestFilter { return; } - // token 存在查找 Redis + // 查找 Redis String username = JwtHelper.getUsername(token); Long userId = JwtHelper.getUserId(token); - LoginVo loginVo = (LoginVo) redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username)); + Object loginVoObject = redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username)); + LoginVo loginVo = JSON.parseObject(JSON.toJSONString(loginVoObject), LoginVo.class); // 判断用户是否禁用 if (loginVo != null && loginVo.getStatus() == 1) { diff --git a/service/src/main/java/cn/bunny/services/security/filter/TokenAuthenticationFilter.java b/service/src/main/java/cn/bunny/services/security/filter/TokenAuthenticationFilter.java index 75cdb90..18c819e 100644 --- a/service/src/main/java/cn/bunny/services/security/filter/TokenAuthenticationFilter.java +++ b/service/src/main/java/cn/bunny/services/security/filter/TokenAuthenticationFilter.java @@ -1,10 +1,12 @@ package cn.bunny.services.security.filter; +import cn.bunny.common.service.context.BaseContext; +import cn.bunny.dao.vo.user.LoginVo; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.springframework.data.redis.core.RedisTemplate; +import org.jetbrains.annotations.NotNull; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; @@ -17,16 +19,10 @@ import java.util.List; public class TokenAuthenticationFilter extends OncePerRequestFilter { - private final RedisTemplate redisTemplate; - - public TokenAuthenticationFilter(RedisTemplate redisTemplate) { - this.redisTemplate = redisTemplate; - } - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { + protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, FilterChain chain) throws ServletException, IOException { // 自定义实现内容 - UsernamePasswordAuthenticationToken authentication = getAuthentication(request); + UsernamePasswordAuthenticationToken authentication = getAuthentication(); SecurityContextHolder.getContext().setAuthentication(authentication); chain.doFilter(request, response); @@ -35,21 +31,20 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { /** * 用户请求判断 * - * @param request 请求 * @return 验证码方法 */ - private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) { + private UsernamePasswordAuthenticationToken getAuthentication() { // 请求头是否有token - String token = request.getHeader("token"); - String username = "admin"; - List authList = new ArrayList<>(); + LoginVo LoginVo = BaseContext.getLoginVo(); - // 设置角色内容 - if (token != null) { - List roleList = new ArrayList<>(); - return new UsernamePasswordAuthenticationToken(username, null, authList); - } else { - return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>()); - } + // 通过username从redis获取权限数据 + String username = LoginVo.getUsername(); + List roleList = LoginVo.getRoles(); + + // 角色列表 + List authList = roleList.stream().map(SimpleGrantedAuthority::new).toList(); + + if (authList.isEmpty()) return new UsernamePasswordAuthenticationToken(username, null, new ArrayList<>()); + return new UsernamePasswordAuthenticationToken(username, null, authList); } } diff --git a/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java b/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java index 4b722fb..9132d65 100644 --- a/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java +++ b/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java @@ -21,6 +21,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.util.StringUtils; import java.io.IOException; @@ -76,10 +77,15 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte } } + /** + * * 验证成功 + */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) { + // 获取登录返回信息 LoginVo loginVo = customUserDetailsService.login(loginDto); + // 判断用户是否禁用 if (loginVo.getStatus() == 1) { out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED)); return; @@ -88,15 +94,17 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte out(response, Result.success(loginVo)); } + /** + * 验证失败 + */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) { String password = loginDto.getPassword(); String username = loginDto.getUsername(); - if (password == null || username == null || password.isBlank() || username.isBlank()) { + if (!StringUtils.hasText(password) || !StringUtils.hasText(username)) out(response, Result.error(ResultCodeEnum.USERNAME_OR_PASSWORD_NOT_EMPTY)); - } else { + else out(response, Result.error(null, ResultCodeEnum.LOGIN_ERROR)); - } } } \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/security/service/iml/CustomAuthorizationManagerServiceImpl.java b/service/src/main/java/cn/bunny/services/security/service/iml/CustomAuthorizationManagerServiceImpl.java index 706d414..1fff064 100644 --- a/service/src/main/java/cn/bunny/services/security/service/iml/CustomAuthorizationManagerServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/security/service/iml/CustomAuthorizationManagerServiceImpl.java @@ -1,6 +1,9 @@ package cn.bunny.services.security.service.iml; +import cn.bunny.common.service.context.BaseContext; import cn.bunny.common.service.utils.JwtHelper; +import cn.bunny.dao.entity.system.Power; +import cn.bunny.services.mapper.PowerMapper; import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.security.authorization.AuthorizationDecision; @@ -21,27 +24,50 @@ import java.util.function.Supplier; @Component @Slf4j public class CustomAuthorizationManagerServiceImpl implements AuthorizationManager { + private final PowerMapper powerMapper; + + public CustomAuthorizationManagerServiceImpl(PowerMapper powerMapper) {this.powerMapper = powerMapper;} + @Override public AuthorizationDecision check(Supplier authentication, RequestAuthorizationContext context) { // 用户的token和用户id、请求Url HttpServletRequest request = context.getRequest(); String token = request.getHeader("token"); - Long userId = JwtHelper.getUserId(token);// 用户id - String requestURI = request.getRequestURI();// 请求地址 - String method = request.getMethod();// 请求方式 - List roleCodeList = authentication.get().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList();// 角色代码列表 - return new AuthorizationDecision(hasRoleList(requestURI, method, userId)); + // 用户id + Long userId = JwtHelper.getUserId(token); + + // 请求地址 + String requestURI = request.getRequestURI(); + + // 请求方式 + String method = request.getMethod(); + + // 角色代码列表 + List roleCodeList = authentication.get().getAuthorities().stream().map(GrantedAuthority::getAuthority).toList(); + + // 校验权限 + return new AuthorizationDecision(hasAuth(requestURI, roleCodeList)); } /** * 查询用户所属的角色信息 * - * @param requestURI 请求url地址 - * @param method 请求方式 - * @param userId 用户id + * @param requestURI 请求url地址 + * @param roleCodeList 角色列表 */ - private Boolean hasRoleList(String requestURI, String method, Long userId) { - return true; + private Boolean hasAuth(String requestURI, List roleCodeList) { + // 判断是否是 admin + boolean isAdmin = roleCodeList.stream().anyMatch(role -> role.equals("admin")); + if (isAdmin) return true; + + // 不是 admin,查询角色权限关系表 + List powerCodes = BaseContext.getLoginVo().getPermissions(); + + // 根据权限码查询可以访问URL + List powerList = powerMapper.selectListByPowerCodes(powerCodes); + + // 判断是否与请求路径匹配 + return powerList.stream().anyMatch(power -> power.getRequestUrl().equals(requestURI)); } } diff --git a/service/src/main/java/cn/bunny/services/service/RouterService.java b/service/src/main/java/cn/bunny/services/service/RouterService.java index 130b11a..1f53e4f 100644 --- a/service/src/main/java/cn/bunny/services/service/RouterService.java +++ b/service/src/main/java/cn/bunny/services/service/RouterService.java @@ -1,16 +1,24 @@ package cn.bunny.services.service; import cn.bunny.dao.entity.system.Router; +import cn.bunny.dao.vo.router.UserRouterVo; import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + /** *

- * 系统菜单表 服务类 + * 服务类 *

* * @author Bunny - * @since 2024-09-26 + * @since 2024-09-27 */ public interface RouterService extends IService { - + /** + * * 获取路由内容 + * + * @return 路遇列表 + */ + List getRouterAsync(); } diff --git a/service/src/main/java/cn/bunny/services/service/impl/RouterServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/RouterServiceImpl.java index 4aa5367..c8db3ba 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/RouterServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/RouterServiceImpl.java @@ -1,20 +1,103 @@ package cn.bunny.services.service.impl; +import cn.bunny.common.service.context.BaseContext; +import cn.bunny.common.service.exception.BunnyException; import cn.bunny.dao.entity.system.Router; +import cn.bunny.dao.pojo.constant.RedisUserConstant; +import cn.bunny.dao.pojo.result.ResultCodeEnum; +import cn.bunny.dao.vo.router.RouterMeta; +import cn.bunny.dao.vo.router.UserRouterVo; +import cn.bunny.dao.vo.user.LoginVo; import cn.bunny.services.mapper.RouterMapper; import cn.bunny.services.service.RouterService; +import cn.bunny.services.service.process.RouterServiceProcess; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; /** *

- * 系统菜单表 服务实现类 + * 服务实现类 *

* * @author Bunny - * @since 2024-09-26 + * @since 2024-09-27 */ @Service +@Transactional public class RouterServiceImpl extends ServiceImpl implements RouterService { + @Autowired + private RouterServiceProcess routerServiceProcess; + @Autowired + private RedisTemplate redisTemplate; + /** + * * 获取路由内容 + * + * @return 路遇列表 + */ + @Override + public List getRouterAsync() { + // 当前用户id + String username = BaseContext.getUsername(); + + LoginVo loginVo = (LoginVo) redisTemplate.opsForValue().get(RedisUserConstant.getAdminLoginInfoPrefix(username)); + if (loginVo == null) throw new BunnyException(ResultCodeEnum.FAIL); + + // 角色列表 + List roleList = loginVo.getRoles(); + // 权限列表 + List powerCodeList = loginVo.getPermissions(); + + // 路由列表,根据用户角色判断 + List routerList; + + // 返回路由列表 + List list = new ArrayList<>(); + + // 查询用户角色,判断是否是管理员角色 + boolean isAdmin = roleList.stream().anyMatch(authUserRole -> authUserRole.equals("admin")); + if (isAdmin) { + routerList = list(); + } else { + List routerIds = baseMapper.selectListByUserId(loginVo.getId()); + routerList = baseMapper.selectParentListByRouterId(routerIds); + } + + // 构建返回路由列表 + List routerVoList = routerList.stream() + .filter(Router::getVisible) + .map(router -> { + // 复制对象 + UserRouterVo routerVo = new UserRouterVo(); + BeanUtils.copyProperties(router, routerVo); + routerVo.setPath(router.getPath().trim()); + + // 设置 + RouterMeta meta = RouterMeta.builder() + .rank(router.getRouterRank()) + .icon(router.getIcon()) + .title(router.getTitle()) + .roles(roleList) + .auths(powerCodeList).build(); + routerVo.setMeta(meta); + return routerVo; + }).distinct().toList(); + + // 构建树形结构 + routerVoList.forEach(routerVo -> { + if (routerVo.getParentId() == 0) { + routerVo.setChildren(routerServiceProcess.handleGetChildrenWIthRouter(routerVo.getId(), routerVoList)); + list.add(routerVo); + } + }); + + return list; + } } diff --git a/service/src/main/java/cn/bunny/services/service/process/RouterServiceProcess.java b/service/src/main/java/cn/bunny/services/service/process/RouterServiceProcess.java new file mode 100644 index 0000000..813f8ed --- /dev/null +++ b/service/src/main/java/cn/bunny/services/service/process/RouterServiceProcess.java @@ -0,0 +1,62 @@ +package cn.bunny.services.service.process; + +import cn.bunny.dao.vo.common.TreeSelectVo; +import cn.bunny.dao.vo.router.RouterControllerVo; +import cn.bunny.dao.vo.router.UserRouterVo; +import org.jetbrains.annotations.NotNull; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class RouterServiceProcess { + + /** + * * 递归调用设置子路由 + * + * @param id 主键 + * @param routerVoList 返回VO列表 + * @return 返回路由列表 + */ + public List handleGetChildrenWIthRouter(Long id, @NotNull List routerVoList) { + List list = new ArrayList<>(); + for (UserRouterVo routerVo : routerVoList) { + if (routerVo.getParentId().equals(id)) { + routerVo.setChildren(handleGetChildrenWIthRouter(routerVo.getId(), routerVoList)); + list.add(routerVo); + } + } + + return list; + } + + /** + * * 递归调用设置管理子路由 + * + * @param nodeId 主键 + * @param nodeList 返回VO列表 + * @return 返回路由列表 + */ + public List handleGetChildrenWithRouterControllerVo(Long nodeId, List nodeList) { + return nodeList.stream() + .filter(node -> node.getParentId().equals(nodeId)) + .peek(node -> node.setChildren(handleGetChildrenWithRouterControllerVo(node.getId(), nodeList))) + .toList(); + } + + /** + * * 整理树形结构 + * + * @param nodeId 节点ID + * @param nodeList 节点列表 + * @return 树形列表 + */ + public List handleGetTreeSelectList(Object nodeId, @NotNull List nodeList) { + // 使用 Stream API 找到所有子节点 + return nodeList.stream() + .filter(node -> node.getParentId().equals(nodeId)) + .peek(node -> node.setChildren(handleGetTreeSelectList(node.getValue(), nodeList))) + .toList(); + } +} diff --git a/service/src/main/resources/mapper/PowerMapper.xml b/service/src/main/resources/mapper/PowerMapper.xml index 78c203f..353303a 100644 --- a/service/src/main/resources/mapper/PowerMapper.xml +++ b/service/src/main/resources/mapper/PowerMapper.xml @@ -33,5 +33,10 @@ AND rp.power_id = p.id AND u.id = #{userId} - + diff --git a/service/src/main/resources/mapper/RouterMapper.xml b/service/src/main/resources/mapper/RouterMapper.xml index 713dcab..145e26f 100644 --- a/service/src/main/resources/mapper/RouterMapper.xml +++ b/service/src/main/resources/mapper/RouterMapper.xml @@ -5,7 +5,7 @@ - + @@ -14,14 +14,39 @@ - + - id, router_path, route_name, parent_id, title, icon, router_rank, visible, create_user, update_user, create_time, update_time, is_deleted + id, path, route_name, parent_id, title, icon, router_rank, visible, create_user, update_user, update_time, create_time, is_deleted + + + +