Commit bbe71ec2c893abc4e8a4a983f48e416f9e3e94db
1 parent
aa38c0f9
完成部分权限的认证操作的迁移
Showing
39 changed files
with
370 additions
and
394 deletions
http-client.env.json
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
| @@ -9,17 +9,15 @@ import com.ruoyi.framework.web.domain.Server; | @@ -9,17 +9,15 @@ import com.ruoyi.framework.web.domain.Server; | ||
| 9 | 9 | ||
| 10 | /** | 10 | /** |
| 11 | * 服务器监控 | 11 | * 服务器监控 |
| 12 | - * | 12 | + * |
| 13 | * @author ruoyi | 13 | * @author ruoyi |
| 14 | */ | 14 | */ |
| 15 | @RestController | 15 | @RestController |
| 16 | @RequestMapping("/monitor/server") | 16 | @RequestMapping("/monitor/server") |
| 17 | -public class ServerController | ||
| 18 | -{ | 17 | +public class ServerController { |
| 19 | @PreAuthorize("@ss.hasPermi('monitor:server:list')") | 18 | @PreAuthorize("@ss.hasPermi('monitor:server:list')") |
| 20 | @GetMapping() | 19 | @GetMapping() |
| 21 | - public AjaxResult getInfo() throws Exception | ||
| 22 | - { | 20 | + public AjaxResult getInfo() throws Exception { |
| 23 | Server server = new Server(); | 21 | Server server = new Server(); |
| 24 | server.copyTo(); | 22 | server.copyTo(); |
| 25 | return AjaxResult.success(server); | 23 | return AjaxResult.success(server); |
ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/SwaggerController.java renamed to ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SwaggerController.java
| 1 | -package com.ruoyi.web.controller.tool; | ||
| 2 | - | ||
| 3 | -import org.springframework.security.access.prepost.PreAuthorize; | ||
| 4 | -import org.springframework.stereotype.Controller; | ||
| 5 | -import org.springframework.web.bind.annotation.GetMapping; | ||
| 6 | -import org.springframework.web.bind.annotation.RequestMapping; | ||
| 7 | -import com.ruoyi.common.core.controller.BaseController; | ||
| 8 | - | ||
| 9 | -/** | ||
| 10 | - * swagger 接口 | ||
| 11 | - * | ||
| 12 | - * @author ruoyi | ||
| 13 | - */ | ||
| 14 | -@Controller | ||
| 15 | -@RequestMapping("/tool/swagger") | ||
| 16 | -public class SwaggerController extends BaseController | ||
| 17 | -{ | ||
| 18 | - @PreAuthorize("@ss.hasPermi('tool:swagger:view')") | ||
| 19 | - @GetMapping() | ||
| 20 | - public String index() | ||
| 21 | - { | ||
| 22 | - return redirect("/swagger-ui.html"); | ||
| 23 | - } | ||
| 24 | -} | 1 | +package com.ruoyi.web.controller.tool; |
| 2 | + | ||
| 3 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 4 | +import org.springframework.stereotype.Controller; | ||
| 5 | +import org.springframework.web.bind.annotation.GetMapping; | ||
| 6 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 7 | +import com.ruoyi.common.core.controller.BaseController; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * swagger 接口 | ||
| 11 | + * | ||
| 12 | + * @author ruoyi | ||
| 13 | + */ | ||
| 14 | +@Controller | ||
| 15 | +@RequestMapping("/tool/swagger") | ||
| 16 | +public class SwaggerController extends BaseController | ||
| 17 | +{ | ||
| 18 | + @PreAuthorize("@ss.hasPermi('tool:swagger:view')") | ||
| 19 | + @GetMapping() | ||
| 20 | + public String index() | ||
| 21 | + { | ||
| 22 | + return redirect("/swagger-ui.html"); | ||
| 23 | + } | ||
| 24 | +} |
ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnline.java
| @@ -5,31 +5,45 @@ package com.ruoyi.system.domain; | @@ -5,31 +5,45 @@ package com.ruoyi.system.domain; | ||
| 5 | * | 5 | * |
| 6 | * @author ruoyi | 6 | * @author ruoyi |
| 7 | */ | 7 | */ |
| 8 | -public class SysUserOnline | ||
| 9 | -{ | ||
| 10 | - /** 会话编号 */ | 8 | +public class SysUserOnline { |
| 9 | + /** | ||
| 10 | + * 会话编号 | ||
| 11 | + */ | ||
| 11 | private String tokenId; | 12 | private String tokenId; |
| 12 | 13 | ||
| 13 | - /** 部门名称 */ | 14 | + /** |
| 15 | + * 部门名称 | ||
| 16 | + */ | ||
| 14 | private String deptName; | 17 | private String deptName; |
| 15 | 18 | ||
| 16 | - /** 用户名称 */ | 19 | + /** |
| 20 | + * 用户名称 | ||
| 21 | + */ | ||
| 17 | private String userName; | 22 | private String userName; |
| 18 | 23 | ||
| 19 | - /** 登录IP地址 */ | 24 | + /** |
| 25 | + * 登录IP地址 | ||
| 26 | + */ | ||
| 20 | private String ipaddr; | 27 | private String ipaddr; |
| 21 | 28 | ||
| 22 | - /** 登录地址 */ | 29 | + /** |
| 30 | + * 登录地址 | ||
| 31 | + */ | ||
| 23 | private String loginLocation; | 32 | private String loginLocation; |
| 24 | 33 | ||
| 25 | - /** 浏览器类型 */ | 34 | + /** |
| 35 | + * 浏览器类型 | ||
| 36 | + */ | ||
| 26 | private String browser; | 37 | private String browser; |
| 27 | 38 | ||
| 28 | - /** 操作系统 */ | 39 | + /** |
| 40 | + * 操作系统 | ||
| 41 | + */ | ||
| 29 | private String os; | 42 | private String os; |
| 30 | 43 | ||
| 31 | - /** 登录时间 */ | 44 | + /** |
| 45 | + * 登录时间 | ||
| 46 | + */ | ||
| 32 | private Long loginTime; | 47 | private Long loginTime; |
| 33 | 48 | ||
| 34 | - | ||
| 35 | } | 49 | } |
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
| @@ -8,14 +8,13 @@ import java.lang.annotation.Target; | @@ -8,14 +8,13 @@ import java.lang.annotation.Target; | ||
| 8 | 8 | ||
| 9 | /** | 9 | /** |
| 10 | * 数据权限过滤注解 | 10 | * 数据权限过滤注解 |
| 11 | - * | 11 | + * |
| 12 | * @author ruoyi | 12 | * @author ruoyi |
| 13 | */ | 13 | */ |
| 14 | @Target(ElementType.METHOD) | 14 | @Target(ElementType.METHOD) |
| 15 | @Retention(RetentionPolicy.RUNTIME) | 15 | @Retention(RetentionPolicy.RUNTIME) |
| 16 | @Documented | 16 | @Documented |
| 17 | -public @interface DataScope | ||
| 18 | -{ | 17 | +public @interface DataScope { |
| 19 | /** | 18 | /** |
| 20 | * 部门表的别名 | 19 | * 部门表的别名 |
| 21 | */ | 20 | */ |
ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
| @@ -6,21 +6,21 @@ import java.lang.annotation.Inherited; | @@ -6,21 +6,21 @@ import java.lang.annotation.Inherited; | ||
| 6 | import java.lang.annotation.Retention; | 6 | import java.lang.annotation.Retention; |
| 7 | import java.lang.annotation.RetentionPolicy; | 7 | import java.lang.annotation.RetentionPolicy; |
| 8 | import java.lang.annotation.Target; | 8 | import java.lang.annotation.Target; |
| 9 | + | ||
| 9 | import com.ruoyi.common.enums.DataSourceType; | 10 | import com.ruoyi.common.enums.DataSourceType; |
| 10 | 11 | ||
| 11 | /** | 12 | /** |
| 12 | * 自定义多数据源切换注解 | 13 | * 自定义多数据源切换注解 |
| 13 | - * | 14 | + * <p> |
| 14 | * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 | 15 | * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准 |
| 15 | * | 16 | * |
| 16 | * @author ruoyi | 17 | * @author ruoyi |
| 17 | */ | 18 | */ |
| 18 | -@Target({ ElementType.METHOD, ElementType.TYPE }) | 19 | +@Target({ElementType.METHOD, ElementType.TYPE}) |
| 19 | @Retention(RetentionPolicy.RUNTIME) | 20 | @Retention(RetentionPolicy.RUNTIME) |
| 20 | @Documented | 21 | @Documented |
| 21 | @Inherited | 22 | @Inherited |
| 22 | -public @interface DataSource | ||
| 23 | -{ | 23 | +public @interface DataSource { |
| 24 | /** | 24 | /** |
| 25 | * 切换数据源名称 | 25 | * 切换数据源名称 |
| 26 | */ | 26 | */ |
ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
| @@ -9,15 +9,13 @@ import java.lang.annotation.Target; | @@ -9,15 +9,13 @@ import java.lang.annotation.Target; | ||
| 9 | 9 | ||
| 10 | /** | 10 | /** |
| 11 | * 自定义注解防止表单重复提交 | 11 | * 自定义注解防止表单重复提交 |
| 12 | - * | ||
| 13 | - * @author ruoyi | ||
| 14 | * | 12 | * |
| 13 | + * @author ruoyi | ||
| 15 | */ | 14 | */ |
| 16 | @Inherited | 15 | @Inherited |
| 17 | @Target(ElementType.METHOD) | 16 | @Target(ElementType.METHOD) |
| 18 | @Retention(RetentionPolicy.RUNTIME) | 17 | @Retention(RetentionPolicy.RUNTIME) |
| 19 | @Documented | 18 | @Documented |
| 20 | -public @interface RepeatSubmit | ||
| 21 | -{ | 19 | +public @interface RepeatSubmit { |
| 22 | 20 | ||
| 23 | } | 21 | } |
ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
| @@ -2,7 +2,7 @@ package com.ruoyi.common.constant; | @@ -2,7 +2,7 @@ package com.ruoyi.common.constant; | ||
| 2 | 2 | ||
| 3 | /** | 3 | /** |
| 4 | * 代码生成通用常量 | 4 | * 代码生成通用常量 |
| 5 | - * | 5 | + * |
| 6 | * @author ruoyi | 6 | * @author ruoyi |
| 7 | */ | 7 | */ |
| 8 | public class GenConstants | 8 | public class GenConstants |
| @@ -13,6 +13,7 @@ public class GenConstants | @@ -13,6 +13,7 @@ public class GenConstants | ||
| 13 | /** 树表(增删改查) */ | 13 | /** 树表(增删改查) */ |
| 14 | public static final String TPL_TREE = "tree"; | 14 | public static final String TPL_TREE = "tree"; |
| 15 | 15 | ||
| 16 | + | ||
| 16 | /** 树编码字段 */ | 17 | /** 树编码字段 */ |
| 17 | public static final String TREE_CODE = "treeCode"; | 18 | public static final String TREE_CODE = "treeCode"; |
| 18 | 19 |
ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
| @@ -8,45 +8,38 @@ import javax.servlet.ServletException; | @@ -8,45 +8,38 @@ import javax.servlet.ServletException; | ||
| 8 | import javax.servlet.ServletRequest; | 8 | import javax.servlet.ServletRequest; |
| 9 | import javax.servlet.ServletResponse; | 9 | import javax.servlet.ServletResponse; |
| 10 | import javax.servlet.http.HttpServletRequest; | 10 | import javax.servlet.http.HttpServletRequest; |
| 11 | + | ||
| 11 | import org.springframework.http.MediaType; | 12 | import org.springframework.http.MediaType; |
| 12 | import com.ruoyi.common.utils.StringUtils; | 13 | import com.ruoyi.common.utils.StringUtils; |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * Repeatable 过滤器 | 16 | * Repeatable 过滤器 |
| 16 | - * | 17 | + * |
| 17 | * @author ruoyi | 18 | * @author ruoyi |
| 18 | */ | 19 | */ |
| 19 | -public class RepeatableFilter implements Filter | ||
| 20 | -{ | 20 | +public class RepeatableFilter implements Filter { |
| 21 | @Override | 21 | @Override |
| 22 | - public void init(FilterConfig filterConfig) throws ServletException | ||
| 23 | - { | 22 | + public void init(FilterConfig filterConfig) throws ServletException { |
| 24 | 23 | ||
| 25 | } | 24 | } |
| 26 | 25 | ||
| 27 | @Override | 26 | @Override |
| 28 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) | 27 | public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) |
| 29 | - throws IOException, ServletException | ||
| 30 | - { | 28 | + throws IOException, ServletException { |
| 31 | ServletRequest requestWrapper = null; | 29 | ServletRequest requestWrapper = null; |
| 32 | if (request instanceof HttpServletRequest | 30 | if (request instanceof HttpServletRequest |
| 33 | - && StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) | ||
| 34 | - { | 31 | + && StringUtils.equalsAnyIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE)) { |
| 35 | requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); | 32 | requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response); |
| 36 | } | 33 | } |
| 37 | - if (null == requestWrapper) | ||
| 38 | - { | 34 | + if (null == requestWrapper) { |
| 39 | chain.doFilter(request, response); | 35 | chain.doFilter(request, response); |
| 40 | - } | ||
| 41 | - else | ||
| 42 | - { | 36 | + } else { |
| 43 | chain.doFilter(requestWrapper, response); | 37 | chain.doFilter(requestWrapper, response); |
| 44 | } | 38 | } |
| 45 | } | 39 | } |
| 46 | 40 | ||
| 47 | @Override | 41 | @Override |
| 48 | - public void destroy() | ||
| 49 | - { | 42 | + public void destroy() { |
| 50 | 43 | ||
| 51 | } | 44 | } |
| 52 | } | 45 | } |
ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
| @@ -9,19 +9,18 @@ import javax.servlet.ServletInputStream; | @@ -9,19 +9,18 @@ import javax.servlet.ServletInputStream; | ||
| 9 | import javax.servlet.ServletResponse; | 9 | import javax.servlet.ServletResponse; |
| 10 | import javax.servlet.http.HttpServletRequest; | 10 | import javax.servlet.http.HttpServletRequest; |
| 11 | import javax.servlet.http.HttpServletRequestWrapper; | 11 | import javax.servlet.http.HttpServletRequestWrapper; |
| 12 | + | ||
| 12 | import com.ruoyi.common.utils.http.HttpHelper; | 13 | import com.ruoyi.common.utils.http.HttpHelper; |
| 13 | 14 | ||
| 14 | /** | 15 | /** |
| 15 | * 构建可重复读取inputStream的request | 16 | * 构建可重复读取inputStream的request |
| 16 | - * | 17 | + * |
| 17 | * @author ruoyi | 18 | * @author ruoyi |
| 18 | */ | 19 | */ |
| 19 | -public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper | ||
| 20 | -{ | 20 | +public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper { |
| 21 | private final byte[] body; | 21 | private final byte[] body; |
| 22 | 22 | ||
| 23 | - public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException | ||
| 24 | - { | 23 | + public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException { |
| 25 | super(request); | 24 | super(request); |
| 26 | request.setCharacterEncoding("UTF-8"); | 25 | request.setCharacterEncoding("UTF-8"); |
| 27 | response.setCharacterEncoding("UTF-8"); | 26 | response.setCharacterEncoding("UTF-8"); |
| @@ -30,41 +29,34 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper | @@ -30,41 +29,34 @@ public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper | ||
| 30 | } | 29 | } |
| 31 | 30 | ||
| 32 | @Override | 31 | @Override |
| 33 | - public BufferedReader getReader() throws IOException | ||
| 34 | - { | 32 | + public BufferedReader getReader() throws IOException { |
| 35 | return new BufferedReader(new InputStreamReader(getInputStream())); | 33 | return new BufferedReader(new InputStreamReader(getInputStream())); |
| 36 | } | 34 | } |
| 37 | 35 | ||
| 38 | @Override | 36 | @Override |
| 39 | - public ServletInputStream getInputStream() throws IOException | ||
| 40 | - { | 37 | + public ServletInputStream getInputStream() throws IOException { |
| 41 | 38 | ||
| 42 | final ByteArrayInputStream bais = new ByteArrayInputStream(body); | 39 | final ByteArrayInputStream bais = new ByteArrayInputStream(body); |
| 43 | 40 | ||
| 44 | - return new ServletInputStream() | ||
| 45 | - { | 41 | + return new ServletInputStream() { |
| 46 | 42 | ||
| 47 | @Override | 43 | @Override |
| 48 | - public int read() throws IOException | ||
| 49 | - { | 44 | + public int read() throws IOException { |
| 50 | return bais.read(); | 45 | return bais.read(); |
| 51 | } | 46 | } |
| 52 | 47 | ||
| 53 | @Override | 48 | @Override |
| 54 | - public boolean isFinished() | ||
| 55 | - { | 49 | + public boolean isFinished() { |
| 56 | return false; | 50 | return false; |
| 57 | } | 51 | } |
| 58 | 52 | ||
| 59 | @Override | 53 | @Override |
| 60 | - public boolean isReady() | ||
| 61 | - { | 54 | + public boolean isReady() { |
| 62 | return false; | 55 | return false; |
| 63 | } | 56 | } |
| 64 | 57 | ||
| 65 | @Override | 58 | @Override |
| 66 | - public void setReadListener(ReadListener readListener) | ||
| 67 | - { | 59 | + public void setReadListener(ReadListener readListener) { |
| 68 | 60 | ||
| 69 | } | 61 | } |
| 70 | }; | 62 | }; |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java
| @@ -55,46 +55,6 @@ public class Server { | @@ -55,46 +55,6 @@ public class Server { | ||
| 55 | */ | 55 | */ |
| 56 | private List<SysFile> sysFiles = new LinkedList<SysFile>(); | 56 | private List<SysFile> sysFiles = new LinkedList<SysFile>(); |
| 57 | 57 | ||
| 58 | - public Cpu getCpu() { | ||
| 59 | - return cpu; | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - public void setCpu(Cpu cpu) { | ||
| 63 | - this.cpu = cpu; | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - public Mem getMem() { | ||
| 67 | - return mem; | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - public void setMem(Mem mem) { | ||
| 71 | - this.mem = mem; | ||
| 72 | - } | ||
| 73 | - | ||
| 74 | - public Jvm getJvm() { | ||
| 75 | - return jvm; | ||
| 76 | - } | ||
| 77 | - | ||
| 78 | - public void setJvm(Jvm jvm) { | ||
| 79 | - this.jvm = jvm; | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - public Sys getSys() { | ||
| 83 | - return sys; | ||
| 84 | - } | ||
| 85 | - | ||
| 86 | - public void setSys(Sys sys) { | ||
| 87 | - this.sys = sys; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - public List<SysFile> getSysFiles() { | ||
| 91 | - return sysFiles; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | - public void setSysFiles(List<SysFile> sysFiles) { | ||
| 95 | - this.sysFiles = sysFiles; | ||
| 96 | - } | ||
| 97 | - | ||
| 98 | public void copyTo() throws Exception { | 58 | public void copyTo() throws Exception { |
| 99 | SystemInfo si = new SystemInfo(); | 59 | SystemInfo si = new SystemInfo(); |
| 100 | HardwareAbstractionLayer hal = si.getHardware(); | 60 | HardwareAbstractionLayer hal = si.getHardware(); |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
| @@ -38,22 +38,10 @@ public class Cpu { | @@ -38,22 +38,10 @@ public class Cpu { | ||
| 38 | */ | 38 | */ |
| 39 | private double free; | 39 | private double free; |
| 40 | 40 | ||
| 41 | - public int getCpuNum() { | ||
| 42 | - return cpuNum; | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - public void setCpuNum(int cpuNum) { | ||
| 46 | - this.cpuNum = cpuNum; | ||
| 47 | - } | ||
| 48 | - | ||
| 49 | public double getTotal() { | 41 | public double getTotal() { |
| 50 | return Arith.round(Arith.mul(total, 100), 2); | 42 | return Arith.round(Arith.mul(total, 100), 2); |
| 51 | } | 43 | } |
| 52 | 44 | ||
| 53 | - public void setTotal(double total) { | ||
| 54 | - this.total = total; | ||
| 55 | - } | ||
| 56 | - | ||
| 57 | public double getSys() { | 45 | public double getSys() { |
| 58 | return Arith.round(Arith.mul(sys / total, 100), 2); | 46 | return Arith.round(Arith.mul(sys / total, 100), 2); |
| 59 | } | 47 | } |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
| @@ -40,18 +40,10 @@ public class Jvm { | @@ -40,18 +40,10 @@ public class Jvm { | ||
| 40 | return Arith.div(total, (1024 * 1024), 2); | 40 | return Arith.div(total, (1024 * 1024), 2); |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | - public void setTotal(double total) { | ||
| 44 | - this.total = total; | ||
| 45 | - } | ||
| 46 | - | ||
| 47 | public double getMax() { | 43 | public double getMax() { |
| 48 | return Arith.div(max, (1024 * 1024), 2); | 44 | return Arith.div(max, (1024 * 1024), 2); |
| 49 | } | 45 | } |
| 50 | 46 | ||
| 51 | - public void setMax(double max) { | ||
| 52 | - this.max = max; | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | public double getFree() { | 47 | public double getFree() { |
| 56 | return Arith.div(free, (1024 * 1024), 2); | 48 | return Arith.div(free, (1024 * 1024), 2); |
| 57 | } | 49 | } |
| @@ -75,22 +67,6 @@ public class Jvm { | @@ -75,22 +67,6 @@ public class Jvm { | ||
| 75 | return ManagementFactory.getRuntimeMXBean().getVmName(); | 67 | return ManagementFactory.getRuntimeMXBean().getVmName(); |
| 76 | } | 68 | } |
| 77 | 69 | ||
| 78 | - public String getVersion() { | ||
| 79 | - return version; | ||
| 80 | - } | ||
| 81 | - | ||
| 82 | - public void setVersion(String version) { | ||
| 83 | - this.version = version; | ||
| 84 | - } | ||
| 85 | - | ||
| 86 | - public String getHome() { | ||
| 87 | - return home; | ||
| 88 | - } | ||
| 89 | - | ||
| 90 | - public void setHome(String home) { | ||
| 91 | - this.home = home; | ||
| 92 | - } | ||
| 93 | - | ||
| 94 | /** | 70 | /** |
| 95 | * JDK启动时间 | 71 | * JDK启动时间 |
| 96 | */ | 72 | */ |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
| @@ -27,27 +27,16 @@ public class Mem { | @@ -27,27 +27,16 @@ public class Mem { | ||
| 27 | return Arith.div(total, (1024 * 1024 * 1024), 2); | 27 | return Arith.div(total, (1024 * 1024 * 1024), 2); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | - public void setTotal(long total) { | ||
| 31 | - this.total = total; | ||
| 32 | - } | ||
| 33 | - | ||
| 34 | public double getUsed() { | 30 | public double getUsed() { |
| 35 | return Arith.div(used, (1024 * 1024 * 1024), 2); | 31 | return Arith.div(used, (1024 * 1024 * 1024), 2); |
| 36 | } | 32 | } |
| 37 | 33 | ||
| 38 | - public void setUsed(long used) { | ||
| 39 | - this.used = used; | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | public double getFree() { | 34 | public double getFree() { |
| 43 | return Arith.div(free, (1024 * 1024 * 1024), 2); | 35 | return Arith.div(free, (1024 * 1024 * 1024), 2); |
| 44 | } | 36 | } |
| 45 | 37 | ||
| 46 | - public void setFree(long free) { | ||
| 47 | - this.free = free; | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | public double getUsage() { | 38 | public double getUsage() { |
| 51 | return Arith.mul(Arith.div(used, total, 4), 100); | 39 | return Arith.mul(Arith.div(used, total, 4), 100); |
| 52 | } | 40 | } |
| 41 | + | ||
| 53 | } | 42 | } |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
| @@ -31,43 +31,4 @@ public class Sys { | @@ -31,43 +31,4 @@ public class Sys { | ||
| 31 | */ | 31 | */ |
| 32 | private String osArch; | 32 | private String osArch; |
| 33 | 33 | ||
| 34 | - public String getComputerName() { | ||
| 35 | - return computerName; | ||
| 36 | - } | ||
| 37 | - | ||
| 38 | - public void setComputerName(String computerName) { | ||
| 39 | - this.computerName = computerName; | ||
| 40 | - } | ||
| 41 | - | ||
| 42 | - public String getComputerIp() { | ||
| 43 | - return computerIp; | ||
| 44 | - } | ||
| 45 | - | ||
| 46 | - public void setComputerIp(String computerIp) { | ||
| 47 | - this.computerIp = computerIp; | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | - public String getUserDir() { | ||
| 51 | - return userDir; | ||
| 52 | - } | ||
| 53 | - | ||
| 54 | - public void setUserDir(String userDir) { | ||
| 55 | - this.userDir = userDir; | ||
| 56 | - } | ||
| 57 | - | ||
| 58 | - public String getOsName() { | ||
| 59 | - return osName; | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - public void setOsName(String osName) { | ||
| 63 | - this.osName = osName; | ||
| 64 | - } | ||
| 65 | - | ||
| 66 | - public String getOsArch() { | ||
| 67 | - return osArch; | ||
| 68 | - } | ||
| 69 | - | ||
| 70 | - public void setOsArch(String osArch) { | ||
| 71 | - this.osArch = osArch; | ||
| 72 | - } | ||
| 73 | } | 34 | } |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
| @@ -41,59 +41,4 @@ public class SysFile { | @@ -41,59 +41,4 @@ public class SysFile { | ||
| 41 | */ | 41 | */ |
| 42 | private double usage; | 42 | private double usage; |
| 43 | 43 | ||
| 44 | - public String getDirName() { | ||
| 45 | - return dirName; | ||
| 46 | - } | ||
| 47 | - | ||
| 48 | - public void setDirName(String dirName) { | ||
| 49 | - this.dirName = dirName; | ||
| 50 | - } | ||
| 51 | - | ||
| 52 | - public String getSysTypeName() { | ||
| 53 | - return sysTypeName; | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | - public void setSysTypeName(String sysTypeName) { | ||
| 57 | - this.sysTypeName = sysTypeName; | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - public String getTypeName() { | ||
| 61 | - return typeName; | ||
| 62 | - } | ||
| 63 | - | ||
| 64 | - public void setTypeName(String typeName) { | ||
| 65 | - this.typeName = typeName; | ||
| 66 | - } | ||
| 67 | - | ||
| 68 | - public String getTotal() { | ||
| 69 | - return total; | ||
| 70 | - } | ||
| 71 | - | ||
| 72 | - public void setTotal(String total) { | ||
| 73 | - this.total = total; | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - public String getFree() { | ||
| 77 | - return free; | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - public void setFree(String free) { | ||
| 81 | - this.free = free; | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - public String getUsed() { | ||
| 85 | - return used; | ||
| 86 | - } | ||
| 87 | - | ||
| 88 | - public void setUsed(String used) { | ||
| 89 | - this.used = used; | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - public double getUsage() { | ||
| 93 | - return usage; | ||
| 94 | - } | ||
| 95 | - | ||
| 96 | - public void setUsage(double usage) { | ||
| 97 | - this.usage = usage; | ||
| 98 | - } | ||
| 99 | } | 44 | } |
ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
| @@ -17,68 +17,6 @@ import com.ruoyi.common.utils.StringUtils; | @@ -17,68 +17,6 @@ import com.ruoyi.common.utils.StringUtils; | ||
| 17 | */ | 17 | */ |
| 18 | @Service("ss") | 18 | @Service("ss") |
| 19 | public class PermissionService { | 19 | public class PermissionService { |
| 20 | - /** | ||
| 21 | - * 所有权限标识 | ||
| 22 | - */ | ||
| 23 | - private static final String ALL_PERMISSION = "*:*:*"; | ||
| 24 | - | ||
| 25 | - /** | ||
| 26 | - * 管理员角色权限标识 | ||
| 27 | - */ | ||
| 28 | - private static final String SUPER_ADMIN = "admin"; | ||
| 29 | - | ||
| 30 | - @Autowired | ||
| 31 | - private TokenService tokenService; | ||
| 32 | - | ||
| 33 | - /** | ||
| 34 | - * 验证用户是否具备某权限 | ||
| 35 | - * | ||
| 36 | - * @param permission 权限字符串 | ||
| 37 | - * @return 用户是否具备某权限 | ||
| 38 | - */ | ||
| 39 | - public boolean hasPermi(String permission) { | ||
| 40 | - if (StringUtils.isEmpty(permission)) { | ||
| 41 | - return false; | ||
| 42 | - } | ||
| 43 | - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); | ||
| 44 | - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { | ||
| 45 | - return false; | ||
| 46 | - } | ||
| 47 | - return hasPermissions(loginUser.getPermissions(), permission); | ||
| 48 | - } | ||
| 49 | - | ||
| 50 | - /** | ||
| 51 | - * 验证用户是否不具备某权限,与 hasPermi逻辑相反 | ||
| 52 | - * | ||
| 53 | - * @param permission 权限字符串 | ||
| 54 | - * @return 用户是否不具备某权限 | ||
| 55 | - */ | ||
| 56 | - public boolean lacksPermi(String permission) { | ||
| 57 | - return hasPermi(permission) != true; | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - /** | ||
| 61 | - * 验证用户是否具有以下任意一个权限 | ||
| 62 | - * | ||
| 63 | - * @param permissions 以 PERMISSION_NAMES_DELIMETER 为分隔符的权限列表 | ||
| 64 | - * @return 用户是否具有以下任意一个权限 | ||
| 65 | - */ | ||
| 66 | - public boolean hasAnyPermi(String permissions) { | ||
| 67 | - if (StringUtils.isEmpty(permissions)) { | ||
| 68 | - return false; | ||
| 69 | - } | ||
| 70 | - LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest()); | ||
| 71 | - if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions())) { | ||
| 72 | - return false; | ||
| 73 | - } | ||
| 74 | - Set<String> authorities = loginUser.getPermissions(); | ||
| 75 | - for (String permission : permissions.split(PERMISSION_DELIMETER)) { | ||
| 76 | - if (permission != null && hasPermissions(authorities, permission)) { | ||
| 77 | - return true; | ||
| 78 | - } | ||
| 79 | - } | ||
| 80 | - return false; | ||
| 81 | - } | ||
| 82 | 20 | ||
| 83 | /** | 21 | /** |
| 84 | * 判断用户是否拥有某个角色 | 22 | * 判断用户是否拥有某个角色 |
| @@ -104,16 +42,6 @@ public class PermissionService { | @@ -104,16 +42,6 @@ public class PermissionService { | ||
| 104 | } | 42 | } |
| 105 | 43 | ||
| 106 | /** | 44 | /** |
| 107 | - * 验证用户是否不具备某角色,与 isRole逻辑相反。 | ||
| 108 | - * | ||
| 109 | - * @param role 角色名称 | ||
| 110 | - * @return 用户是否不具备某角色 | ||
| 111 | - */ | ||
| 112 | - public boolean lacksRole(String role) { | ||
| 113 | - return hasRole(role) != true; | ||
| 114 | - } | ||
| 115 | - | ||
| 116 | - /** | ||
| 117 | * 验证用户是否具有以下任意一个角色 | 45 | * 验证用户是否具有以下任意一个角色 |
| 118 | * | 46 | * |
| 119 | * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 | 47 | * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表 |
| @@ -135,14 +63,4 @@ public class PermissionService { | @@ -135,14 +63,4 @@ public class PermissionService { | ||
| 135 | return false; | 63 | return false; |
| 136 | } | 64 | } |
| 137 | 65 | ||
| 138 | - /** | ||
| 139 | - * 判断是否包含权限 | ||
| 140 | - * | ||
| 141 | - * @param permissions 权限列表 | ||
| 142 | - * @param permission 权限字符串 | ||
| 143 | - * @return 用户是否具备某权限 | ||
| 144 | - */ | ||
| 145 | - private boolean hasPermissions(Set<String> permissions, String permission) { | ||
| 146 | - return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission)); | ||
| 147 | - } | ||
| 148 | } | 66 | } |
ruoyi-ui/src/utils/request.js
| @@ -61,7 +61,9 @@ service.interceptors.response.use(res => { | @@ -61,7 +61,9 @@ service.interceptors.response.use(res => { | ||
| 61 | } | 61 | } |
| 62 | ).then(() => { | 62 | ).then(() => { |
| 63 | store.dispatch('LogOut').then(() => { | 63 | store.dispatch('LogOut').then(() => { |
| 64 | - location.href = '/index'; | 64 | + if (location.pathname !== '/login') { // 避免重复跳转 |
| 65 | + location.href = '/index'; | ||
| 66 | + } | ||
| 65 | }) | 67 | }) |
| 66 | }) | 68 | }) |
| 67 | } else if (code === 500) { | 69 | } else if (code === 500) { |
ruoyi-ui/src/views/system/role/index.vue
| @@ -392,6 +392,7 @@ export default { | @@ -392,6 +392,7 @@ export default { | ||
| 392 | menuIds: [], | 392 | menuIds: [], |
| 393 | dataScope: undefined, | 393 | dataScope: undefined, |
| 394 | deptCheckStrictly: false, | 394 | deptCheckStrictly: false, |
| 395 | + menuCheckStrictly: true, | ||
| 395 | remark: undefined | 396 | remark: undefined |
| 396 | }; | 397 | }; |
| 397 | this.resetForm("form"); | 398 | this.resetForm("form"); |
| @@ -471,8 +472,12 @@ export default { | @@ -471,8 +472,12 @@ export default { | ||
| 471 | }); | 472 | }); |
| 472 | // 获得角色拥有的菜单集合 | 473 | // 获得角色拥有的菜单集合 |
| 473 | listRoleMenus(id).then(response => { | 474 | listRoleMenus(id).then(response => { |
| 475 | + // 设置为严格,避免设置父节点自动选中子节点,解决半选中问题 | ||
| 476 | + this.form.menuCheckStrictly = true | ||
| 474 | // 设置选中 | 477 | // 设置选中 |
| 475 | - this.$refs.menu.setCheckedKeys(response.data, true, false); | 478 | + this.$refs.menu.setCheckedKeys(response.data); |
| 479 | + // 设置为非严格,继续使用半选中 | ||
| 480 | + this.form.menuCheckStrictly = false | ||
| 476 | }) | 481 | }) |
| 477 | }, | 482 | }, |
| 478 | /** 分配数据权限操作 */ | 483 | /** 分配数据权限操作 */ |
| @@ -523,7 +528,7 @@ export default { | @@ -523,7 +528,7 @@ export default { | ||
| 523 | roleId: this.form.id, | 528 | roleId: this.form.id, |
| 524 | dataScope: this.form.dataScope, | 529 | dataScope: this.form.dataScope, |
| 525 | dataScopeDeptIds: this.form.dataScope !== SysDataScopeEnum.DEPT_CUSTOM ? [] : | 530 | dataScopeDeptIds: this.form.dataScope !== SysDataScopeEnum.DEPT_CUSTOM ? [] : |
| 526 | - this.$refs.dept.getCheckedKeys(false) | 531 | + this.$refs.dept.getCheckedKeys() |
| 527 | }).then(response => { | 532 | }).then(response => { |
| 528 | this.msgSuccess("修改成功"); | 533 | this.msgSuccess("修改成功"); |
| 529 | this.openDataScope = false; | 534 | this.openDataScope = false; |
| @@ -536,7 +541,7 @@ export default { | @@ -536,7 +541,7 @@ export default { | ||
| 536 | if (this.form.id !== undefined) { | 541 | if (this.form.id !== undefined) { |
| 537 | assignRoleMenu({ | 542 | assignRoleMenu({ |
| 538 | roleId: this.form.id, | 543 | roleId: this.form.id, |
| 539 | - menuIds: this.$refs.menu.getCheckedKeys(true) | 544 | + menuIds: [...this.$refs.menu.getCheckedKeys(), ...this.$refs.menu.getHalfCheckedKeys()] |
| 540 | }).then(response => { | 545 | }).then(response => { |
| 541 | this.msgSuccess("修改成功"); | 546 | this.msgSuccess("修改成功"); |
| 542 | this.openMenu = false; | 547 | this.openMenu = false; |
src/main/java/cn/iocoder/dashboard/framework/logger/operatelog/core/aop/OperateLogAspect.java
| @@ -233,11 +233,6 @@ public class OperateLogAspect { | @@ -233,11 +233,6 @@ public class OperateLogAspect { | ||
| 233 | } | 233 | } |
| 234 | } | 234 | } |
| 235 | 235 | ||
| 236 | - private static void fillContentFields(SysOperateLogCreateReqVO operateLogVO) { | ||
| 237 | - operateLogVO.setContent(CONTENT.get()); | ||
| 238 | - operateLogVO.setExts(EXTS.get()); | ||
| 239 | - } | ||
| 240 | - | ||
| 241 | private static boolean isLogEnable(ProceedingJoinPoint joinPoint, OperateLog operateLog) { | 236 | private static boolean isLogEnable(ProceedingJoinPoint joinPoint, OperateLog operateLog) { |
| 242 | // 有 @OperateLog 注解的情况下 | 237 | // 有 @OperateLog 注解的情况下 |
| 243 | if (operateLog != null) { | 238 | if (operateLog != null) { |
src/main/java/cn/iocoder/dashboard/framework/security/core/handler/LogoutSuccessHandlerImpl.java
| @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.framework.security.core.handler; | @@ -2,7 +2,7 @@ package cn.iocoder.dashboard.framework.security.core.handler; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.util.StrUtil; | 3 | import cn.hutool.core.util.StrUtil; |
| 4 | import cn.iocoder.dashboard.framework.security.config.SecurityProperties; | 4 | import cn.iocoder.dashboard.framework.security.config.SecurityProperties; |
| 5 | -import cn.iocoder.dashboard.framework.security.core.service.SecurityFrameworkService; | 5 | +import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService; |
| 6 | import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; | 6 | import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; |
| 7 | import cn.iocoder.dashboard.util.servlet.ServletUtils; | 7 | import cn.iocoder.dashboard.util.servlet.ServletUtils; |
| 8 | import org.springframework.security.core.Authentication; | 8 | import org.springframework.security.core.Authentication; |
| @@ -26,7 +26,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { | @@ -26,7 +26,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { | ||
| 26 | private SecurityProperties securityProperties; | 26 | private SecurityProperties securityProperties; |
| 27 | 27 | ||
| 28 | @Resource | 28 | @Resource |
| 29 | - private SecurityFrameworkService securityFrameworkService; | 29 | + private SecurityAuthFrameworkService securityFrameworkService; |
| 30 | 30 | ||
| 31 | @Override | 31 | @Override |
| 32 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { | 32 | public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { |
src/main/java/cn/iocoder/dashboard/framework/security/core/service/SecurityFrameworkService.java renamed to src/main/java/cn/iocoder/dashboard/framework/security/core/service/SecurityAuthFrameworkService.java
| @@ -4,16 +4,11 @@ import cn.iocoder.dashboard.framework.security.core.LoginUser; | @@ -4,16 +4,11 @@ import cn.iocoder.dashboard.framework.security.core.LoginUser; | ||
| 4 | import org.springframework.security.core.userdetails.UserDetailsService; | 4 | import org.springframework.security.core.userdetails.UserDetailsService; |
| 5 | 5 | ||
| 6 | /** | 6 | /** |
| 7 | - * Security 框架 Service 接口,定义 security 组件需要的功能 | 7 | + * Security 框架 Auth Service 接口,定义 security 组件需要的功能 |
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 8 | */ | 10 | */ |
| 9 | -public interface SecurityFrameworkService extends UserDetailsService { | ||
| 10 | - | ||
| 11 | - /** | ||
| 12 | - * 基于 token 退出登录 | ||
| 13 | - * | ||
| 14 | - * @param token token | ||
| 15 | - */ | ||
| 16 | - void logout(String token); | 11 | +public interface SecurityAuthFrameworkService extends UserDetailsService { |
| 17 | 12 | ||
| 18 | /** | 13 | /** |
| 19 | * 校验 token 的有效性,并获取用户信息 | 14 | * 校验 token 的有效性,并获取用户信息 |
| @@ -32,4 +27,11 @@ public interface SecurityFrameworkService extends UserDetailsService { | @@ -32,4 +27,11 @@ public interface SecurityFrameworkService extends UserDetailsService { | ||
| 32 | */ | 27 | */ |
| 33 | LoginUser mockLogin(Long userId); | 28 | LoginUser mockLogin(Long userId); |
| 34 | 29 | ||
| 30 | + /** | ||
| 31 | + * 基于 token 退出登录 | ||
| 32 | + * | ||
| 33 | + * @param token token | ||
| 34 | + */ | ||
| 35 | + void logout(String token); | ||
| 36 | + | ||
| 35 | } | 37 | } |
src/main/java/cn/iocoder/dashboard/framework/security/core/service/SecurityPermissionFrameworkService.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.framework.security.core.service; | ||
| 2 | + | ||
| 3 | +/** | ||
| 4 | + * Security 框架 Permission Service 接口,定义 security 组件需要的功能 | ||
| 5 | + * | ||
| 6 | + * @author 芋道源码 | ||
| 7 | + */ | ||
| 8 | +public interface SecurityPermissionFrameworkService { | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 判断是否有权限 | ||
| 12 | + * | ||
| 13 | + * @param permission 权限 | ||
| 14 | + * @return 是否 | ||
| 15 | + */ | ||
| 16 | + boolean hasPermission(String permission); | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 判断是否有权限,任一一个即可 | ||
| 20 | + * | ||
| 21 | + * @param permissions 权限 | ||
| 22 | + * @return 是否 | ||
| 23 | + */ | ||
| 24 | + boolean hasAnyPermissions(String... permissions); | ||
| 25 | + | ||
| 26 | +} |
src/main/java/cn/iocoder/dashboard/framework/web/core/handler/GlobalExceptionHandler.java
| @@ -3,7 +3,9 @@ package cn.iocoder.dashboard.framework.web.core.handler; | @@ -3,7 +3,9 @@ package cn.iocoder.dashboard.framework.web.core.handler; | ||
| 3 | import cn.iocoder.dashboard.common.exception.GlobalException; | 3 | import cn.iocoder.dashboard.common.exception.GlobalException; |
| 4 | import cn.iocoder.dashboard.common.exception.ServiceException; | 4 | import cn.iocoder.dashboard.common.exception.ServiceException; |
| 5 | import cn.iocoder.dashboard.common.pojo.CommonResult; | 5 | import cn.iocoder.dashboard.common.pojo.CommonResult; |
| 6 | +import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; | ||
| 6 | import lombok.extern.slf4j.Slf4j; | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | +import org.springframework.security.access.AccessDeniedException; | ||
| 7 | import org.springframework.validation.BindException; | 9 | import org.springframework.validation.BindException; |
| 8 | import org.springframework.validation.FieldError; | 10 | import org.springframework.validation.FieldError; |
| 9 | import org.springframework.web.HttpRequestMethodNotSupportedException; | 11 | import org.springframework.web.HttpRequestMethodNotSupportedException; |
| @@ -64,6 +66,9 @@ public class GlobalExceptionHandler { | @@ -64,6 +66,9 @@ public class GlobalExceptionHandler { | ||
| 64 | if (ex instanceof ServiceException) { | 66 | if (ex instanceof ServiceException) { |
| 65 | return serviceExceptionHandler((ServiceException) ex); | 67 | return serviceExceptionHandler((ServiceException) ex); |
| 66 | } | 68 | } |
| 69 | + if (ex instanceof AccessDeniedException) { | ||
| 70 | + return accessDeniedExceptionHandler(request, (AccessDeniedException) ex); | ||
| 71 | + } | ||
| 67 | if (ex instanceof GlobalException) { | 72 | if (ex instanceof GlobalException) { |
| 68 | return globalExceptionHandler(request, (GlobalException) ex); | 73 | return globalExceptionHandler(request, (GlobalException) ex); |
| 69 | } | 74 | } |
| @@ -131,7 +136,7 @@ public class GlobalExceptionHandler { | @@ -131,7 +136,7 @@ public class GlobalExceptionHandler { | ||
| 131 | public CommonResult<?> validationException(ValidationException ex) { | 136 | public CommonResult<?> validationException(ValidationException ex) { |
| 132 | log.warn("[constraintViolationExceptionHandler]", ex); | 137 | log.warn("[constraintViolationExceptionHandler]", ex); |
| 133 | // 无法拼接明细的错误信息,因为 Dubbo Consumer 抛出 ValidationException 异常时,是直接的字符串信息,且人类不可读 | 138 | // 无法拼接明细的错误信息,因为 Dubbo Consumer 抛出 ValidationException 异常时,是直接的字符串信息,且人类不可读 |
| 134 | - return CommonResult.error(BAD_REQUEST.getCode(), "请求参数不正确"); | 139 | + return CommonResult.error(BAD_REQUEST); |
| 135 | } | 140 | } |
| 136 | 141 | ||
| 137 | /** | 142 | /** |
| @@ -159,6 +164,18 @@ public class GlobalExceptionHandler { | @@ -159,6 +164,18 @@ public class GlobalExceptionHandler { | ||
| 159 | } | 164 | } |
| 160 | 165 | ||
| 161 | /** | 166 | /** |
| 167 | + * 处理 Spring Security 权限不足的异常 | ||
| 168 | + * | ||
| 169 | + * 来源是,使用 @PreAuthorize 注解,AOP 进行权限拦截 | ||
| 170 | + */ | ||
| 171 | + @ExceptionHandler(value = AccessDeniedException.class) | ||
| 172 | + public CommonResult<?> accessDeniedExceptionHandler(HttpServletRequest req, AccessDeniedException ex) { | ||
| 173 | + log.warn("[accessDeniedExceptionHandler][userId({}) 无法访问 url({})]", SecurityUtils.getLoginUserId(), | ||
| 174 | + req.getRequestURL(), ex); | ||
| 175 | + return CommonResult.error(FORBIDDEN); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + /** | ||
| 162 | * 处理业务异常 ServiceException | 179 | * 处理业务异常 ServiceException |
| 163 | * | 180 | * |
| 164 | * 例如说,商品库存不足,用户手机号已存在。 | 181 | * 例如说,商品库存不足,用户手机号已存在。 |
src/main/java/cn/iocoder/dashboard/modules/system/controller/auth/vo/SysAuthLoginReqVO.java
| @@ -7,9 +7,7 @@ import lombok.Builder; | @@ -7,9 +7,7 @@ import lombok.Builder; | ||
| 7 | import lombok.Data; | 7 | import lombok.Data; |
| 8 | import lombok.NoArgsConstructor; | 8 | import lombok.NoArgsConstructor; |
| 9 | import org.hibernate.validator.constraints.Length; | 9 | import org.hibernate.validator.constraints.Length; |
| 10 | -import org.springframework.validation.annotation.Validated; | ||
| 11 | 10 | ||
| 12 | -import javax.validation.Valid; | ||
| 13 | import javax.validation.constraints.NotEmpty; | 11 | import javax.validation.constraints.NotEmpty; |
| 14 | import javax.validation.constraints.Pattern; | 12 | import javax.validation.constraints.Pattern; |
| 15 | 13 | ||
| @@ -22,7 +20,7 @@ public class SysAuthLoginReqVO { | @@ -22,7 +20,7 @@ public class SysAuthLoginReqVO { | ||
| 22 | 20 | ||
| 23 | @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") | 21 | @ApiModelProperty(value = "账号", required = true, example = "yudaoyuanma") |
| 24 | @NotEmpty(message = "登陆账号不能为空") | 22 | @NotEmpty(message = "登陆账号不能为空") |
| 25 | - @Length(min = 5, max = 16, message = "账号长度为 5-16 位") | 23 | + @Length(min = 4, max = 16, message = "账号长度为 4-16 位") |
| 26 | @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") | 24 | @Pattern(regexp = "^[A-Za-z0-9]+$", message = "账号格式为数字以及字母") |
| 27 | private String username; | 25 | private String username; |
| 28 | 26 |
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/SysUserController.http
0 → 100644
src/main/java/cn/iocoder/dashboard/modules/system/controller/user/SysUserController.java
| @@ -18,6 +18,7 @@ import io.swagger.annotations.Api; | @@ -18,6 +18,7 @@ import io.swagger.annotations.Api; | ||
| 18 | import io.swagger.annotations.ApiImplicitParam; | 18 | import io.swagger.annotations.ApiImplicitParam; |
| 19 | import io.swagger.annotations.ApiImplicitParams; | 19 | import io.swagger.annotations.ApiImplicitParams; |
| 20 | import io.swagger.annotations.ApiOperation; | 20 | import io.swagger.annotations.ApiOperation; |
| 21 | +import org.springframework.security.access.prepost.PreAuthorize; | ||
| 21 | import org.springframework.validation.annotation.Validated; | 22 | import org.springframework.validation.annotation.Validated; |
| 22 | import org.springframework.web.bind.annotation.*; | 23 | import org.springframework.web.bind.annotation.*; |
| 23 | import org.springframework.web.multipart.MultipartFile; | 24 | import org.springframework.web.multipart.MultipartFile; |
| @@ -41,7 +42,7 @@ public class SysUserController { | @@ -41,7 +42,7 @@ public class SysUserController { | ||
| 41 | 42 | ||
| 42 | @ApiOperation("获得用户分页列表") | 43 | @ApiOperation("获得用户分页列表") |
| 43 | @GetMapping("/page") | 44 | @GetMapping("/page") |
| 44 | -// @PreAuthorize("@ss.hasPermi('system:user:list')") | 45 | + @PreAuthorize("@ss.hasPermission('system:user:list')") |
| 45 | public CommonResult<PageResult<SysUserPageItemRespVO>> pageUsers(@Validated SysUserPageReqVO reqVO) { | 46 | public CommonResult<PageResult<SysUserPageItemRespVO>> pageUsers(@Validated SysUserPageReqVO reqVO) { |
| 46 | // 获得用户分页列表 | 47 | // 获得用户分页列表 |
| 47 | PageResult<SysUserDO> pageResult = userService.pageUsers(reqVO); | 48 | PageResult<SysUserDO> pageResult = userService.pageUsers(reqVO); |
src/main/java/cn/iocoder/dashboard/modules/system/dal/mysql/dao/permission/SysRoleMenuMapper.java
| 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; | 1 | package cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX; | ||
| 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; | 4 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; |
| 4 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; | 5 | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| 5 | -import com.baomidou.mybatisplus.core.mapper.BaseMapper; | ||
| 6 | import org.apache.ibatis.annotations.Mapper; | 6 | import org.apache.ibatis.annotations.Mapper; |
| 7 | 7 | ||
| 8 | import java.util.Collection; | 8 | import java.util.Collection; |
| 9 | +import java.util.Date; | ||
| 9 | import java.util.List; | 10 | import java.util.List; |
| 10 | import java.util.stream.Collectors; | 11 | import java.util.stream.Collectors; |
| 11 | 12 | ||
| 12 | @Mapper | 13 | @Mapper |
| 13 | -public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenuDO> { | 14 | +public interface SysRoleMenuMapper extends BaseMapperX<SysRoleMenuDO> { |
| 14 | 15 | ||
| 15 | default List<SysRoleMenuDO> selectListByRoleId(Long roleId) { | 16 | default List<SysRoleMenuDO> selectListByRoleId(Long roleId) { |
| 16 | return selectList(new QueryWrapper<SysRoleMenuDO>().eq("role_id", roleId)); | 17 | return selectList(new QueryWrapper<SysRoleMenuDO>().eq("role_id", roleId)); |
| @@ -32,4 +33,9 @@ public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenuDO> { | @@ -32,4 +33,9 @@ public interface SysRoleMenuMapper extends BaseMapper<SysRoleMenuDO> { | ||
| 32 | .in("menu_id", menuIds)); | 33 | .in("menu_id", menuIds)); |
| 33 | } | 34 | } |
| 34 | 35 | ||
| 36 | + default boolean selectExistsByUpdateTimeAfter(Date maxUpdateTime) { | ||
| 37 | + return selectOne(new QueryWrapper<SysRoleMenuDO>().select("id") | ||
| 38 | + .gt("update_time", maxUpdateTime).last("LIMIT 1")) != null; | ||
| 39 | + } | ||
| 40 | + | ||
| 35 | } | 41 | } |
src/main/java/cn/iocoder/dashboard/modules/system/mq/consumer/permission/SysRoleMenuRefreshConsumer.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.consumer.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.AbstractChannelMessageListener; | ||
| 4 | +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; | ||
| 5 | +import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | ||
| 6 | +import lombok.extern.slf4j.Slf4j; | ||
| 7 | +import org.springframework.stereotype.Component; | ||
| 8 | + | ||
| 9 | +import javax.annotation.Resource; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 针对 {@link SysRoleMenuRefreshMessage} 的消费者 | ||
| 13 | + * | ||
| 14 | + * @author 芋道源码 | ||
| 15 | + */ | ||
| 16 | +@Component | ||
| 17 | +@Slf4j | ||
| 18 | +public class SysRoleMenuRefreshConsumer extends AbstractChannelMessageListener<SysRoleMenuRefreshMessage> { | ||
| 19 | + | ||
| 20 | + @Resource | ||
| 21 | + private SysPermissionService permissionService; | ||
| 22 | + | ||
| 23 | + @Override | ||
| 24 | + public void onMessage(SysRoleMenuRefreshMessage message) { | ||
| 25 | + log.info("[onMessage][收到 Role 与 Menu 的关联刷新消息]"); | ||
| 26 | + permissionService.initLocalCache(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/mq/message/permission/SysRoleMenuRefreshMessage.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.message.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.pubsub.ChannelMessage; | ||
| 4 | +import lombok.Data; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 角色与菜单数据刷新 Message | ||
| 8 | + */ | ||
| 9 | +@Data | ||
| 10 | +public class SysRoleMenuRefreshMessage implements ChannelMessage { | ||
| 11 | + | ||
| 12 | + @Override | ||
| 13 | + public String getChannel() { | ||
| 14 | + return "system.role-menu.refresh"; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/mq/producer/permission/SysPermissionProducer.java
0 → 100644
| 1 | +package cn.iocoder.dashboard.modules.system.mq.producer.permission; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.dashboard.framework.redis.core.util.RedisMessageUtils; | ||
| 4 | +import cn.iocoder.dashboard.modules.system.mq.message.permission.SysRoleMenuRefreshMessage; | ||
| 5 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 6 | +import org.springframework.stereotype.Component; | ||
| 7 | + | ||
| 8 | +import javax.annotation.Resource; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * Permission 权限相关消息的 Producer | ||
| 12 | + */ | ||
| 13 | +@Component | ||
| 14 | +public class SysPermissionProducer { | ||
| 15 | + | ||
| 16 | + @Resource | ||
| 17 | + private StringRedisTemplate stringRedisTemplate; | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 发送 {@link SysRoleMenuRefreshMessage} 消息 | ||
| 21 | + */ | ||
| 22 | + public void sendRoleMenuRefreshMessage() { | ||
| 23 | + SysRoleMenuRefreshMessage message = new SysRoleMenuRefreshMessage(); | ||
| 24 | + RedisMessageUtils.sendChannelMessage(stringRedisTemplate, message); | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | +} |
src/main/java/cn/iocoder/dashboard/modules/system/service/auth/SysAuthService.java
| 1 | package cn.iocoder.dashboard.modules.system.service.auth; | 1 | package cn.iocoder.dashboard.modules.system.service.auth; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.dashboard.framework.security.core.service.SecurityFrameworkService; | 3 | +import cn.iocoder.dashboard.framework.security.core.service.SecurityAuthFrameworkService; |
| 4 | 4 | ||
| 5 | /** | 5 | /** |
| 6 | * 认证 Service 接口 | 6 | * 认证 Service 接口 |
| @@ -9,7 +9,7 @@ import cn.iocoder.dashboard.framework.security.core.service.SecurityFrameworkSer | @@ -9,7 +9,7 @@ import cn.iocoder.dashboard.framework.security.core.service.SecurityFrameworkSer | ||
| 9 | * | 9 | * |
| 10 | * @author 芋道源码 | 10 | * @author 芋道源码 |
| 11 | */ | 11 | */ |
| 12 | -public interface SysAuthService extends SecurityFrameworkService { | 12 | +public interface SysAuthService extends SecurityAuthFrameworkService { |
| 13 | 13 | ||
| 14 | String login(String username, String password, String captchaUUID, String captchaCode); | 14 | String login(String username, String password, String captchaUUID, String captchaCode); |
| 15 | 15 |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysMenuService.java
| @@ -59,6 +59,14 @@ public interface SysMenuService { | @@ -59,6 +59,14 @@ public interface SysMenuService { | ||
| 59 | List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, | 59 | List<SysMenuDO> listMenusFromCache(Collection<Long> menuIds, Collection<Integer> menuTypes, |
| 60 | Collection<Integer> menusStatuses); | 60 | Collection<Integer> menusStatuses); |
| 61 | 61 | ||
| 62 | + /** | ||
| 63 | + * 获得权限对应的菜单数组 | ||
| 64 | + * | ||
| 65 | + * @param permission 权限标识 | ||
| 66 | + * @return 数组 | ||
| 67 | + */ | ||
| 68 | + List<SysMenuDO> getMenuListByPermissionFromCache(String permission); | ||
| 69 | + | ||
| 62 | /* | 70 | /* |
| 63 | * 创建菜单 | 71 | * 创建菜单 |
| 64 | * | 72 | * |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysPermissionService.java
| 1 | package cn.iocoder.dashboard.modules.system.service.permission; | 1 | package cn.iocoder.dashboard.modules.system.service.permission; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.dashboard.framework.security.core.service.SecurityPermissionFrameworkService; | ||
| 3 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 4 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 4 | import org.springframework.lang.Nullable; | 5 | import org.springframework.lang.Nullable; |
| 5 | 6 | ||
| @@ -14,12 +15,12 @@ import java.util.Set; | @@ -14,12 +15,12 @@ import java.util.Set; | ||
| 14 | * | 15 | * |
| 15 | * @author 芋道源码 | 16 | * @author 芋道源码 |
| 16 | */ | 17 | */ |
| 17 | -public interface SysPermissionService { | 18 | +public interface SysPermissionService extends SecurityPermissionFrameworkService { |
| 18 | 19 | ||
| 19 | /** | 20 | /** |
| 20 | * 初始化 | 21 | * 初始化 |
| 21 | */ | 22 | */ |
| 22 | - void init(); | 23 | + void initLocalCache(); |
| 23 | 24 | ||
| 24 | /** | 25 | /** |
| 25 | * 获得角色们拥有的菜单列表,从缓存中获取 | 26 | * 获得角色们拥有的菜单列表,从缓存中获取 |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/SysRoleService.java
| @@ -57,6 +57,16 @@ public interface SysRoleService { | @@ -57,6 +57,16 @@ public interface SysRoleService { | ||
| 57 | boolean hasAnyAdmin(Collection<SysRoleDO> roleList); | 57 | boolean hasAnyAdmin(Collection<SysRoleDO> roleList); |
| 58 | 58 | ||
| 59 | /** | 59 | /** |
| 60 | + * 判断角色编号数组中,是否有管理员 | ||
| 61 | + * | ||
| 62 | + * @param ids 角色编号数组 | ||
| 63 | + * @return 是否有管理员 | ||
| 64 | + */ | ||
| 65 | + default boolean hasAnyAdmin(Set<Long> ids) { | ||
| 66 | + return hasAnyAdmin(listRolesFromCache(ids)); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + /** | ||
| 60 | * 创建角色 | 70 | * 创建角色 |
| 61 | * | 71 | * |
| 62 | * @param reqVO 创建角色信息 | 72 | * @param reqVO 创建角色信息 |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysMenuServiceImpl.java
| @@ -61,7 +61,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -61,7 +61,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 61 | * | 61 | * |
| 62 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 62 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 63 | */ | 63 | */ |
| 64 | - private volatile Multimap<String, SysMenuDO> permMenuCache; | 64 | + private volatile Multimap<String, SysMenuDO> permissionMenuCache; |
| 65 | /** | 65 | /** |
| 66 | * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | 66 | * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 |
| 67 | */ | 67 | */ |
| @@ -76,7 +76,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -76,7 +76,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 76 | private SysMenuProducer menuProducer; | 76 | private SysMenuProducer menuProducer; |
| 77 | 77 | ||
| 78 | /** | 78 | /** |
| 79 | - * 初始化 {@link #menuCache} 和 {@link #permMenuCache} 缓存 | 79 | + * 初始化 {@link #menuCache} 和 {@link #permissionMenuCache} 缓存 |
| 80 | */ | 80 | */ |
| 81 | @Override | 81 | @Override |
| 82 | @PostConstruct | 82 | @PostConstruct |
| @@ -95,7 +95,7 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -95,7 +95,7 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 95 | permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); | 95 | permMenuCacheBuilder.put(menuDO.getPermission(), menuDO); |
| 96 | }); | 96 | }); |
| 97 | menuCache = menuCacheBuilder.build(); | 97 | menuCache = menuCacheBuilder.build(); |
| 98 | - permMenuCache = permMenuCacheBuilder.build(); | 98 | + permissionMenuCache = permMenuCacheBuilder.build(); |
| 99 | assert menuList.size() > 0; // 断言,避免告警 | 99 | assert menuList.size() > 0; // 断言,避免告警 |
| 100 | maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | 100 | maxUpdateTime = menuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); |
| 101 | log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); | 101 | log.info("[initLocalCache][缓存菜单,数量为:{}]", menuList.size()); |
| @@ -163,6 +163,11 @@ public class SysMenuServiceImpl implements SysMenuService { | @@ -163,6 +163,11 @@ public class SysMenuServiceImpl implements SysMenuService { | ||
| 163 | } | 163 | } |
| 164 | 164 | ||
| 165 | @Override | 165 | @Override |
| 166 | + public List<SysMenuDO> getMenuListByPermissionFromCache(String permission) { | ||
| 167 | + return new ArrayList<>(permissionMenuCache.get(permission)); | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + @Override | ||
| 166 | public Long createMenu(SysMenuCreateReqVO reqVO) { | 171 | public Long createMenu(SysMenuCreateReqVO reqVO) { |
| 167 | // 校验父菜单存在 | 172 | // 校验父菜单存在 |
| 168 | checkParentResource(reqVO.getParentId(), null); | 173 | checkParentResource(reqVO.getParentId(), null); |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysPermissionServiceImpl.java
| @@ -2,12 +2,16 @@ package cn.iocoder.dashboard.modules.system.service.permission.impl; | @@ -2,12 +2,16 @@ package cn.iocoder.dashboard.modules.system.service.permission.impl; | ||
| 2 | 2 | ||
| 3 | import cn.hutool.core.collection.CollUtil; | 3 | import cn.hutool.core.collection.CollUtil; |
| 4 | import cn.hutool.core.collection.CollectionUtil; | 4 | import cn.hutool.core.collection.CollectionUtil; |
| 5 | +import cn.hutool.core.util.ArrayUtil; | ||
| 6 | +import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO; | ||
| 7 | +import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils; | ||
| 5 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMenuMapper; | 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysRoleMenuMapper; |
| 6 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysUserRoleMapper; | 9 | import cn.iocoder.dashboard.modules.system.dal.mysql.dao.permission.SysUserRoleMapper; |
| 7 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; | 10 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysMenuDO; |
| 8 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; | 11 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleDO; |
| 9 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; | 12 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysRoleMenuDO; |
| 10 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysUserRoleDO; | 13 | import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.permission.SysUserRoleDO; |
| 14 | +import cn.iocoder.dashboard.modules.system.mq.producer.permission.SysPermissionProducer; | ||
| 11 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; | 15 | import cn.iocoder.dashboard.modules.system.service.permission.SysMenuService; |
| 12 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; | 16 | import cn.iocoder.dashboard.modules.system.service.permission.SysPermissionService; |
| 13 | import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; | 17 | import cn.iocoder.dashboard.modules.system.service.permission.SysRoleService; |
| @@ -18,24 +22,29 @@ import com.google.common.collect.Multimap; | @@ -18,24 +22,29 @@ import com.google.common.collect.Multimap; | ||
| 18 | import lombok.extern.slf4j.Slf4j; | 22 | import lombok.extern.slf4j.Slf4j; |
| 19 | import org.springframework.stereotype.Service; | 23 | import org.springframework.stereotype.Service; |
| 20 | import org.springframework.transaction.annotation.Transactional; | 24 | import org.springframework.transaction.annotation.Transactional; |
| 25 | +import org.springframework.transaction.support.TransactionSynchronization; | ||
| 26 | +import org.springframework.transaction.support.TransactionSynchronizationManager; | ||
| 21 | 27 | ||
| 22 | import javax.annotation.PostConstruct; | 28 | import javax.annotation.PostConstruct; |
| 23 | import javax.annotation.Resource; | 29 | import javax.annotation.Resource; |
| 24 | -import java.util.Collection; | ||
| 25 | -import java.util.Collections; | ||
| 26 | -import java.util.List; | ||
| 27 | -import java.util.Set; | 30 | +import java.util.*; |
| 28 | 31 | ||
| 29 | /** | 32 | /** |
| 30 | * 权限 Service 实现类 | 33 | * 权限 Service 实现类 |
| 31 | * | 34 | * |
| 32 | * @author 芋道源码 | 35 | * @author 芋道源码 |
| 33 | */ | 36 | */ |
| 34 | -@Service | 37 | +@Service("ss") // 使用 Spring Security 的缩写,方便食用 |
| 35 | @Slf4j | 38 | @Slf4j |
| 36 | public class SysPermissionServiceImpl implements SysPermissionService { | 39 | public class SysPermissionServiceImpl implements SysPermissionService { |
| 37 | 40 | ||
| 38 | /** | 41 | /** |
| 42 | + * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 | ||
| 43 | + * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 | ||
| 44 | + */ | ||
| 45 | + private static final long SCHEDULER_PERIOD = 5 * 60 * 1000L; | ||
| 46 | + | ||
| 47 | + /** | ||
| 39 | * 角色编号与菜单编号的缓存映射 | 48 | * 角色编号与菜单编号的缓存映射 |
| 40 | * key:角色编号 | 49 | * key:角色编号 |
| 41 | * value:菜单编号的数组 | 50 | * value:菜单编号的数组 |
| @@ -51,6 +60,10 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -51,6 +60,10 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 51 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 | 60 | * 这里声明 volatile 修饰的原因是,每次刷新时,直接修改指向 |
| 52 | */ | 61 | */ |
| 53 | private volatile Multimap<Long, Long> menuRoleCache; | 62 | private volatile Multimap<Long, Long> menuRoleCache; |
| 63 | + /** | ||
| 64 | + * 缓存菜单的最大更新时间,用于后续的增量轮询,判断是否有更新 | ||
| 65 | + */ | ||
| 66 | + private volatile Date maxUpdateTime; | ||
| 54 | 67 | ||
| 55 | @Resource | 68 | @Resource |
| 56 | private SysRoleMenuMapper roleMenuMapper; | 69 | private SysRoleMenuMapper roleMenuMapper; |
| @@ -62,14 +75,22 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -62,14 +75,22 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 62 | @Resource | 75 | @Resource |
| 63 | private SysMenuService menuService; | 76 | private SysMenuService menuService; |
| 64 | 77 | ||
| 78 | + @Resource | ||
| 79 | + private SysPermissionProducer permissionProducer; | ||
| 80 | + | ||
| 65 | /** | 81 | /** |
| 66 | * 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存 | 82 | * 初始化 {@link #roleMenuCache} 和 {@link #menuRoleCache} 缓存 |
| 67 | */ | 83 | */ |
| 68 | @Override | 84 | @Override |
| 69 | @PostConstruct | 85 | @PostConstruct |
| 70 | - public void init() { | 86 | + public void initLocalCache() { |
| 87 | + // 获取角色与菜单的关联列表,如果有更新 | ||
| 88 | + List<SysRoleMenuDO> roleMenuList = this.loadRoleMenuIfUpdate(maxUpdateTime); | ||
| 89 | + if (CollUtil.isEmpty(roleMenuList)) { | ||
| 90 | + return; | ||
| 91 | + } | ||
| 92 | + | ||
| 71 | // 初始化 roleMenuCache 和 menuRoleCache 缓存 | 93 | // 初始化 roleMenuCache 和 menuRoleCache 缓存 |
| 72 | - List<SysRoleMenuDO> roleMenuList = roleMenuMapper.selectList(null); | ||
| 73 | ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder(); | 94 | ImmutableMultimap.Builder<Long, Long> roleMenuCacheBuilder = ImmutableMultimap.builder(); |
| 74 | ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder(); | 95 | ImmutableMultimap.Builder<Long, Long> menuRoleCacheBuilder = ImmutableMultimap.builder(); |
| 75 | roleMenuList.forEach(roleMenuDO -> { | 96 | roleMenuList.forEach(roleMenuDO -> { |
| @@ -78,9 +99,32 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -78,9 +99,32 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 78 | }); | 99 | }); |
| 79 | roleMenuCache = roleMenuCacheBuilder.build(); | 100 | roleMenuCache = roleMenuCacheBuilder.build(); |
| 80 | menuRoleCache = menuRoleCacheBuilder.build(); | 101 | menuRoleCache = menuRoleCacheBuilder.build(); |
| 102 | + assert roleMenuList.size() > 0; // 断言,避免告警 | ||
| 103 | + maxUpdateTime = roleMenuList.stream().max(Comparator.comparing(BaseDO::getUpdateTime)).get().getUpdateTime(); | ||
| 81 | log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); | 104 | log.info("[initLocalCache][初始化角色与菜单的关联数量为 {}]", roleMenuList.size()); |
| 82 | } | 105 | } |
| 83 | 106 | ||
| 107 | + /** | ||
| 108 | + * 如果角色与菜单的关联发生变化,从数据库中获取最新的全量角色与菜单的关联。 | ||
| 109 | + * 如果未发生变化,则返回空 | ||
| 110 | + * | ||
| 111 | + * @param maxUpdateTime 当前角色与菜单的关联的最大更新时间 | ||
| 112 | + * @return 角色与菜单的关联列表 | ||
| 113 | + */ | ||
| 114 | + private List<SysRoleMenuDO> loadRoleMenuIfUpdate(Date maxUpdateTime) { | ||
| 115 | + // 第一步,判断是否要更新。 | ||
| 116 | + if (maxUpdateTime == null) { // 如果更新时间为空,说明 DB 一定有新数据 | ||
| 117 | + log.info("[loadRoleMenuIfUpdate][首次加载全量角色与菜单的关联]"); | ||
| 118 | + } else { // 判断数据库中是否有更新的角色与菜单的关联 | ||
| 119 | + if (!roleMenuMapper.selectExistsByUpdateTimeAfter(maxUpdateTime)) { | ||
| 120 | + return null; | ||
| 121 | + } | ||
| 122 | + log.info("[loadRoleMenuIfUpdate][增量加载全量角色与菜单的关联]"); | ||
| 123 | + } | ||
| 124 | + // 第二步,如果有更新,则从数据库加载所有角色与菜单的关联 | ||
| 125 | + return roleMenuMapper.selectList(); | ||
| 126 | + } | ||
| 127 | + | ||
| 84 | @Override | 128 | @Override |
| 85 | public List<SysMenuDO> listRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, | 129 | public List<SysMenuDO> listRoleMenusFromCache(Collection<Long> roleIds, Collection<Integer> menuTypes, |
| 86 | Collection<Integer> menusStatuses) { | 130 | Collection<Integer> menusStatuses) { |
| @@ -140,6 +184,15 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -140,6 +184,15 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 140 | if (!CollectionUtil.isEmpty(deleteMenuIds)) { | 184 | if (!CollectionUtil.isEmpty(deleteMenuIds)) { |
| 141 | roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); | 185 | roleMenuMapper.deleteListByRoleIdAndMenuIds(roleId, deleteMenuIds); |
| 142 | } | 186 | } |
| 187 | + // 发送刷新消息. 注意,需要事务提交后,在进行发送刷新消息。不然 db 还未提交,结果缓存先刷新了 | ||
| 188 | + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { | ||
| 189 | + | ||
| 190 | + @Override | ||
| 191 | + public void afterCommit() { | ||
| 192 | + permissionProducer.sendRoleMenuRefreshMessage(); | ||
| 193 | + } | ||
| 194 | + | ||
| 195 | + }); | ||
| 143 | } | 196 | } |
| 144 | 197 | ||
| 145 | @Override | 198 | @Override |
| @@ -189,4 +242,39 @@ public class SysPermissionServiceImpl implements SysPermissionService { | @@ -189,4 +242,39 @@ public class SysPermissionServiceImpl implements SysPermissionService { | ||
| 189 | // TODO 实现我 | 242 | // TODO 实现我 |
| 190 | } | 243 | } |
| 191 | 244 | ||
| 245 | + @Override | ||
| 246 | + public boolean hasPermission(String permission) { | ||
| 247 | + return hasAnyPermissions(permission); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + @Override | ||
| 251 | + public boolean hasAnyPermissions(String... permissions) { | ||
| 252 | + // 如果为空,说明已经有权限 | ||
| 253 | + if (ArrayUtil.isEmpty(permissions)) { | ||
| 254 | + return true; | ||
| 255 | + } | ||
| 256 | + | ||
| 257 | + // 获得当前登陆的角色。如果为空,说明没有权限 | ||
| 258 | + Set<Long> roleIds = SecurityUtils.getLoginUserRoleIds(); | ||
| 259 | + if (CollUtil.isEmpty(roleIds)) { | ||
| 260 | + return false; | ||
| 261 | + } | ||
| 262 | + // 判断是否是超管。如果是,当然符合条件 | ||
| 263 | + if (roleService.hasAnyAdmin(roleIds)) { | ||
| 264 | + return true; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + // 遍历权限,判断是否有一个满足 | ||
| 268 | + return Arrays.stream(permissions).anyMatch(permission -> { | ||
| 269 | + List<SysMenuDO> menuList = menuService.getMenuListByPermissionFromCache(permission); | ||
| 270 | + // 采用严格模式,如果权限找不到对应的 Menu 的话,认为 | ||
| 271 | + if (CollUtil.isEmpty(menuList)) { | ||
| 272 | + return false; | ||
| 273 | + } | ||
| 274 | + // 获得是否拥有该权限,任一一个 | ||
| 275 | + return menuList.stream().anyMatch(menu -> CollUtil.containsAny(roleIds, | ||
| 276 | + menuRoleCache.get(menu.getId()))); | ||
| 277 | + }); | ||
| 278 | + } | ||
| 279 | + | ||
| 192 | } | 280 | } |
src/main/java/cn/iocoder/dashboard/modules/system/service/permission/impl/SysRoleServiceImpl.java
| @@ -217,6 +217,8 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -217,6 +217,8 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 217 | updateObject.setId(id); | 217 | updateObject.setId(id); |
| 218 | updateObject.setStatus(status); | 218 | updateObject.setStatus(status); |
| 219 | roleMapper.updateById(updateObject); | 219 | roleMapper.updateById(updateObject); |
| 220 | + // 发送刷新消息 | ||
| 221 | + roleProducer.sendRoleRefreshMessage(); | ||
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | @Override | 224 | @Override |
| @@ -229,6 +231,8 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -229,6 +231,8 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 229 | updateObject.setDataScope(dataScope); | 231 | updateObject.setDataScope(dataScope); |
| 230 | updateObject.setDataScopeDeptIds(dataScopeDeptIds); | 232 | updateObject.setDataScopeDeptIds(dataScopeDeptIds); |
| 231 | roleMapper.updateById(updateObject); | 233 | roleMapper.updateById(updateObject); |
| 234 | + // 发送刷新消息 | ||
| 235 | + roleProducer.sendRoleRefreshMessage(); | ||
| 232 | } | 236 | } |
| 233 | 237 | ||
| 234 | /** | 238 | /** |
src/main/resources/application.yaml
| @@ -34,7 +34,7 @@ yudao: | @@ -34,7 +34,7 @@ yudao: | ||
| 34 | token-timeout: 1d | 34 | token-timeout: 1d |
| 35 | session-timeout: 30m | 35 | session-timeout: 30m |
| 36 | mock-enable: true | 36 | mock-enable: true |
| 37 | - mock-secret: yudaoyuanma | 37 | + mock-secret: test |
| 38 | swagger: | 38 | swagger: |
| 39 | title: 管理后台 | 39 | title: 管理后台 |
| 40 | description: 提供管理员管理的所有功能 | 40 | description: 提供管理员管理的所有功能 |