Forráskód Böngészése

修改后台管理接口增加数据范围鉴权功能

luoshi 2 éve
szülő
commit
aed8ebf94f
23 módosított fájl, 500 hozzáadás és 60 törlés
  1. 7 2
      src/main/java/com/qmth/ops/api/controller/admin/AppController.java
  2. 21 9
      src/main/java/com/qmth/ops/api/controller/admin/DeployController.java
  3. 4 1
      src/main/java/com/qmth/ops/api/controller/admin/EnvController.java
  4. 3 0
      src/main/java/com/qmth/ops/api/controller/admin/ModuleController.java
  5. 14 4
      src/main/java/com/qmth/ops/api/controller/admin/NginxConfigController.java
  6. 14 9
      src/main/java/com/qmth/ops/api/controller/admin/OrgController.java
  7. 19 10
      src/main/java/com/qmth/ops/api/controller/admin/PropertyController.java
  8. 41 1
      src/main/java/com/qmth/ops/api/controller/admin/UserController.java
  9. 3 0
      src/main/java/com/qmth/ops/api/controller/admin/VersionController.java
  10. 7 2
      src/main/java/com/qmth/ops/api/controller/admin/WxappController.java
  11. 43 0
      src/main/java/com/qmth/ops/api/dto/PermissionDTO.java
  12. 36 0
      src/main/java/com/qmth/ops/api/dto/UserPermissionDTO.java
  13. 5 1
      src/main/java/com/qmth/ops/api/security/AdminAuthorizationService.java
  14. 18 1
      src/main/java/com/qmth/ops/api/security/AdminSession.java
  15. 49 0
      src/main/java/com/qmth/ops/api/security/Permission.java
  16. 6 0
      src/main/java/com/qmth/ops/api/security/ScopeType.java
  17. 16 0
      src/main/java/com/qmth/ops/api/vo/UpdateTimeVO.java
  18. 13 0
      src/main/java/com/qmth/ops/biz/dao/UserPermissionDao.java
  19. 1 1
      src/main/java/com/qmth/ops/biz/domain/FileFormat.java
  20. 57 0
      src/main/java/com/qmth/ops/biz/domain/UserPermission.java
  21. 14 0
      src/main/java/com/qmth/ops/biz/service/InitService.java
  22. 80 0
      src/main/java/com/qmth/ops/biz/service/UserPermissionService.java
  23. 29 19
      src/main/resources/script/init.sql

+ 7 - 2
src/main/java/com/qmth/ops/api/controller/admin/AppController.java

@@ -2,12 +2,15 @@ package com.qmth.ops.api.controller.admin;
 
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.ops.api.constants.OpsApiConstants;
+import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.AppVersionVO;
 import com.qmth.ops.biz.domain.App;
 import com.qmth.ops.biz.query.AppQuery;
 import com.qmth.ops.biz.service.AppService;
 import com.qmth.ops.biz.service.VersionService;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -37,13 +40,15 @@ public class AppController {
     }
 
     @PostMapping("/insert")
-    public AppVersionVO insert(App app) {
+    public AppVersionVO insert(@RequestAttribute AdminSession adminSession, App app) {
+        adminSession.permissionCheck(Permission.APP_INSERT);
         appService.insert(app);
         return new AppVersionVO(appService.getById(app.getId()), versionService);
     }
 
     @PostMapping("/update")
-    public AppVersionVO update(App app) {
+    public AppVersionVO update(@RequestAttribute AdminSession adminSession, App app) {
+        adminSession.permissionCheck(Permission.APP_EDIT);
         appService.update(app);
         return new AppVersionVO(appService.getById(app.getId()), versionService);
     }

+ 21 - 9
src/main/java/com/qmth/ops/api/controller/admin/DeployController.java

@@ -7,6 +7,8 @@ import com.qmth.boot.api.exception.ApiException;
 import com.qmth.boot.tools.device.DeviceInfo;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.dto.DeployForm;
+import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.CodeNameVO;
 import com.qmth.ops.api.vo.DeployVO;
 import com.qmth.ops.api.vo.OrgVO;
@@ -59,18 +61,23 @@ public class DeployController {
     }
 
     @PostMapping("/insert")
-    public DeployVO insert(@Validated(DeployForm.InsertGroup.class) @RequestBody DeployForm form) {
+    public DeployVO insert(@RequestAttribute AdminSession adminSession,
+            @Validated(DeployForm.InsertGroup.class) @RequestBody DeployForm form) {
+        adminSession.permissionCheck(Permission.DEPLOY_INSERT);
         return new DeployVO(deployService.insert(form.build()), appService);
     }
 
     @PostMapping("/update")
-    public DeployVO update(@Validated(DeployForm.UpdateGroup.class) @RequestBody DeployForm form) {
+    public DeployVO update(@RequestAttribute AdminSession adminSession,
+            @Validated(DeployForm.UpdateGroup.class) @RequestBody DeployForm form) {
+        adminSession.permissionCheck(Permission.DEPLOY_EDIT, form.getId());
         return new DeployVO(deployService.update(form.build()), appService);
     }
 
     @PostMapping("/device/save")
-    public Object saveDevice(@RequestParam Long id, @RequestParam MultipartFile deviceInfo,
-            @RequestParam(required = false) String remark) throws Exception {
+    public Object saveDevice(@RequestAttribute AdminSession adminSession, @RequestParam Long id,
+            @RequestParam MultipartFile deviceInfo, @RequestParam(required = false) String remark) throws Exception {
+        adminSession.permissionCheck(Permission.DEPLOY_DEVICE_EDIT, id);
         Deploy deploy = deployService.findById(id);
         if (deploy != null) {
             DeviceInfo info = licenseService.parseDeviceInfo(deviceInfo);
@@ -87,7 +94,9 @@ public class DeployController {
     }
 
     @PostMapping("/device/delete")
-    public Object deleteDevice(@RequestParam Long id, @RequestParam String deviceId) throws Exception {
+    public Object deleteDevice(@RequestAttribute AdminSession adminSession, @RequestParam Long id,
+            @RequestParam String deviceId) throws Exception {
+        adminSession.permissionCheck(Permission.DEPLOY_DEVICE_EDIT, id);
         Deploy deploy = deployService.findById(id);
         if (deploy != null) {
             deployService.deleteDevice(deploy, deviceId);
@@ -108,9 +117,10 @@ public class DeployController {
     }
 
     @PostMapping("/license/download")
-    public void licenseDownload(HttpServletResponse response, @RequestParam Long id,
-            @RequestParam(required = false) String deviceId, @RequestParam(required = false) String version)
-            throws Exception {
+    public void licenseDownload(@RequestAttribute AdminSession adminSession, HttpServletResponse response,
+            @RequestParam Long id, @RequestParam(required = false) String deviceId,
+            @RequestParam(required = false) String version) throws Exception {
+        adminSession.permissionCheck(Permission.DEPLOY_LICENSE_DOWNLOAD, id);
         response.setContentType("application/octet-stream; charset=utf-8");
         response.setHeader("Content-Disposition", "attachment; filename=app.lic");
         licenseService.buildLicense(deployService.findById(id), deviceId, version, response.getOutputStream());
@@ -127,7 +137,9 @@ public class DeployController {
     }
 
     @PostMapping("/org/update")
-    public Object updateOrg(@RequestParam Long id, @RequestParam Long[] orgId) {
+    public Object updateOrg(@RequestAttribute AdminSession adminSession, @RequestParam Long id,
+            @RequestParam Long[] orgId) {
+        adminSession.permissionCheck(Permission.DEPLOY_ORG_EDIT, id);
         Deploy deploy = deployService.findById(id);
         if (deploy != null) {
             deployService.updateOrg(deploy, orgId);

+ 4 - 1
src/main/java/com/qmth/ops/api/controller/admin/EnvController.java

@@ -4,6 +4,7 @@ import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.CodeNameVO;
 import com.qmth.ops.api.vo.EnvVO;
 import com.qmth.ops.biz.domain.Env;
@@ -34,18 +35,20 @@ public class EnvController {
 
     @PostMapping("/insert")
     public EnvVO insert(@RequestAttribute AdminSession adminSession, Env env) {
+        adminSession.permissionCheck(Permission.ENV_INSERT);
         env = envService.insert(env);
         return new EnvVO(env);
     }
 
     @PostMapping("/update")
     public EnvVO update(@RequestAttribute AdminSession adminSession, Env env) {
+        adminSession.permissionCheck(Permission.ENV_EDIT);
         env = envService.update(env);
         return new EnvVO(env);
     }
 
     @PostMapping("/list")
-    public List<EnvVO> list(@RequestAttribute AdminSession adminSession, Long appId) {
+    public List<EnvVO> list(Long appId) {
         return envService.list(appId).stream().map(EnvVO::new).collect(Collectors.toList());
     }
 

+ 3 - 0
src/main/java/com/qmth/ops/api/controller/admin/ModuleController.java

@@ -4,6 +4,7 @@ import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.ModuleTypeVO;
 import com.qmth.ops.biz.domain.Module;
 import com.qmth.ops.biz.domain.ModuleType;
@@ -33,11 +34,13 @@ public class ModuleController {
 
     @PostMapping("/insert")
     public Module insert(@RequestAttribute AdminSession adminSession, Module module) {
+        adminSession.permissionCheck(Permission.MODULE_INSERT);
         return moduleService.insert(module);
     }
 
     @PostMapping("/update")
     public Module update(@RequestAttribute AdminSession adminSession, Module module) {
+        adminSession.permissionCheck(Permission.MODULE_EDIT);
         return moduleService.update(module);
     }
 

+ 14 - 4
src/main/java/com/qmth/ops/api/controller/admin/NginxConfigController.java

@@ -2,6 +2,9 @@ package com.qmth.ops.api.controller.admin;
 
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
+import com.qmth.ops.biz.domain.App;
+import com.qmth.ops.biz.domain.Env;
 import com.qmth.ops.biz.domain.NginxConfig;
 import com.qmth.ops.biz.service.AppService;
 import com.qmth.ops.biz.service.EnvService;
@@ -28,8 +31,8 @@ public class NginxConfigController {
     private EnvService envService;
 
     @PostMapping("/find")
-    public NginxConfig find(@RequestAttribute AdminSession adminSession, @RequestParam Long appId,
-            @RequestParam(required = false) Long envId, @RequestParam(required = false) Long moduleId) {
+    public NginxConfig find(@RequestParam Long appId, @RequestParam(required = false) Long envId,
+            @RequestParam(required = false) Long moduleId) {
         return nginxConfigService.find(appService.getById(appId), envId != null ? envService.getById(envId) : null,
                 moduleId != null ? moduleService.getById(moduleId) : null);
     }
@@ -38,8 +41,15 @@ public class NginxConfigController {
     public Object update(@RequestAttribute AdminSession adminSession, @RequestParam Long appId,
             @RequestParam(required = false) Long envId, @RequestParam(required = false) Long moduleId,
             @RequestParam String content) {
-        return nginxConfigService.update(appService.getById(appId), envId != null ? envService.getById(envId) : null,
-                moduleId != null ? moduleService.getById(moduleId) : null, content);
+        App app = appService.getById(appId);
+        Env env = null;
+        if (envId != null) {
+            env = envService.getById(envId);
+            adminSession.permissionCheck(Permission.NGINX_EDIT, env.getId());
+        } else {
+            adminSession.permissionCheck(Permission.NGINX_BASELINE_EDIT, app.getId());
+        }
+        return nginxConfigService.update(app, env, moduleId != null ? moduleService.getById(moduleId) : null, content);
     }
 
 }

+ 14 - 9
src/main/java/com/qmth/ops/api/controller/admin/OrgController.java

@@ -5,6 +5,8 @@ import com.qmth.boot.api.annotation.Aac;
 import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.core.solar.enums.OrgType;
 import com.qmth.ops.api.constants.OpsApiConstants;
+import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.OrgTypeVO;
 import com.qmth.ops.api.vo.OrgVO;
 import com.qmth.ops.api.vo.SuccessVO;
@@ -12,10 +14,7 @@ import com.qmth.ops.biz.domain.Org;
 import com.qmth.ops.biz.query.OrgQuery;
 import com.qmth.ops.biz.service.FileService;
 import com.qmth.ops.biz.service.OrgService;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
@@ -43,8 +42,10 @@ public class OrgController {
     }
 
     @PostMapping("/insert")
-    public OrgVO insert(Org org, @RequestParam(required = false) MultipartFile logoFile,
-            @RequestParam(required = false) String logoMd5) throws Exception {
+    public OrgVO insert(@RequestAttribute AdminSession adminSession, Org org,
+            @RequestParam(required = false) MultipartFile logoFile, @RequestParam(required = false) String logoMd5)
+            throws Exception {
+        adminSession.permissionCheck(Permission.ORG_INSERT);
         org = orgService.insert(org);
         if (logoFile != null && logoMd5 != null) {
             fileService.uploadOrgLogo(org, logoFile, logoMd5);
@@ -54,8 +55,10 @@ public class OrgController {
     }
 
     @PostMapping("/update")
-    public OrgVO update(Org org, @RequestParam(required = false) MultipartFile logoFile,
-            @RequestParam(required = false) String logoMd5) throws Exception {
+    public OrgVO update(@RequestAttribute AdminSession adminSession, Org org,
+            @RequestParam(required = false) MultipartFile logoFile, @RequestParam(required = false) String logoMd5)
+            throws Exception {
+        adminSession.permissionCheck(Permission.ORG_EDIT);
         org = orgService.update(org);
         if (logoFile != null && logoMd5 != null) {
             fileService.uploadOrgLogo(org, logoFile, logoMd5);
@@ -65,7 +68,9 @@ public class OrgController {
     }
 
     @PostMapping("/toggle")
-    public Object toggle(@RequestParam Long id, @RequestParam Boolean enable) {
+    public Object toggle(@RequestAttribute AdminSession adminSession, @RequestParam Long id,
+            @RequestParam Boolean enable) {
+        adminSession.permissionCheck(Permission.ORG_EDIT);
         return new SuccessVO(orgService.toggle(id, enable));
     }
 }

+ 19 - 10
src/main/java/com/qmth/ops/api/controller/admin/PropertyController.java

@@ -5,7 +5,9 @@ import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.ops.api.binder.FileFormatBinder;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.CodeNameVO;
+import com.qmth.ops.api.vo.SuccessVO;
 import com.qmth.ops.biz.domain.*;
 import com.qmth.ops.biz.service.*;
 import org.springframework.web.bind.WebDataBinder;
@@ -15,9 +17,7 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.annotation.Resource;
 import java.io.IOException;
 import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 @RestController
 @RequestMapping(OpsApiConstants.ADMIN_URI_PREFIX + "/property")
@@ -38,6 +38,9 @@ public class PropertyController {
     @Resource
     private EnvService envService;
 
+    @Resource
+    private UserPermissionService userPermissionService;
+
     @InitBinder
     public void initBinder(WebDataBinder dataBinder) {
         dataBinder.addCustomFormatter(new FileFormatBinder());
@@ -66,13 +69,17 @@ public class PropertyController {
     public Object updateBaseline(@RequestAttribute AdminSession adminSession, @RequestParam Long versionId,
             @RequestParam Long moduleId, @RequestParam MultipartFile file, @RequestParam FileFormat extension,
             @RequestParam(required = false) Long inheritVersionId) throws IOException {
-        return propertyService.updateBaseline(versionService.getById(versionId), moduleService.getById(moduleId),
-                file.getInputStream(), extension,
-                inheritVersionId != null ? versionService.getById(inheritVersionId) : null);
+        Version version = versionService.getById(versionId);
+        adminSession.permissionCheck(Permission.PROPERTY_BASELINE_EDIT, version.getAppId());
+        return propertyService
+                .updateBaseline(version, moduleService.getById(moduleId), file.getInputStream(), extension,
+                        inheritVersionId != null ? versionService.getById(inheritVersionId) : null);
     }
 
     @PostMapping("/baseline/item/update")
     public PropertyItem updateBaselineItem(@RequestAttribute AdminSession adminSession, PropertyItem item) {
+        Version version = versionService.getById(item.getVersionId());
+        adminSession.permissionCheck(Permission.PROPERTY_BASELINE_EDIT, version.getAppId());
         return propertyService.updateBaselineItem(item);
     }
 
@@ -81,8 +88,8 @@ public class PropertyController {
             @RequestParam Long versionId, @RequestParam Long moduleId, @RequestParam Long envId) {
         Env env = envService.getById(envId);
         List<PropertyItem> list = propertyService.listPropertyItem(versionId, moduleId, env.getId());
-        //非管理员/运维角色,且非环境维护用户,需要隐藏机密信息
-        if (!adminSession.getUser().hasRole(Role.ADMIN, Role.OPS)) {
+        //且非环境可编辑用户,需要隐藏机密信息
+        if (!userPermissionService.hasPermission(adminSession.getUser(), Permission.PROPERTY_EDIT, env.getId())) {
             for (PropertyItem item : list) {
                 //包含密钥/密码类信息
                 if (item.getKey().contains("secret") || item.getKey().contains("password")) {
@@ -112,15 +119,17 @@ public class PropertyController {
 
     @PostMapping("/item/update")
     public PropertyItem updatePropertyItem(@RequestAttribute AdminSession adminSession, PropertyItem item) {
+        Env env = envService.getById(item.getEnvId());
+        adminSession.permissionCheck(Permission.PROPERTY_EDIT, env.getId());
         return propertyService.updatePropertyItem(item);
     }
 
     @PostMapping("/item/delete")
     public Object deletePropertyItem(@RequestAttribute AdminSession adminSession, PropertyItem item) {
+        Env env = envService.getById(item.getEnvId());
+        adminSession.permissionCheck(Permission.PROPERTY_EDIT, env.getId());
         propertyService.deletePropertyItem(item);
-        Map<String, Object> map = new HashMap<>();
-        map.put("success", true);
-        return map;
+        return new SuccessVO(true);
     }
 
 }

+ 41 - 1
src/main/java/com/qmth/ops/api/controller/admin/UserController.java

@@ -6,13 +6,18 @@ import com.qmth.boot.api.annotation.BOOL;
 import com.qmth.boot.core.exception.ParameterException;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.dto.LoginResult;
+import com.qmth.ops.api.dto.PermissionDTO;
 import com.qmth.ops.api.dto.UserForm;
+import com.qmth.ops.api.dto.UserPermissionDTO;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.api.vo.CodeNameVO;
+import com.qmth.ops.api.vo.UpdateTimeVO;
 import com.qmth.ops.biz.domain.Role;
 import com.qmth.ops.biz.domain.User;
 import com.qmth.ops.biz.query.UserQuery;
 import com.qmth.ops.biz.service.FileService;
+import com.qmth.ops.biz.service.UserPermissionService;
 import com.qmth.ops.biz.service.UserService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -20,6 +25,7 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.Resource;
 import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @RestController
 @RequestMapping(OpsApiConstants.ADMIN_URI_PREFIX + "/user")
@@ -28,6 +34,9 @@ public class UserController {
     @Resource
     private UserService userService;
 
+    @Resource
+    private UserPermissionService userPermissionService;
+
     @Resource
     private FileService fileService;
 
@@ -44,7 +53,8 @@ public class UserController {
         if (!user.buildPassword(form.getPassword()).equals(user.getPassword())) {
             throw new ParameterException("密码错误");
         }
-        return new AdminSession(userService.changeAccessToken(user)).getLoginResult(fileService.getServer());
+        return new AdminSession(userService.changeAccessToken(user), userPermissionService)
+                .getLoginResult(fileService.getServer());
     }
 
     @RequestMapping("/roles")
@@ -66,12 +76,14 @@ public class UserController {
     @PostMapping("/insert")
     public User insert(@RequestAttribute AdminSession adminSession,
             @Validated(UserForm.InsertGroup.class) UserForm form) {
+        adminSession.permissionCheck(Permission.USER_INSERT);
         return userService.insert(form.build());
     }
 
     @PostMapping("/update")
     public User update(@RequestAttribute AdminSession adminSession,
             @Validated(UserForm.UpdateGroup.class) UserForm form) {
+        adminSession.permissionCheck(Permission.USER_EDIT);
         return userService.update(form.build());
     }
 
@@ -82,4 +94,32 @@ public class UserController {
         return userService.changePassword(user);
     }
 
+    @PostMapping("/permission/query")
+    public List<PermissionDTO> permissionQuery(@RequestParam Long userId) {
+        return userPermissionService.listByUser(userService.getById(userId)).stream().map(PermissionDTO::new)
+                .collect(Collectors.toList());
+    }
+
+    @PostMapping("/permission/save")
+    public UpdateTimeVO permissionSave(@RequestAttribute AdminSession adminSession,
+            @Validated @RequestBody UserPermissionDTO userPermission) {
+        adminSession.permissionCheck(Permission.USER_EDIT);
+        User user = userService.getById(userPermission.getUserId());
+        for (PermissionDTO dto : userPermission.getPermissions()) {
+            userPermissionService.save(user, dto.getPermission(), dto.getScope());
+        }
+        return new UpdateTimeVO().set("userId", user.getId());
+    }
+
+    @PostMapping("/permission/delete")
+    public UpdateTimeVO permissionDelete(@RequestAttribute AdminSession adminSession,
+            @Validated @RequestBody UserPermissionDTO userPermission) {
+        adminSession.permissionCheck(Permission.USER_EDIT);
+        User user = userService.getById(userPermission.getUserId());
+        for (PermissionDTO dto : userPermission.getPermissions()) {
+            userPermissionService.delete(user, dto.getPermission());
+        }
+        return new UpdateTimeVO().set("userId", userPermission.getUserId());
+    }
+
 }

+ 3 - 0
src/main/java/com/qmth/ops/api/controller/admin/VersionController.java

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.qmth.ops.api.binder.VersionNumberBinder;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.biz.domain.Version;
 import com.qmth.ops.biz.query.VersionQuery;
 import com.qmth.ops.biz.service.AppService;
@@ -32,11 +33,13 @@ public class VersionController {
     @PostMapping("/insert")
     public Version insert(@RequestAttribute AdminSession adminSession, @RequestParam Long appId,
             @RequestParam VersionNumber name) {
+        adminSession.permissionCheck(Permission.VERSION_INSERT);
         return versionService.insert(appService.getById(appId), name);
     }
 
     @PostMapping("/update")
     public Version list(@RequestAttribute AdminSession adminSession, Version version) {
+        adminSession.permissionCheck(Permission.VERSION_EDIT);
         return versionService.update(version);
     }
 

+ 7 - 2
src/main/java/com/qmth/ops/api/controller/admin/WxappController.java

@@ -1,10 +1,13 @@
 package com.qmth.ops.api.controller.admin;
 
 import com.qmth.ops.api.constants.OpsApiConstants;
+import com.qmth.ops.api.security.AdminSession;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.biz.domain.Wxapp;
 import com.qmth.ops.biz.query.WxappQuery;
 import com.qmth.ops.biz.service.WxappService;
 import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestAttribute;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 
@@ -29,12 +32,14 @@ public class WxappController {
     }
 
     @PostMapping("/insert")
-    public Wxapp insert(Wxapp wxapp) {
+    public Wxapp insert(@RequestAttribute AdminSession adminSession, Wxapp wxapp) {
+        adminSession.permissionCheck(Permission.WXAPP_INSERT);
         return wxappService.insert(wxapp);
     }
 
     @PostMapping("/update")
-    public Wxapp update(Wxapp wxapp) {
+    public Wxapp update(@RequestAttribute AdminSession adminSession, Wxapp wxapp) {
+        adminSession.permissionCheck(Permission.WXAPP_EDIT);
         return wxappService.update(wxapp);
     }
 

+ 43 - 0
src/main/java/com/qmth/ops/api/dto/PermissionDTO.java

@@ -0,0 +1,43 @@
+package com.qmth.ops.api.dto;
+
+import com.qmth.ops.api.security.Permission;
+import com.qmth.ops.biz.domain.UserPermission;
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Validated
+public class PermissionDTO {
+
+    @NotNull
+    private Permission permission;
+
+    @NotBlank
+    private String scope;
+
+    public PermissionDTO() {
+
+    }
+
+    public PermissionDTO(UserPermission up) {
+        this.permission = up.getPermission();
+        this.scope = up.getScope();
+    }
+
+    public Permission getPermission() {
+        return permission;
+    }
+
+    public void setPermission(Permission permission) {
+        this.permission = permission;
+    }
+
+    public String getScope() {
+        return scope;
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+}

+ 36 - 0
src/main/java/com/qmth/ops/api/dto/UserPermissionDTO.java

@@ -0,0 +1,36 @@
+package com.qmth.ops.api.dto;
+
+import org.springframework.validation.annotation.Validated;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.List;
+
+@Validated
+public class UserPermissionDTO {
+
+    @NotNull
+    private Long userId;
+
+    @NotNull
+    @Size(min = 1)
+    @Valid
+    private List<PermissionDTO> permissions;
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public List<PermissionDTO> getPermissions() {
+        return permissions;
+    }
+
+    public void setPermissions(List<PermissionDTO> permissions) {
+        this.permissions = permissions;
+    }
+}

+ 5 - 1
src/main/java/com/qmth/ops/api/security/AdminAuthorizationService.java

@@ -5,6 +5,7 @@ import com.qmth.boot.core.security.service.AuthorizationService;
 import com.qmth.boot.tools.signature.SignatureType;
 import com.qmth.ops.api.constants.OpsApiConstants;
 import com.qmth.ops.biz.domain.User;
+import com.qmth.ops.biz.service.UserPermissionService;
 import com.qmth.ops.biz.service.UserService;
 
 import javax.annotation.Resource;
@@ -15,11 +16,14 @@ public class AdminAuthorizationService implements AuthorizationService<AdminSess
     @Resource
     private UserService userService;
 
+    @Resource
+    private UserPermissionService userPermissionService;
+
     @Override
     public AdminSession findByIdentity(String identity, SignatureType signatureType, String path) {
         User user = userService.getById(Long.parseLong(identity));
         if (user != null) {
-            return new AdminSession(user);
+            return new AdminSession(user, userPermissionService);
         }
         return null;
     }

+ 18 - 1
src/main/java/com/qmth/ops/api/security/AdminSession.java

@@ -1,15 +1,20 @@
 package com.qmth.ops.api.security;
 
+import com.qmth.boot.core.exception.UnauthorizedException;
 import com.qmth.boot.core.security.model.AccessEntity;
 import com.qmth.ops.api.dto.LoginResult;
 import com.qmth.ops.biz.domain.User;
+import com.qmth.ops.biz.service.UserPermissionService;
 
 public class AdminSession implements AccessEntity {
 
     private User user;
 
-    public AdminSession(User user) {
+    private UserPermissionService userPermissionService;
+
+    public AdminSession(User user, UserPermissionService userPermissionService) {
         this.user = user;
+        this.userPermissionService = userPermissionService;
     }
 
     public LoginResult getLoginResult(String fileServer) {
@@ -27,6 +32,18 @@ public class AdminSession implements AccessEntity {
         return user;
     }
 
+    public void permissionCheck(Permission permission) {
+        if (!userPermissionService.hasPermission(user, permission, null)) {
+            throw new UnauthorizedException("没有[" + permission.getName() + "]操作权限");
+        }
+    }
+
+    public void permissionCheck(Permission permission, Object data) {
+        if (!userPermissionService.hasPermission(user, permission, data)) {
+            throw new UnauthorizedException("没有[" + permission.getName() + "]操作权限");
+        }
+    }
+
     @Override
     public String getIdentity() {
         return user.getId().toString();

+ 49 - 0
src/main/java/com/qmth/ops/api/security/Permission.java

@@ -0,0 +1,49 @@
+package com.qmth.ops.api.security;
+
+public enum Permission {
+    APP_INSERT("应用新增", null),
+    APP_EDIT("应用修改", null),
+    MODULE_INSERT("模块新增", null),
+    MODULE_EDIT("模块修改", null),
+    ENV_INSERT("环境新增", null),
+    ENV_EDIT("环境修改", null),
+    VERSION_INSERT("版本新增", ScopeType.APP),
+    VERSION_EDIT("版本修改", ScopeType.APP),
+    PROPERTY_BASELINE_EDIT("基线配置修改", ScopeType.APP),
+    PROPERTY_EDIT("程序配置修改", ScopeType.ENV),
+    NGINX_BASELINE_EDIT("Nginx基线修改", ScopeType.APP),
+    NGINX_EDIT("Nginx配置修改", ScopeType.ENV),
+    DEPLOY_INSERT("部署新增", null),
+    DEPLOY_EDIT("部署修改", ScopeType.DEPLOY),
+    DEPLOY_DEVICE_EDIT("部署绑定设备修改", ScopeType.DEPLOY),
+    DEPLOY_ORG_EDIT("部署绑定机构修改", ScopeType.DEPLOY),
+    DEPLOY_SECRET_VIEW("部署密钥查看", ScopeType.DEPLOY),
+    DEPLOY_LICENSE_DOWNLOAD("部署证书下载", ScopeType.DEPLOY),
+    ORG_INSERT("机构新增", null),
+    ORG_EDIT("机构修改", null),
+    WXAPP_INSERT("微信小程序新增", null),
+    WXAPP_EDIT("微信小程序修改", null),
+    USER_INSERT("用户新增", null),
+    USER_EDIT("用户修改", null);
+
+    private String name;
+
+    private ScopeType scope;
+
+    Permission(String name, ScopeType scope) {
+        this.name = name;
+        this.scope = scope;
+    }
+
+    public String getCode() {
+        return toString().toLowerCase();
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public ScopeType getScope() {
+        return scope;
+    }
+}

+ 6 - 0
src/main/java/com/qmth/ops/api/security/ScopeType.java

@@ -0,0 +1,6 @@
+package com.qmth.ops.api.security;
+
+public enum ScopeType {
+
+    APP, ENV, DEPLOY
+}

+ 16 - 0
src/main/java/com/qmth/ops/api/vo/UpdateTimeVO.java

@@ -0,0 +1,16 @@
+package com.qmth.ops.api.vo;
+
+import java.util.HashMap;
+
+public class UpdateTimeVO extends HashMap<String, Object> {
+
+    public UpdateTimeVO() {
+        super();
+        put("updateTime", System.currentTimeMillis());
+    }
+
+    public UpdateTimeVO set(String key, Object value) {
+        put(key, value);
+        return this;
+    }
+}

+ 13 - 0
src/main/java/com/qmth/ops/biz/dao/UserPermissionDao.java

@@ -0,0 +1,13 @@
+package com.qmth.ops.biz.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.qmth.ops.api.security.Permission;
+import com.qmth.ops.biz.domain.UserPermission;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Update;
+
+public interface UserPermissionDao extends BaseMapper<UserPermission> {
+
+    @Update("replace into user_permission (user_id, permission, scope) values (#{userId}, #{permission}, #{scope}")
+    void save(@Param("userId") Long userId, @Param("permission") Permission permission, @Param("scope") String scope);
+}

+ 1 - 1
src/main/java/com/qmth/ops/biz/domain/FileFormat.java

@@ -6,7 +6,7 @@ public enum FileFormat {
 
     private String extension;
 
-    private FileFormat(String extension) {
+    FileFormat(String extension) {
         this.extension = extension;
     }
 

+ 57 - 0
src/main/java/com/qmth/ops/biz/domain/UserPermission.java

@@ -0,0 +1,57 @@
+package com.qmth.ops.biz.domain;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.qmth.ops.api.security.Permission;
+
+import java.io.Serializable;
+import java.util.HashSet;
+import java.util.Set;
+
+@TableName(value = "user_permission", autoResultMap = true)
+public class UserPermission implements Serializable {
+
+    private static final long serialVersionUID = 1052334090653353488L;
+
+    public static final String UNLIMIT_SCOPE = "*";
+
+    public static final String SCOPE_SPLIT = ",";
+
+    private Long userId;
+
+    private Permission permission;
+
+    private String scope;
+
+    public Long getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Long userId) {
+        this.userId = userId;
+    }
+
+    public Permission getPermission() {
+        return permission;
+    }
+
+    public void setPermission(Permission permission) {
+        this.permission = permission;
+    }
+
+    public String getScope() {
+        return scope;
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
+
+    public Set<Long> getDataSet() {
+        Set<Long> set = new HashSet<>();
+        String[] datas = scope.split(SCOPE_SPLIT);
+        for (String item : datas) {
+            set.add(Long.parseLong(item));
+        }
+        return set;
+    }
+}

+ 14 - 0
src/main/java/com/qmth/ops/biz/service/InitService.java

@@ -2,8 +2,10 @@ package com.qmth.ops.biz.service;
 
 import com.qmth.boot.mybatis.service.SqlProvider;
 import com.qmth.boot.tools.models.ByteArray;
+import com.qmth.ops.api.security.Permission;
 import com.qmth.ops.biz.domain.Role;
 import com.qmth.ops.biz.domain.User;
+import com.qmth.ops.biz.domain.UserPermission;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.boot.CommandLineRunner;
@@ -20,6 +22,9 @@ public class InitService implements SqlProvider, CommandLineRunner {
     @Resource
     private UserService userService;
 
+    @Resource
+    private UserPermissionService userPermissionService;
+
     @Override
     public String get() {
         try {
@@ -42,5 +47,14 @@ public class InitService implements SqlProvider, CommandLineRunner {
             userService.insert(user);
             log.info("系统管理员初始化完成");
         }
+
+        User user = userService.findByLoginName("admin");
+        if (user != null && user.hasRole(Role.ADMIN)) {
+            for (Permission permission : Permission.values()) {
+                userPermissionService.save(user, permission, UserPermission.UNLIMIT_SCOPE);
+            }
+            log.info("系统管理员权限更新完成");
+        }
     }
+
 }

+ 80 - 0
src/main/java/com/qmth/ops/biz/service/UserPermissionService.java

@@ -0,0 +1,80 @@
+package com.qmth.ops.biz.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.qmth.ops.api.security.Permission;
+import com.qmth.ops.biz.dao.UserPermissionDao;
+import com.qmth.ops.biz.domain.*;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+public class UserPermissionService extends ServiceImpl<UserPermissionDao, UserPermission> {
+
+    @Resource
+    private UserPermissionDao userPermissionDao;
+
+    @Resource
+    private AppService appService;
+
+    @Resource
+    private EnvService envService;
+
+    @Resource
+    private DeployService deployService;
+
+    public List<UserPermission> listByUser(User user) {
+        return userPermissionDao
+                .selectList(new LambdaQueryWrapper<UserPermission>().eq(UserPermission::getUserId, user.getId()));
+    }
+
+    public UserPermission findByUserAndPermission(User user, Permission permission) {
+        return userPermissionDao.selectOne(
+                new LambdaQueryWrapper<UserPermission>().eq(UserPermission::getUserId, user.getId())
+                        .eq(UserPermission::getPermission, permission));
+    }
+
+    @Transactional
+    public void save(User user, Permission permission, String scope) {
+        userPermissionDao.save(user.getId(), permission, scope);
+    }
+
+    @Transactional
+    public void delete(User user, Permission permission) {
+        userPermissionDao.delete(new LambdaUpdateWrapper<UserPermission>().eq(UserPermission::getUserId, user.getId())
+                .eq(UserPermission::getPermission, permission));
+    }
+
+    public boolean hasPermission(User user, Permission permission, Object data) {
+        UserPermission up = findByUserAndPermission(user, permission);
+        if (up == null) {
+            return false;
+        }
+        if (permission.getScope() == null) {
+            return true;
+        }
+        String scope = up.getScope();
+        if (UserPermission.UNLIMIT_SCOPE.equals(scope)) {
+            return true;
+        }
+        try {
+            switch (permission.getScope()) {
+            case APP:
+                App app = appService.getById((Long) data);
+                return app != null && up.getDataSet().contains(app.getId());
+            case ENV:
+                Env env = envService.getById((Long) data);
+                return env != null && up.getDataSet().contains(env.getId());
+            case DEPLOY:
+                Deploy deploy = deployService.getById((Long) data);
+                return deploy != null && up.getDataSet().contains(deploy.getId());
+            }
+        } catch (Exception ignored) {
+        }
+        return false;
+    }
+}

+ 29 - 19
src/main/resources/script/init.sql

@@ -1,3 +1,32 @@
+-- Create syntax for TABLE 'user'
+CREATE TABLE IF NOT EXISTS `user`
+(
+    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT,
+    `login_name`    varchar(64)         NOT NULL,
+    `name`          varchar(64)         NOT NULL,
+    `password`      varchar(64)         NOT NULL,
+    `role`          varchar(64)         NOT NULL,
+    `enable`        tinyint(1)          NOT NULL,
+    `export_secret` varchar(64)         NOT NULL,
+    `access_token`  varchar(64) DEFAULT NULL,
+    `create_time`   bigint(20)          NOT NULL,
+    `update_time`   bigint(20)          NOT NULL,
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `login_name` (`login_name`),
+    UNIQUE KEY `export_secret` (`export_secret`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4;
+
+-- Create syntax for TABLE 'user_permission'
+CREATE TABLE IF NOT EXISTS `user_permission`
+(
+    `user_id`    bigint(20) unsigned NOT NULL,
+    `permission` varchar(64)         NOT NULL,
+    `scope`      text                NOT NULL,
+    PRIMARY KEY (`user_id`, `permission`)
+) ENGINE = InnoDB
+  DEFAULT CHARSET = utf8mb4;
+
 -- Create syntax for TABLE 'app'
 CREATE TABLE IF NOT EXISTS `app`
 (
@@ -58,25 +87,6 @@ CREATE TABLE IF NOT EXISTS `module`
 ) ENGINE = InnoDB
   DEFAULT CHARSET = utf8mb4;
 
--- Create syntax for TABLE 'user'
-CREATE TABLE IF NOT EXISTS `user`
-(
-    `id`            bigint(20) unsigned NOT NULL AUTO_INCREMENT,
-    `login_name`    varchar(64)         NOT NULL,
-    `name`          varchar(64)         NOT NULL,
-    `password`      varchar(64)         NOT NULL,
-    `role`          varchar(64)         NOT NULL,
-    `enable`        tinyint(1)          NOT NULL,
-    `export_secret` varchar(64)         NOT NULL,
-    `access_token`  varchar(64) DEFAULT NULL,
-    `create_time`   bigint(20)          NOT NULL,
-    `update_time`   bigint(20)          NOT NULL,
-    PRIMARY KEY (`id`),
-    UNIQUE KEY `login_name` (`login_name`),
-    UNIQUE KEY `export_secret` (`export_secret`)
-) ENGINE = InnoDB
-  DEFAULT CHARSET = utf8mb4;
-
 -- Create syntax for TABLE 'version'
 CREATE TABLE IF NOT EXISTS `version`
 (