Browse Source

feat: 接口权限与设备注册逻辑调整
1. 更改用户权限部分逻辑, 区分为用户和管理员权限角色
2. 新增sip域管理, 设备注册时会比对sip配置表中的 域与密码等信息
docs: 设备绑定机制的优化
1. 确定的设备绑定机制的数据库更改
2. 细化设备绑定功能的数据模型

kindring 1 năm trước cách đây
mục cha
commit
cb14210817
41 tập tin đã thay đổi với 1776 bổ sung92 xóa
  1. 9 1
      README.md
  2. 1 0
      src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java
  3. 73 0
      src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java
  4. 27 0
      src/main/java/com/genersoft/iot/vmp/conf/security/SaTokenConfigure.java
  5. 17 2
      src/main/java/com/genersoft/iot/vmp/conf/security/StpInterfaceImpl.java
  6. 3 3
      src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
  7. 24 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminCheckLogin.java
  8. 41 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminCheckRole.java
  9. 40 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminPermission.java
  10. 24 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserCheckLogin.java
  11. 41 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserCheckRole.java
  12. 41 0
      src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserPermission.java
  13. 22 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java
  14. 119 0
      src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipUserConfig.java
  15. 1 0
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java
  16. 20 7
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java
  17. 39 22
      src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java
  18. 13 0
      src/main/java/com/genersoft/iot/vmp/service/ISipConfigService.java
  19. 24 0
      src/main/java/com/genersoft/iot/vmp/service/impl/SipConfigService.java
  20. 11 1
      src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java
  21. 77 0
      src/main/java/com/genersoft/iot/vmp/storager/dao/SipConfigMapper.java
  22. 487 0
      src/main/java/com/genersoft/iot/vmp/utils/StpAdminUtil.java
  23. 496 0
      src/main/java/com/genersoft/iot/vmp/utils/StpUserUtil.java
  24. 17 0
      src/main/java/com/genersoft/iot/vmp/vmanager/account/DeviceManager.java
  25. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java
  26. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/aiLib/AiApi.java
  27. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/aiLib/AiControl.java
  28. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java
  29. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
  30. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java
  31. 6 2
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
  32. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java
  33. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java
  34. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java
  35. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java
  36. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java
  37. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java
  38. 2 0
      src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java
  39. 22 29
      src/main/java/com/genersoft/iot/vmp/vmanager/user/AccountController.java
  40. 13 15
      src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
  41. 42 10
      设备绑定机制.md

+ 9 - 1
README.md

@@ -1,12 +1,20 @@
 # 合方圆国标平台
+
 > 本项目基于开源项目 [wvp](https://github.com/648540858/wvp-GB28181-pro)
 > 定制开发特色功能.
+
 ## 项目开发环境
 
+## 关键数据
+
+### 权限验证 `sa-token`
+
 ## 数据库设计
+
 ### 预置位表
+
 > 设备预置位通过预置位国标预置位查询指令实现.
-> 配合数据表存储预置位信息,从而实现调用功能指定预置位功能  
+> 配合数据表存储预置位信息,从而实现调用功能指定预置位功能
 
 #### preset
 

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/VManageBootstrap.java

@@ -14,6 +14,7 @@ import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.ServletComponentScan;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.context.annotation.ComponentScan;
 import org.springframework.scheduling.annotation.EnableScheduling;
 
 import javax.servlet.ServletContext;

+ 73 - 0
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.conf;
 
+import cn.dev33.satoken.exception.*;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
@@ -57,6 +58,7 @@ public class GlobalExceptionHandler {
 
     /**
      * 登陆失败
+     *
      * @param e 异常
      * @return 统一返回结果
      */
@@ -65,4 +67,75 @@ public class GlobalExceptionHandler {
     public ResponseEntity<WVPResult<String>> exceptionHandler(BadCredentialsException e) {
         return new ResponseEntity<>(WVPResult.fail(ErrorCode.ERROR100.getCode(), e.getMessage()), HttpStatus.OK);
     }
+
+    /**
+     * 全局异常处理
+     */
+    @RestControllerAdvice
+    public static class AuthException {
+
+        private Logger logger = LoggerFactory.getLogger(AuthException.class);
+
+        // 拦截:未登录异常
+        @ExceptionHandler(NotLoginException.class)
+        public ResponseEntity<WVPResult> handlerException(NotLoginException e) {
+            logger.warn("[未登录异常]: {}", e.getMessage());
+            // 打印堆栈,以供调试
+//            e.printStackTrace();
+            // 构造包含401状态码和对应数据的WVPResult对象
+            WVPResult result = WVPResult.fail(ErrorCode.ERROR401);
+            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
+        }
+
+        // 拦截:缺少权限异常
+        @ExceptionHandler(NotPermissionException.class)
+        public ResponseEntity<WVPResult> handlerException(NotPermissionException e) {
+            logger.warn("[缺少权限异常] {}", e.getMessage());
+//            e.printStackTrace();
+            WVPResult result = WVPResult.fail(ErrorCode.ERROR403);
+            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
+        }
+
+        // 拦截:缺少角色异常
+        @ExceptionHandler(NotRoleException.class)
+        public ResponseEntity<WVPResult> handlerException(NotRoleException e) {
+            logger.warn("[缺少角色异常] {}", e.getMessage());
+//            e.printStackTrace();
+            WVPResult result = WVPResult.fail(ErrorCode.ERROR403);
+            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
+        }
+
+        // 拦截:二级认证校验失败异常
+        @ExceptionHandler(NotSafeException.class)
+        public ResponseEntity<WVPResult> handlerException(NotSafeException e) {
+            logger.warn("二级认证校验失败异常");
+            e.printStackTrace();
+            WVPResult result = WVPResult.fail(ErrorCode.ERROR403);
+            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(result);
+        }
+
+        // 拦截:服务封禁异常
+        @ExceptionHandler(DisableServiceException.class)
+        public WVPResult handlerException(DisableServiceException e) {
+            logger.error("当前服务已被封禁");
+            e.printStackTrace();
+            return WVPResult.fail(ErrorCode.ERROR403, "当前服务已被封禁");
+        }
+
+        // 拦截:Http Basic 校验失败异常
+        @ExceptionHandler(NotBasicAuthException.class)
+        public WVPResult handlerException(NotBasicAuthException e) {
+            logger.error("Http Basic 校验失败异常");
+            e.printStackTrace();
+            return WVPResult.fail(ErrorCode.ERROR401);
+        }
+
+        // 拦截:其它所有异常
+        @ExceptionHandler(Exception.class)
+        public WVPResult handlerException(Exception e) {
+            logger.error("其它所有异常");
+            e.printStackTrace();
+            return WVPResult.fail(ErrorCode.ERROR500);
+        }
+    }
 }

+ 27 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/SaTokenConfigure.java

@@ -0,0 +1,27 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import cn.dev33.satoken.interceptor.SaInterceptor;
+import cn.dev33.satoken.strategy.SaStrategy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotatedElementUtils;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class SaTokenConfigure implements WebMvcConfigurer {
+    // 注册 Sa-Token 拦截器,打开注解式鉴权功能
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 注册 Sa-Token 拦截器,打开注解式鉴权功能
+        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
+    }
+
+    @Autowired
+    public void rewriteSaStrategy() {
+        // 重写Sa-Token的注解处理器,增加注解合并功能
+        SaStrategy.instance.getAnnotation = (element, annotationClass) -> {
+            return AnnotatedElementUtils.getMergedAnnotation(element, annotationClass);
+        };
+    }
+}

+ 17 - 2
src/main/java/com/genersoft/iot/vmp/conf/security/StpInterfaceImpl.java

@@ -1,6 +1,8 @@
 package com.genersoft.iot.vmp.conf.security;
 
 import cn.dev33.satoken.stp.StpInterface;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Component;
 
 import java.util.ArrayList;
@@ -11,11 +13,13 @@ import java.util.List;
  */
 @Component    // 打开此注解,保证此类被springboot扫描,即可完成sa-token的自定义权限验证扩展
 public class StpInterfaceImpl implements StpInterface {
+    private Logger logger = LoggerFactory.getLogger(StpInterfaceImpl.class);
     /**
      * 返回一个账号所拥有的权限码集合
      */
     @Override
     public List<String> getPermissionList(Object loginId, String loginKey) {
+        logger.debug("[用户权限] 获取用户权限 {}: {}", loginId, loginKey);
         // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
         List<String> list = new ArrayList<>();
         list.add("101");
@@ -31,10 +35,21 @@ public class StpInterfaceImpl implements StpInterface {
      */
     @Override
     public List<String> getRoleList(Object loginId, String loginKey) {
+        logger.debug("[用户权限] 获取用户角色 {}: {}", loginId, loginKey);
         // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
         List<String> list = new ArrayList<>();
-        list.add("admin");
-        list.add("super-admin");
+        switch (loginKey) {
+            case "admin":
+//                StpAdminUtil.checkLogin();
+                list.add("admin");
+                break;
+            case "user":
+//                StpUserUtil.checkLogin();
+                list.add("user");
+                break;
+            default:
+                break;
+        }
         return list;
     }
 }

+ 3 - 3
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java

@@ -168,11 +168,11 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 //                .and().cors().configurationSource(configurationSource())
                 .and().cors()
                 .and().csrf().disable()
-                .sessionManagement()
-                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+//                .sessionManagement()
+//                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
 
                 // 配置拦截规则
-                .and()
+//                .and()
                 .authorizeRequests()
                 // 分享码验证
                 .accessDecisionManager(accessDecisionManager())

+ 24 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminCheckLogin.java

@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckLogin;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 登录认证(User版):只有登录之后才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckLogin(type = StpAdminUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaAdminCheckLogin {
+
+}
+

+ 41 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminCheckRole.java

@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import cn.dev33.satoken.annotation.SaMode;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 角色认证(User版):必须具有指定角色标识才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckRole(type = StpAdminUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaAdminCheckRole {
+    /**
+     * 需要校验的角色标识
+     *
+     * @return 需要校验的角色标识
+     */
+    @AliasFor(annotation = SaCheckRole.class)
+    String[] value() default {};
+
+    /**
+     * 验证模式:AND | OR,默认AND
+     *
+     * @return 验证模式
+     */
+    @AliasFor(annotation = SaCheckRole.class)
+    SaMode mode() default SaMode.AND;
+}
+
+

+ 40 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaAdminPermission.java

@@ -0,0 +1,40 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaMode;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 权限认证(User版):必须具有指定权限才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckPermission(type = StpAdminUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaAdminPermission {
+
+    /**
+     * 需要校验的权限码
+     *
+     * @return 需要校验的权限码
+     */
+    @AliasFor(annotation = SaCheckPermission.class)
+    String[] value() default {};
+
+    /**
+     * 验证模式:AND | OR,默认AND
+     *
+     * @return 验证模式
+     */
+    @AliasFor(annotation = SaCheckPermission.class)
+    SaMode mode() default SaMode.AND;
+
+}

+ 24 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserCheckLogin.java

@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckLogin;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+import com.genersoft.iot.vmp.utils.StpUserUtil;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 登录认证(User版):只有登录之后才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckLogin(type = StpUserUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaUserCheckLogin {
+
+}
+

+ 41 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserCheckRole.java

@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckRole;
+import cn.dev33.satoken.annotation.SaMode;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+import com.genersoft.iot.vmp.utils.StpUserUtil;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 角色认证(User版):必须具有指定角色标识才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckRole(type = StpUserUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaUserCheckRole {
+    /**
+     * 需要校验的角色标识
+     *
+     * @return 需要校验的角色标识
+     */
+    @AliasFor(annotation = SaCheckRole.class)
+    String[] value() default {};
+
+    /**
+     * 验证模式:AND | OR,默认AND
+     *
+     * @return 验证模式
+     */
+    @AliasFor(annotation = SaCheckRole.class)
+    SaMode mode() default SaMode.AND;
+}
+
+

+ 41 - 0
src/main/java/com/genersoft/iot/vmp/conf/security/saToken/SaUserPermission.java

@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.conf.security.saToken;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaMode;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
+import com.genersoft.iot.vmp.utils.StpUserUtil;
+import org.springframework.core.annotation.AliasFor;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 权限认证(User版):必须具有指定权限才能进入该方法
+ * <p> 可标注在函数、类上(效果等同于标注在此类的所有方法上)
+ *
+ * @author click33
+ */
+@SaCheckPermission(type = StpUserUtil.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+public @interface SaUserPermission {
+
+    /**
+     * 需要校验的权限码
+     *
+     * @return 需要校验的权限码
+     */
+    @AliasFor(annotation = SaCheckPermission.class)
+    String[] value() default {};
+
+    /**
+     * 验证模式:AND | OR,默认AND
+     *
+     * @return 验证模式
+     */
+    @AliasFor(annotation = SaCheckPermission.class)
+    SaMode mode() default SaMode.AND;
+
+}

+ 22 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/Device.java

@@ -198,6 +198,9 @@ public class Device {
 	@Schema(description = "SIP交互IP(设备访问平台的IP)")
 	private String localIp;
 
+	@Schema(description = "设备连接的域")
+	private String domain;
+
 
 	@Schema(description = "是否作为消息通道")
 	private boolean asMessageChannel;
@@ -220,6 +223,9 @@ public class Device {
 	@Schema(description = "分享中的播放通道")
 	private String playChannel;
 
+	@Schema(description = "设备绑定码")
+	private String bindCode;
+
 
 	public String getDeviceId() {
 		return deviceId;
@@ -531,4 +537,20 @@ public class Device {
 	public void setId(int id) {
 		this.id = id;
 	}
+
+	public String getDomain() {
+		return domain;
+	}
+
+	public void setDomain(String domain) {
+		this.domain = domain;
+	}
+
+	public String getBindCode() {
+		return bindCode;
+	}
+
+	public void setBindCode(String bindCode) {
+		this.bindCode = bindCode;
+	}
 }

+ 119 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/bean/SipUserConfig.java

@@ -0,0 +1,119 @@
+package com.genersoft.iot.vmp.gb28181.bean;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * | 字段          | 类型           | 值介绍   | 默认 | 备注                  |
+ * |-------------|--------------|-------|----|---------------------|
+ * | id          | int          | 主键    | 无  | 无                   |
+ * | adminId   | int          | 管理员id | 无  | 创建者id, 在注册时不发挥作用    |
+ * | sipDomain   | varchar(100) | sip域名 | 无  | sip域 唯一,根据域来获取对应的密码 |
+ * | serverId    | varchar(100) | 服务器id | 无  | 服务器id               |
+ * | password    | varchar(100) | 服务器密码 | 无  | 密码                  |
+ * | description | varchar(255) | 描述    | 无  | 描述                  |
+ * | enable      | char(1)      | 是否启用 0 不启用 1 启用 | 1  | 只有启用的情况下才会被允许注册     |
+ * | createTime  | datetime     | 创建时间  | 无  | 创建时间                |
+ */
+public class SipUserConfig {
+    @Schema(description = "配置id")
+    private int id;
+    @Schema(description = "管理员id")
+    private int adminId;
+    @Schema(description = "sip域名")
+    private String sipDomain;
+    @Schema(description = "服务器id")
+    private String serverId;
+    @Schema(description = "服务器密码")
+    private String password;
+    @Schema(description = "描述")
+    private String description;
+    @Schema(description = "是否启用 0 不启用 1 启用")
+    private String enable;
+
+    @Schema(description = "是否有绑定机制")
+    private String enableBind;
+
+    @Schema(description = "创建时间")
+    private String createTime;
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public void setAdminId(int adminId) {
+        this.adminId = adminId;
+    }
+
+    public void setSipDomain(String sipDomain) {
+        this.sipDomain = sipDomain;
+    }
+
+    public void setServerId(String serverId) {
+        this.serverId = serverId;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setEnable(String enable) {
+        this.enable = enable;
+    }
+
+
+    public void setCreateTime(String createTime) {
+        this.createTime = createTime;
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public int getAdminId() {
+        return adminId;
+    }
+
+    public String getSipDomain() {
+        return sipDomain;
+    }
+
+    public String getServerId() {
+        return serverId;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getEnable() {
+        return enable;
+    }
+
+    public Boolean isEnable() {
+        return enable.equals("1");
+    }
+
+    public String getCreateTime() {
+        return createTime;
+    }
+
+    public String getEnableBind() {
+        return enableBind;
+    }
+
+    public void setEnableBind(String enableBind) {
+        this.enableBind = enableBind;
+    }
+
+    public Boolean isEnableBind() {
+        return enableBind.equals("1");
+    }
+}

+ 1 - 0
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/SIPProcessorObserver.java

@@ -84,6 +84,7 @@ public class SIPProcessorObserver implements ISIPProcessorObserver {
         // 获取设备ID 34020000002000000123 通过正则
         try{
             if (fromHeader != null) {
+                logger.info("fromHeader: {}", fromHeader);
                 deviceId = fromHeader.getAddress().getURI().toString().split(":")[1].split("@")[0];
             }
         }catch (Exception e){

+ 20 - 7
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/cmd/SIPRequestHeaderProvider.java

@@ -4,8 +4,10 @@ import com.genersoft.iot.vmp.conf.SipConfig;
 import com.genersoft.iot.vmp.gb28181.SipLayer;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.SipTransactionInfo;
+import com.genersoft.iot.vmp.gb28181.bean.SipUserConfig;
 import com.genersoft.iot.vmp.gb28181.session.VideoStreamSessionManager;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
+import com.genersoft.iot.vmp.service.ISipConfigService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.utils.GitUtil;
 import gov.nist.javax.sip.message.SIPRequest;
@@ -45,9 +47,13 @@ public class SIPRequestHeaderProvider {
 
 	@Autowired
 	private VideoStreamSessionManager streamSession;
-	
+
+	@Autowired
+	private ISipConfigService sipConfigService;
+
 	public Request createMessageRequest(Device device, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
 		// sipuri
 		SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
 		// via
@@ -55,8 +61,9 @@ public class SIPRequestHeaderProvider {
 		ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), viaTag);
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
+
 		// from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag);
 		// to
@@ -81,6 +88,7 @@ public class SIPRequestHeaderProvider {
 	
 	public Request createInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, String ssrc, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
 		//请求行
 		SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
 		//via
@@ -91,7 +99,7 @@ public class SIPRequestHeaderProvider {
 		viaHeaders.add(viaHeader);
 
 		//from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
 		//to
@@ -121,6 +129,7 @@ public class SIPRequestHeaderProvider {
 	
 	public Request createPlaybackInviteRequest(Device device, String channelId, String content, String viaTag, String fromTag, String toTag, CallIdHeader callIdHeader, String ssrc) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
 		//请求行
 		SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
 		// via
@@ -129,7 +138,7 @@ public class SIPRequestHeaderProvider {
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
 		//from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, fromTag); //必须要有标记,否则无法创建会话,无法回应ack
 		//to
@@ -161,6 +170,7 @@ public class SIPRequestHeaderProvider {
 
 	public Request createByteRequest(Device device, String channelId, SipTransactionInfo transactionInfo) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
 		//请求行
 		SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
 		// via
@@ -168,7 +178,7 @@ public class SIPRequestHeaderProvider {
 		ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
 		viaHeaders.add(viaHeader);
 		//from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
 		//to
@@ -196,6 +206,8 @@ public class SIPRequestHeaderProvider {
 
 	public Request createSubscribeRequest(Device device, String content, SIPRequest requestOld, Integer expires, String event, CallIdHeader callIdHeader) throws ParseException, InvalidArgumentException, PeerUnavailableException {
 		Request request = null;
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
+
 		// sipuri
 		SipURI requestURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(device.getDeviceId(), device.getHostAddress());
 		// via
@@ -205,7 +217,7 @@ public class SIPRequestHeaderProvider {
 		viaHeader.setRPort();
 		viaHeaders.add(viaHeader);
 		// from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(), sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, requestOld == null ? SipUtils.getNewFromTag() :requestOld.getFromTag());
 		// to
@@ -250,6 +262,7 @@ public class SIPRequestHeaderProvider {
 		if (device == null || transactionInfo == null) {
 			return null;
 		}
+		SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(device.getDomain());
 		SIPRequest request = null;
 		//请求行
 		SipURI requestLine = sipLayer.getSipFactory().createAddressFactory().createSipURI(channelId, device.getHostAddress());
@@ -258,7 +271,7 @@ public class SIPRequestHeaderProvider {
 		ViaHeader viaHeader = sipLayer.getSipFactory().createHeaderFactory().createViaHeader(sipLayer.getLocalIp(device.getLocalIp()), sipConfig.getPort(), device.getTransport(), SipUtils.getNewViaTag());
 		viaHeaders.add(viaHeader);
 		//from
-		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipConfig.getId(),sipConfig.getDomain());
+		SipURI fromSipURI = sipLayer.getSipFactory().createAddressFactory().createSipURI(sipUserConfig.getServerId(), sipUserConfig.getSipDomain());
 		Address fromAddress = sipLayer.getSipFactory().createAddressFactory().createAddress(fromSipURI);
 		FromHeader fromHeader = sipLayer.getSipFactory().createHeaderFactory().createFromHeader(fromAddress, transactionInfo.getFromTag());
 		//to

+ 39 - 22
src/main/java/com/genersoft/iot/vmp/gb28181/transmit/event/request/impl/RegisterRequestProcessor.java

@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.gb28181.auth.DigestServerAuthenticationHelper;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.RemoteAddressInfo;
+import com.genersoft.iot.vmp.gb28181.bean.SipUserConfig;
 import com.genersoft.iot.vmp.gb28181.bean.WvpSipDate;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPProcessorObserver;
 import com.genersoft.iot.vmp.gb28181.transmit.SIPSender;
@@ -12,6 +13,8 @@ import com.genersoft.iot.vmp.gb28181.transmit.event.request.ISIPRequestProcessor
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.SIPRequestProcessorParent;
 import com.genersoft.iot.vmp.gb28181.utils.SipUtils;
 import com.genersoft.iot.vmp.service.IDeviceService;
+import com.genersoft.iot.vmp.service.ISipConfigService;
+import com.genersoft.iot.vmp.storager.dao.SipConfigMapper;
 import com.genersoft.iot.vmp.utils.DateUtil;
 import gov.nist.javax.sip.RequestEventExt;
 import gov.nist.javax.sip.address.AddressImpl;
@@ -62,6 +65,9 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
     @Autowired
     private UserSetting userSetting;
 
+    @Autowired
+    private ISipConfigService sipConfigService;
+
     @Override
     public void afterPropertiesSet() throws Exception {
         // 添加消息处理的订阅
@@ -78,21 +84,8 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
         try {
             RequestEventExt evtExt = (RequestEventExt) evt;
             String requestAddress = evtExt.getRemoteIpAddress() + ":" + evtExt.getRemotePort();
-            logger.info("[注册请求] 开始处理: {}", requestAddress);
-//            MBeanServer beanServer = ManagementFactory.getPlatformMBeanServer();
-//            QueryExp protocol = Query.match(Query.attr("protocol"), Query.value("HTTP/1.1"));
-////            ObjectName name = new ObjectName("*:type=Connector,*");
-//            ObjectName name = new ObjectName("*:*");
-//            Set<ObjectName> objectNames = beanServer.queryNames(name, protocol);
-//            for (ObjectName objectName : objectNames) {
-//                String catalina = objectName.getDomain();
-//                if ("Catalina".equals(catalina)) {
-//                    System.out.println(objectName.getKeyProperty("port"));
-//                }
-//            }
-
-//            System.out.println(ServiceInfo.getServerPort());
-            SIPRequest request = (SIPRequest)evt.getRequest();
+            logger.info("[sip注册] 开始处理: {}", requestAddress);
+            SIPRequest request = (SIPRequest) evt.getRequest();
             Response response = null;
             boolean passwordCorrect = false;
             // 注册标志
@@ -102,12 +95,27 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
             SipUri uri = (SipUri) address.getURI();
             String deviceId = uri.getUser();
             Device device = deviceService.getDevice(deviceId);
-            String password = (device != null && !ObjectUtils.isEmpty(device.getPassword()))? device.getPassword() : sipConfig.getPassword();
+
+            // 获取对应的sip配置
+            logger.info("[sip 注册信息] host" + uri.getHost());
+            SipUserConfig sipUserConfig = sipConfigService.getSipConfigByDomain(uri.getHost());
+            if (sipUserConfig == null || !sipUserConfig.isEnable()) {
+                logger.error("[sip注册] 不受支持的sip域, 回复404: {}", uri.getHost());
+                response = getMessageFactory().createResponse(Response.NOT_FOUND, request);
+                response.setReasonPhrase("wrong domain");
+                logger.info("[sip注册] 不受支持的sip域: {}", requestAddress);
+                sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
+                return;
+            }
+
+            // 获取密码
+            String password = (device != null && !ObjectUtils.isEmpty(device.getPassword())) ? device.getPassword() : sipUserConfig.getPassword();
+
             AuthorizationHeader authHead = (AuthorizationHeader) request.getHeader(AuthorizationHeader.NAME);
             if (authHead == null && !ObjectUtils.isEmpty(password)) {
-                logger.info("[注册请求] 回复401: {}", requestAddress);
+                logger.info("[sip注册] 回复401: {}", requestAddress);
                 response = getMessageFactory().createResponse(Response.UNAUTHORIZED, request);
-                new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipConfig.getDomain());
+                new DigestServerAuthenticationHelper().generateChallenge(getHeaderFactory(), response, sipUserConfig.getSipDomain());
                 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
                 return;
             }
@@ -120,7 +128,7 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
                 // 注册失败
                 response = getMessageFactory().createResponse(Response.FORBIDDEN, request);
                 response.setReasonPhrase("wrong password");
-                logger.info("[注册请求] 密码/SIP服务器ID错误, 回复403: {}", requestAddress);
+                logger.info("[sip注册] 密码/SIP服务器ID错误, 回复403: {}", requestAddress);
                 sipSender.transmitRequest(request.getLocalAddress().getHostAddress(), response);
                 return;
             }
@@ -155,11 +163,13 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
                 device.setTreeType("CivilCode");
                 device.setDeviceId(deviceId);
                 device.setOnline(0);
+                // todo 检查设备是否有绑定码
             }
             device.setIp(remoteAddressInfo.getIp());
             device.setPort(remoteAddressInfo.getPort());
             device.setHostAddress(remoteAddressInfo.getIp().concat(":").concat(String.valueOf(remoteAddressInfo.getPort())));
             device.setLocalIp(request.getLocalAddress().getHostAddress());
+            device.setDomain(sipUserConfig.getSipDomain());
             if (request.getExpires().getExpires() == 0) {
                 // 注销成功
                 registerFlag = false;
@@ -177,15 +187,22 @@ public class RegisterRequestProcessor extends SIPRequestProcessorParent implemen
             // 注册成功
             // 保存到redis
             if (registerFlag) {
-                logger.info("[注册成功] deviceId: {}->{}",  deviceId, requestAddress);
+                logger.info("[sip注册成功] deviceId: {}->{}", deviceId, requestAddress);
                 device.setRegisterTime(DateUtil.getNow());
                 deviceService.online(device);
+
+
+                if (sipUserConfig.isEnableBind()) {
+                    logger.info("[sip注册成功] 设备:{} 连接的域启用绑定, 尝试获取设备绑定码中");
+                    // todo 获取设备注册码
+
+                }
             } else {
-                logger.info("[注销成功] deviceId: {}->{}" ,deviceId, requestAddress);
+                logger.info("[sip注销成功] deviceId: {}->{}", deviceId, requestAddress);
                 deviceService.offline(deviceId, "主动注销");
             }
         } catch (SipException | NoSuchAlgorithmException | ParseException e) {
-            logger.error("未处理的异常 ", e);
+            logger.error("sip注册 发现 未处理的异常 ", e);
         }
     }
 }

+ 13 - 0
src/main/java/com/genersoft/iot/vmp/service/ISipConfigService.java

@@ -0,0 +1,13 @@
+package com.genersoft.iot.vmp.service;
+
+import com.genersoft.iot.vmp.gb28181.bean.SipUserConfig;
+
+public interface ISipConfigService {
+    /**
+     * 获取对应的sip配置信息
+     *
+     * @param domain
+     * @return
+     */
+    SipUserConfig getSipConfigByDomain(String domain);
+}

+ 24 - 0
src/main/java/com/genersoft/iot/vmp/service/impl/SipConfigService.java

@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.service.impl;
+
+import com.genersoft.iot.vmp.gb28181.bean.SipUserConfig;
+import com.genersoft.iot.vmp.service.ISipConfigService;
+import com.genersoft.iot.vmp.storager.dao.SipConfigMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class SipConfigService implements ISipConfigService {
+    private final static Logger logger = LoggerFactory.getLogger(SipConfigService.class);
+
+    @Autowired
+    private SipConfigMapper sipConfigMapper;
+
+    @Override
+    public SipUserConfig getSipConfigByDomain(String domain) {
+        return sipConfigMapper.querySipConfigByDomain(domain);
+    }
+}

+ 11 - 1
src/main/java/com/genersoft/iot/vmp/storager/dao/DeviceMapper.java

@@ -50,7 +50,8 @@ public interface DeviceMapper {
             "shareTime," +
             "isShare," +
             "playChannel," +
-            "autoUpdate" +
+            "autoUpdate," +
+            "domain" +
             " FROM device WHERE deviceId = #{deviceId}")
     Device getDeviceByDeviceId(String deviceId);
 
@@ -82,6 +83,7 @@ public interface DeviceMapper {
             "asMessageChannel," +
             "geoCoordSys," +
             "treeType," +
+            "domain," +
             "online" +
             ") VALUES (" +
             "#{deviceId}," +
@@ -111,6 +113,7 @@ public interface DeviceMapper {
             "#{asMessageChannel}," +
             "#{geoCoordSys}," +
             "#{treeType}," +
+            "#{domain}," +
             "#{online}" +
             ")")
     int add(Device device);
@@ -139,6 +142,7 @@ public interface DeviceMapper {
             "<if test=\"shareTime != null\">, shareTime=#{shareTime}</if>" +
             "<if test=\"isShare != null\">, isShare=#{isShare}</if>" +
             "<if test=\"autoUpdate != null\">, autoUpdate=#{autoUpdate}</if>" +
+            "<if test=\"domain != null\">, domain=#{domain}</if>" +
             "WHERE deviceId=#{deviceId}" +
             " </script>"})
     int update(Device device);
@@ -249,6 +253,7 @@ public interface DeviceMapper {
                     "shareExpires," +
                     "shareTime," +
                     "isShare," +
+                    "domain," +
                     "playChannel," +
                     "(SELECT count(0) FROM device_channel WHERE deviceId=de.deviceId) as channelCount  FROM device de" +
                     "<if test=\"online != null\"> where online=${online}</if>" +
@@ -298,6 +303,7 @@ public interface DeviceMapper {
             "shareTime," +
             "isShare," +
             "playChannel," +
+            "domain," +
             "autoUpdate" +
             " FROM device WHERE online = 1")
     List<Device> getOnlineDevices();
@@ -334,6 +340,7 @@ public interface DeviceMapper {
             "mediaServerId," +
             "audioEncodePt," +
             "playChannel," +
+            "domain," +
             "autoUpdate" +
             " FROM device WHERE ip = #{host} AND port=#{port}")
     Device getDeviceByHostAndPort(String host, int port);
@@ -364,6 +371,7 @@ public interface DeviceMapper {
             "<if test=\"shareTime != null\">, shareTime=#{shareTime}</if>" +
             "<if test=\"isShare != null\">, isShare=#{isShare}</if>" +
             "<if test=\"playChannel != null\">, playChannel=#{playChannel}</if>" +
+            "<if test=\"domain != null\">, domain=#{domain}</if>" +
             "WHERE deviceId=#{deviceId}" +
             " </script>"})
     int updateCustom(Device device);
@@ -380,6 +388,7 @@ public interface DeviceMapper {
             "asMessageChannel," +
             "geoCoordSys," +
             "treeType," +
+            "domain," +
             "online" +
             ") VALUES (" +
             "#{deviceId}," +
@@ -393,6 +402,7 @@ public interface DeviceMapper {
             "#{asMessageChannel}," +
             "#{geoCoordSys}," +
             "#{treeType}," +
+            "#{domain}," +
             "#{online}" +
             ")")
     void addCustomDevice(Device device);

+ 77 - 0
src/main/java/com/genersoft/iot/vmp/storager/dao/SipConfigMapper.java

@@ -0,0 +1,77 @@
+package com.genersoft.iot.vmp.storager.dao;
+// class SipUserConfig
+//private int id;
+//private int adminId;
+//private String sipDomain;
+//private String serverId;
+//private String password;
+//private String description;
+//private Boolean enable;
+//private String createTime;
+
+import com.genersoft.iot.vmp.gb28181.bean.SipUserConfig;
+import org.apache.ibatis.annotations.*;
+import org.springframework.stereotype.Repository;
+
+/**
+ * sip配置信息 sipConfig 表
+ */
+@Mapper
+@Repository
+public interface SipConfigMapper {
+
+    // 新增sip规则
+    @Insert("INSERT INTO sip_config (" +
+            "adminId, " +
+            "sipDomain, " +
+            "serverId, " +
+            "password," +
+            "createTime" +
+            ") VALUES (" +
+            "#{adminId}, " +
+            "#{sipDomain}, " +
+            "#{serverId}, " +
+            "#{password}, " +
+            "#{createTime} " +
+            ")"
+    )
+    int addSipConfig(int adminId, String sipDomain, String serverId, String password, String createTime);
+
+    // 禁用规则
+    @Update("UPDATE sip_config SET enable = 1 WHERE id = ${id}")
+    int enableSipConfig(SipUserConfig sipUserConfig);
+
+    // 禁用服务
+    @Update("UPDATE sip_config SET enable = 0 WHERE id = ${id}")
+    int disableSipConfig(SipUserConfig sipUserConfig);
+
+    // 更新sip规则
+    @Update("UPDATE sip_config SET " +
+            "adminId = #{adminId}, " +
+            "sipDomain = #{sipDomain}, " +
+            "serverId = #{serverId}, " +
+            "password = #{password}, " +
+            "description = #{description}, " +
+            "enable = #{enable}, " +
+            "createTime = #{createTime} " +
+            "WHERE id = #{id}"
+    )
+    int updateSipConfig(SipUserConfig sipUserConfig);
+
+    // 删除sip规则
+    @Delete("DELETE FROM sip_config WHERE id = ${id}")
+    int deleteSipConfig(SipUserConfig sipUserConfig);
+
+    // 查询根据域获取对应的sip配置
+    @Select("SELECT * FROM sip_config WHERE sipDomain = ${sipDomain}")
+    SipUserConfig querySipConfigByDomain(String sipDomain);
+
+    // 获取指定管理员创建的sip规则
+    @Select("SELECT * FROM sip_config WHERE adminId = ${adminId}")
+    SipUserConfig querySipConfigByAdminId(int adminId);
+
+    // 获取所有sip规则
+    @Select("SELECT * FROM sip_config")
+    SipUserConfig queryAllSipConfig();
+
+}

+ 487 - 0
src/main/java/com/genersoft/iot/vmp/utils/StpAdminUtil.java

@@ -0,0 +1,487 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package com.genersoft.iot.vmp.utils;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.listener.SaTokenEventCenter;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.session.TokenSign;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.SaTokenInfo;
+import cn.dev33.satoken.stp.StpLogic;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public class StpAdminUtil {
+
+    public static final String TYPE = "admin";
+
+    public static StpLogic stpLogic = new StpLogic(TYPE);
+
+    private StpAdminUtil() {
+    }
+
+    public static String getLoginType() {
+        return stpLogic.getLoginType();
+    }
+
+    public static void setStpLogic(StpLogic newStpLogic) {
+        stpLogic = newStpLogic;
+        SaManager.putStpLogic(newStpLogic);
+        SaTokenEventCenter.doSetStpLogic(stpLogic);
+    }
+
+    public static StpLogic getStpLogic() {
+        return stpLogic;
+    }
+
+    public static String getTokenName() {
+        return stpLogic.getTokenName();
+    }
+
+    public static void setTokenValue(String tokenValue) {
+        stpLogic.setTokenValue(tokenValue);
+    }
+
+    public static void setTokenValue(String tokenValue, int cookieTimeout) {
+        stpLogic.setTokenValue(tokenValue, cookieTimeout);
+    }
+
+    public static void setTokenValue(String tokenValue, SaLoginModel loginModel) {
+        stpLogic.setTokenValue(tokenValue, loginModel);
+    }
+
+    public static String getTokenValue() {
+        return stpLogic.getTokenValue();
+    }
+
+    public static String getTokenValueNotCut() {
+        return stpLogic.getTokenValueNotCut();
+    }
+
+    public static SaTokenInfo getTokenInfo() {
+        return stpLogic.getTokenInfo();
+    }
+
+    public static void login(Object id) {
+        stpLogic.login(id);
+    }
+
+    public static void login(Object id, String device) {
+        stpLogic.login(id, device);
+    }
+
+    public static void login(Object id, boolean isLastingCookie) {
+        stpLogic.login(id, isLastingCookie);
+    }
+
+    public static void login(Object id, long timeout) {
+        stpLogic.login(id, timeout);
+    }
+
+    public static void login(Object id, SaLoginModel loginModel) {
+        stpLogic.login(id, loginModel);
+    }
+
+    public static String createLoginSession(Object id) {
+        return stpLogic.createLoginSession(id);
+    }
+
+    public static String createLoginSession(Object id, SaLoginModel loginModel) {
+        return stpLogic.createLoginSession(id, loginModel);
+    }
+
+    public static void logout() {
+        stpLogic.logout();
+    }
+
+    public static void logout(Object loginId) {
+        stpLogic.logout(loginId);
+    }
+
+    public static void logout(Object loginId, String device) {
+        stpLogic.logout(loginId, device);
+    }
+
+    public static void logoutByTokenValue(String tokenValue) {
+        stpLogic.logoutByTokenValue(tokenValue);
+    }
+
+    public static void kickout(Object loginId) {
+        stpLogic.kickout(loginId);
+    }
+
+    public static void kickout(Object loginId, String device) {
+        stpLogic.kickout(loginId, device);
+    }
+
+    public static void kickoutByTokenValue(String tokenValue) {
+        stpLogic.kickoutByTokenValue(tokenValue);
+    }
+
+    public static void replaced(Object loginId, String device) {
+        stpLogic.replaced(loginId, device);
+    }
+
+    public static boolean isLogin() {
+        return stpLogic.isLogin();
+    }
+
+    public static boolean isLogin(Object loginId) {
+        return stpLogic.isLogin(loginId);
+    }
+
+    public static void checkLogin() {
+        stpLogic.checkLogin();
+    }
+
+    public static Object getLoginId() {
+        return stpLogic.getLoginId();
+    }
+
+    public static <T> T getLoginId(T defaultValue) {
+        return stpLogic.getLoginId(defaultValue);
+    }
+
+    public static Object getLoginIdDefaultNull() {
+        return stpLogic.getLoginIdDefaultNull();
+    }
+
+    public static String getLoginIdAsString() {
+        return stpLogic.getLoginIdAsString();
+    }
+
+    public static int getLoginIdAsInt() {
+        return stpLogic.getLoginIdAsInt();
+    }
+
+    public static long getLoginIdAsLong() {
+        return stpLogic.getLoginIdAsLong();
+    }
+
+    public static Object getLoginIdByToken(String tokenValue) {
+        return stpLogic.getLoginIdByToken(tokenValue);
+    }
+
+    public static Object getExtra(String key) {
+        return stpLogic.getExtra(key);
+    }
+
+    public static Object getExtra(String tokenValue, String key) {
+        return stpLogic.getExtra(tokenValue, key);
+    }
+
+    public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
+        return stpLogic.getSessionByLoginId(loginId, isCreate);
+    }
+
+    public static SaSession getSessionBySessionId(String sessionId) {
+        return stpLogic.getSessionBySessionId(sessionId);
+    }
+
+    public static SaSession getSessionByLoginId(Object loginId) {
+        return stpLogic.getSessionByLoginId(loginId);
+    }
+
+    public static SaSession getSession(boolean isCreate) {
+        return stpLogic.getSession(isCreate);
+    }
+
+    public static SaSession getSession() {
+        return stpLogic.getSession();
+    }
+
+    public static SaSession getTokenSessionByToken(String tokenValue) {
+        return stpLogic.getTokenSessionByToken(tokenValue);
+    }
+
+    public static SaSession getTokenSession() {
+        return stpLogic.getTokenSession();
+    }
+
+    public static SaSession getAnonTokenSession() {
+        return stpLogic.getAnonTokenSession();
+    }
+
+    public static void updateLastActiveToNow() {
+        stpLogic.updateLastActiveToNow();
+    }
+
+    public static void checkActiveTimeout() {
+        stpLogic.checkActiveTimeout();
+    }
+
+    public static long getTokenTimeout() {
+        return stpLogic.getTokenTimeout();
+    }
+
+    public static long getTokenTimeout(String token) {
+        return stpLogic.getTokenTimeout(token);
+    }
+
+    public static long getSessionTimeout() {
+        return stpLogic.getSessionTimeout();
+    }
+
+    public static long getTokenSessionTimeout() {
+        return stpLogic.getTokenSessionTimeout();
+    }
+
+    public static long getTokenActiveTimeout() {
+        return stpLogic.getTokenActiveTimeout();
+    }
+
+    public static void renewTimeout(long timeout) {
+        stpLogic.renewTimeout(timeout);
+    }
+
+    public static void renewTimeout(String tokenValue, long timeout) {
+        stpLogic.renewTimeout(tokenValue, timeout);
+    }
+
+    public static List<String> getRoleList() {
+        return stpLogic.getRoleList();
+    }
+
+    public static List<String> getRoleList(Object loginId) {
+        return stpLogic.getRoleList(loginId);
+    }
+
+    public static boolean hasRole(String role) {
+        return stpLogic.hasRole(role);
+    }
+
+    public static boolean hasRole(Object loginId, String role) {
+        return stpLogic.hasRole(loginId, role);
+    }
+
+    public static boolean hasRoleAnd(String... roleArray) {
+        return stpLogic.hasRoleAnd(roleArray);
+    }
+
+    public static boolean hasRoleOr(String... roleArray) {
+        return stpLogic.hasRoleOr(roleArray);
+    }
+
+    public static void checkRole(String role) {
+        stpLogic.checkRole(role);
+    }
+
+    public static void checkRoleAnd(String... roleArray) {
+        stpLogic.checkRoleAnd(roleArray);
+    }
+
+    public static void checkRoleOr(String... roleArray) {
+        stpLogic.checkRoleOr(roleArray);
+    }
+
+    public static List<String> getPermissionList() {
+        return stpLogic.getPermissionList();
+    }
+
+    public static List<String> getPermissionList(Object loginId) {
+        return stpLogic.getPermissionList(loginId);
+    }
+
+    public static boolean hasPermission(String permission) {
+        return stpLogic.hasPermission(permission);
+    }
+
+    public static boolean hasPermission(Object loginId, String permission) {
+        return stpLogic.hasPermission(loginId, permission);
+    }
+
+    public static boolean hasPermissionAnd(String... permissionArray) {
+        return stpLogic.hasPermissionAnd(permissionArray);
+    }
+
+    public static boolean hasPermissionOr(String... permissionArray) {
+        return stpLogic.hasPermissionOr(permissionArray);
+    }
+
+    public static void checkPermission(String permission) {
+        stpLogic.checkPermission(permission);
+    }
+
+    public static void checkPermissionAnd(String... permissionArray) {
+        stpLogic.checkPermissionAnd(permissionArray);
+    }
+
+    public static void checkPermissionOr(String... permissionArray) {
+        stpLogic.checkPermissionOr(permissionArray);
+    }
+
+    public static String getTokenValueByLoginId(Object loginId) {
+        return stpLogic.getTokenValueByLoginId(loginId);
+    }
+
+    public static String getTokenValueByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueByLoginId(loginId, device);
+    }
+
+    public static List<String> getTokenValueListByLoginId(Object loginId) {
+        return stpLogic.getTokenValueListByLoginId(loginId);
+    }
+
+    public static List<String> getTokenValueListByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueListByLoginId(loginId, device);
+    }
+
+    public static List<TokenSign> getTokenSignListByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenSignListByLoginId(loginId, device);
+    }
+
+    public static String getLoginDevice() {
+        return stpLogic.getLoginDevice();
+    }
+
+    public static List<String> searchTokenValue(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchTokenValue(keyword, start, size, sortType);
+    }
+
+    public static List<String> searchSessionId(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchSessionId(keyword, start, size, sortType);
+    }
+
+    public static List<String> searchTokenSessionId(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchTokenSessionId(keyword, start, size, sortType);
+    }
+
+    public static void disable(Object loginId, long time) {
+        stpLogic.disable(loginId, time);
+    }
+
+    public static boolean isDisable(Object loginId) {
+        return stpLogic.isDisable(loginId);
+    }
+
+    public static void checkDisable(Object loginId) {
+        stpLogic.checkDisable(loginId);
+    }
+
+    public static long getDisableTime(Object loginId) {
+        return stpLogic.getDisableTime(loginId);
+    }
+
+    public static void untieDisable(Object loginId) {
+        stpLogic.untieDisable(loginId);
+    }
+
+    public static void disable(Object loginId, String service, long time) {
+        stpLogic.disable(loginId, service, time);
+    }
+
+    public static boolean isDisable(Object loginId, String service) {
+        return stpLogic.isDisable(loginId, service);
+    }
+
+    public static void checkDisable(Object loginId, String... services) {
+        stpLogic.checkDisable(loginId, services);
+    }
+
+    public static long getDisableTime(Object loginId, String service) {
+        return stpLogic.getDisableTime(loginId, service);
+    }
+
+    public static void untieDisable(Object loginId, String... services) {
+        stpLogic.untieDisable(loginId, services);
+    }
+
+    public static void disableLevel(Object loginId, int level, long time) {
+        stpLogic.disableLevel(loginId, level, time);
+    }
+
+    public static void disableLevel(Object loginId, String service, int level, long time) {
+        stpLogic.disableLevel(loginId, service, level, time);
+    }
+
+    public static boolean isDisableLevel(Object loginId, int level) {
+        return stpLogic.isDisableLevel(loginId, level);
+    }
+
+    public static boolean isDisableLevel(Object loginId, String service, int level) {
+        return stpLogic.isDisableLevel(loginId, service, level);
+    }
+
+    public static void checkDisableLevel(Object loginId, int level) {
+        stpLogic.checkDisableLevel(loginId, level);
+    }
+
+    public static void checkDisableLevel(Object loginId, String service, int level) {
+        stpLogic.checkDisableLevel(loginId, service, level);
+    }
+
+    public static int getDisableLevel(Object loginId) {
+        return stpLogic.getDisableLevel(loginId);
+    }
+
+    public static int getDisableLevel(Object loginId, String service) {
+        return stpLogic.getDisableLevel(loginId, service);
+    }
+
+    public static void switchTo(Object loginId) {
+        stpLogic.switchTo(loginId);
+    }
+
+    public static void endSwitch() {
+        stpLogic.endSwitch();
+    }
+
+    public static boolean isSwitch() {
+        return stpLogic.isSwitch();
+    }
+
+    public static void switchTo(Object loginId, SaFunction function) {
+        stpLogic.switchTo(loginId, function);
+    }
+
+    public static void openSafe(long safeTime) {
+        stpLogic.openSafe(safeTime);
+    }
+
+    public static void openSafe(String service, long safeTime) {
+        stpLogic.openSafe(service, safeTime);
+    }
+
+    public static boolean isSafe() {
+        return stpLogic.isSafe();
+    }
+
+    public static boolean isSafe(String service) {
+        return stpLogic.isSafe(service);
+    }
+
+    public static boolean isSafe(String tokenValue, String service) {
+        return stpLogic.isSafe(tokenValue, service);
+    }
+
+    public static void checkSafe() {
+        stpLogic.checkSafe();
+    }
+
+    public static void checkSafe(String service) {
+        stpLogic.checkSafe(service);
+    }
+
+    public static long getSafeTime() {
+        return stpLogic.getSafeTime();
+    }
+
+    public static long getSafeTime(String service) {
+        return stpLogic.getSafeTime(service);
+    }
+
+    public static void closeSafe() {
+        stpLogic.closeSafe();
+    }
+
+    public static void closeSafe(String service) {
+        stpLogic.closeSafe(service);
+    }
+}

+ 496 - 0
src/main/java/com/genersoft/iot/vmp/utils/StpUserUtil.java

@@ -0,0 +1,496 @@
+//
+// Source code recreated from a .class file by IntelliJ IDEA
+// (powered by FernFlower decompiler)
+//
+
+package com.genersoft.iot.vmp.utils;
+
+import cn.dev33.satoken.SaManager;
+import cn.dev33.satoken.fun.SaFunction;
+import cn.dev33.satoken.listener.SaTokenEventCenter;
+import cn.dev33.satoken.session.SaSession;
+import cn.dev33.satoken.session.TokenSign;
+import cn.dev33.satoken.stp.SaLoginModel;
+import cn.dev33.satoken.stp.SaTokenInfo;
+import cn.dev33.satoken.stp.StpLogic;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+public class StpUserUtil {
+
+    public static final String TYPE = "user";
+
+    // 使用匿名子类 重写`stpLogic对象`的一些方法
+    public static StpLogic stpLogic = new StpLogic(TYPE) {
+        // 重写 StpLogic 类下的 `splicingKeyTokenName` 函数,返回一个与 `StpUtil` 不同的token名称, 防止冲突
+        @Override
+        public String splicingKeyTokenName() {
+            return super.splicingKeyTokenName() + "-user";
+        }
+        // 同理你可以按需重写一些其它方法 ...
+    };
+
+    private StpUserUtil() {
+    }
+
+
+    public static String getLoginType() {
+        return stpLogic.getLoginType();
+    }
+
+    public static void setStpLogic(StpLogic newStpLogic) {
+        stpLogic = newStpLogic;
+        SaManager.putStpLogic(newStpLogic);
+        SaTokenEventCenter.doSetStpLogic(stpLogic);
+    }
+
+    public static StpLogic getStpLogic() {
+        return stpLogic;
+    }
+
+    public static String getTokenName() {
+        return stpLogic.getTokenName();
+    }
+
+    public static void setTokenValue(String tokenValue) {
+        stpLogic.setTokenValue(tokenValue);
+    }
+
+    public static void setTokenValue(String tokenValue, int cookieTimeout) {
+        stpLogic.setTokenValue(tokenValue, cookieTimeout);
+    }
+
+    public static void setTokenValue(String tokenValue, SaLoginModel loginModel) {
+        stpLogic.setTokenValue(tokenValue, loginModel);
+    }
+
+    public static String getTokenValue() {
+        return stpLogic.getTokenValue();
+    }
+
+    public static String getTokenValueNotCut() {
+        return stpLogic.getTokenValueNotCut();
+    }
+
+    public static SaTokenInfo getTokenInfo() {
+        return stpLogic.getTokenInfo();
+    }
+
+    public static void login(Object id) {
+        stpLogic.login(id);
+    }
+
+    public static void login(Object id, String device) {
+        stpLogic.login(id, device);
+    }
+
+    public static void login(Object id, boolean isLastingCookie) {
+        stpLogic.login(id, isLastingCookie);
+    }
+
+    public static void login(Object id, long timeout) {
+        stpLogic.login(id, timeout);
+    }
+
+    public static void login(Object id, SaLoginModel loginModel) {
+        stpLogic.login(id, loginModel);
+    }
+
+    public static String createLoginSession(Object id) {
+        return stpLogic.createLoginSession(id);
+    }
+
+    public static String createLoginSession(Object id, SaLoginModel loginModel) {
+        return stpLogic.createLoginSession(id, loginModel);
+    }
+
+    public static void logout() {
+        stpLogic.logout();
+    }
+
+    public static void logout(Object loginId) {
+        stpLogic.logout(loginId);
+    }
+
+    public static void logout(Object loginId, String device) {
+        stpLogic.logout(loginId, device);
+    }
+
+    public static void logoutByTokenValue(String tokenValue) {
+        stpLogic.logoutByTokenValue(tokenValue);
+    }
+
+    public static void kickout(Object loginId) {
+        stpLogic.kickout(loginId);
+    }
+
+    public static void kickout(Object loginId, String device) {
+        stpLogic.kickout(loginId, device);
+    }
+
+    public static void kickoutByTokenValue(String tokenValue) {
+        stpLogic.kickoutByTokenValue(tokenValue);
+    }
+
+    public static void replaced(Object loginId, String device) {
+        stpLogic.replaced(loginId, device);
+    }
+
+    public static boolean isLogin() {
+        return stpLogic.isLogin();
+    }
+
+    public static boolean isLogin(Object loginId) {
+        return stpLogic.isLogin(loginId);
+    }
+
+    public static void checkLogin() {
+        stpLogic.checkLogin();
+    }
+
+    public static Object getLoginId() {
+        return stpLogic.getLoginId();
+    }
+
+    public static <T> T getLoginId(T defaultValue) {
+        return stpLogic.getLoginId(defaultValue);
+    }
+
+    public static Object getLoginIdDefaultNull() {
+        return stpLogic.getLoginIdDefaultNull();
+    }
+
+    public static String getLoginIdAsString() {
+        return stpLogic.getLoginIdAsString();
+    }
+
+    public static int getLoginIdAsInt() {
+        return stpLogic.getLoginIdAsInt();
+    }
+
+    public static long getLoginIdAsLong() {
+        return stpLogic.getLoginIdAsLong();
+    }
+
+    public static Object getLoginIdByToken(String tokenValue) {
+        return stpLogic.getLoginIdByToken(tokenValue);
+    }
+
+    public static Object getExtra(String key) {
+        return stpLogic.getExtra(key);
+    }
+
+    public static Object getExtra(String tokenValue, String key) {
+        return stpLogic.getExtra(tokenValue, key);
+    }
+
+    public static SaSession getSessionByLoginId(Object loginId, boolean isCreate) {
+        return stpLogic.getSessionByLoginId(loginId, isCreate);
+    }
+
+    public static SaSession getSessionBySessionId(String sessionId) {
+        return stpLogic.getSessionBySessionId(sessionId);
+    }
+
+    public static SaSession getSessionByLoginId(Object loginId) {
+        return stpLogic.getSessionByLoginId(loginId);
+    }
+
+    public static SaSession getSession(boolean isCreate) {
+        return stpLogic.getSession(isCreate);
+    }
+
+    public static SaSession getSession() {
+        return stpLogic.getSession();
+    }
+
+    public static SaSession getTokenSessionByToken(String tokenValue) {
+        return stpLogic.getTokenSessionByToken(tokenValue);
+    }
+
+    public static SaSession getTokenSession() {
+        return stpLogic.getTokenSession();
+    }
+
+    public static SaSession getAnonTokenSession() {
+        return stpLogic.getAnonTokenSession();
+    }
+
+    public static void updateLastActiveToNow() {
+        stpLogic.updateLastActiveToNow();
+    }
+
+    public static void checkActiveTimeout() {
+        stpLogic.checkActiveTimeout();
+    }
+
+    public static long getTokenTimeout() {
+        return stpLogic.getTokenTimeout();
+    }
+
+    public static long getTokenTimeout(String token) {
+        return stpLogic.getTokenTimeout(token);
+    }
+
+    public static long getSessionTimeout() {
+        return stpLogic.getSessionTimeout();
+    }
+
+    public static long getTokenSessionTimeout() {
+        return stpLogic.getTokenSessionTimeout();
+    }
+
+    public static long getTokenActiveTimeout() {
+        return stpLogic.getTokenActiveTimeout();
+    }
+
+    public static void renewTimeout(long timeout) {
+        stpLogic.renewTimeout(timeout);
+    }
+
+    public static void renewTimeout(String tokenValue, long timeout) {
+        stpLogic.renewTimeout(tokenValue, timeout);
+    }
+
+    public static List<String> getRoleList() {
+        return stpLogic.getRoleList();
+    }
+
+    public static List<String> getRoleList(Object loginId) {
+        return stpLogic.getRoleList(loginId);
+    }
+
+    public static boolean hasRole(String role) {
+        return stpLogic.hasRole(role);
+    }
+
+    public static boolean hasRole(Object loginId, String role) {
+        return stpLogic.hasRole(loginId, role);
+    }
+
+    public static boolean hasRoleAnd(String... roleArray) {
+        return stpLogic.hasRoleAnd(roleArray);
+    }
+
+    public static boolean hasRoleOr(String... roleArray) {
+        return stpLogic.hasRoleOr(roleArray);
+    }
+
+    public static void checkRole(String role) {
+        stpLogic.checkRole(role);
+    }
+
+    public static void checkRoleAnd(String... roleArray) {
+        stpLogic.checkRoleAnd(roleArray);
+    }
+
+    public static void checkRoleOr(String... roleArray) {
+        stpLogic.checkRoleOr(roleArray);
+    }
+
+    public static List<String> getPermissionList() {
+        return stpLogic.getPermissionList();
+    }
+
+    public static List<String> getPermissionList(Object loginId) {
+        return stpLogic.getPermissionList(loginId);
+    }
+
+    public static boolean hasPermission(String permission) {
+        return stpLogic.hasPermission(permission);
+    }
+
+    public static boolean hasPermission(Object loginId, String permission) {
+        return stpLogic.hasPermission(loginId, permission);
+    }
+
+    public static boolean hasPermissionAnd(String... permissionArray) {
+        return stpLogic.hasPermissionAnd(permissionArray);
+    }
+
+    public static boolean hasPermissionOr(String... permissionArray) {
+        return stpLogic.hasPermissionOr(permissionArray);
+    }
+
+    public static void checkPermission(String permission) {
+        stpLogic.checkPermission(permission);
+    }
+
+    public static void checkPermissionAnd(String... permissionArray) {
+        stpLogic.checkPermissionAnd(permissionArray);
+    }
+
+    public static void checkPermissionOr(String... permissionArray) {
+        stpLogic.checkPermissionOr(permissionArray);
+    }
+
+    public static String getTokenValueByLoginId(Object loginId) {
+        return stpLogic.getTokenValueByLoginId(loginId);
+    }
+
+    public static String getTokenValueByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueByLoginId(loginId, device);
+    }
+
+    public static List<String> getTokenValueListByLoginId(Object loginId) {
+        return stpLogic.getTokenValueListByLoginId(loginId);
+    }
+
+    public static List<String> getTokenValueListByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenValueListByLoginId(loginId, device);
+    }
+
+    public static List<TokenSign> getTokenSignListByLoginId(Object loginId, String device) {
+        return stpLogic.getTokenSignListByLoginId(loginId, device);
+    }
+
+    public static String getLoginDevice() {
+        return stpLogic.getLoginDevice();
+    }
+
+    public static List<String> searchTokenValue(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchTokenValue(keyword, start, size, sortType);
+    }
+
+    public static List<String> searchSessionId(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchSessionId(keyword, start, size, sortType);
+    }
+
+    public static List<String> searchTokenSessionId(String keyword, int start, int size, boolean sortType) {
+        return stpLogic.searchTokenSessionId(keyword, start, size, sortType);
+    }
+
+    public static void disable(Object loginId, long time) {
+        stpLogic.disable(loginId, time);
+    }
+
+    public static boolean isDisable(Object loginId) {
+        return stpLogic.isDisable(loginId);
+    }
+
+    public static void checkDisable(Object loginId) {
+        stpLogic.checkDisable(loginId);
+    }
+
+    public static long getDisableTime(Object loginId) {
+        return stpLogic.getDisableTime(loginId);
+    }
+
+    public static void untieDisable(Object loginId) {
+        stpLogic.untieDisable(loginId);
+    }
+
+    public static void disable(Object loginId, String service, long time) {
+        stpLogic.disable(loginId, service, time);
+    }
+
+    public static boolean isDisable(Object loginId, String service) {
+        return stpLogic.isDisable(loginId, service);
+    }
+
+    public static void checkDisable(Object loginId, String... services) {
+        stpLogic.checkDisable(loginId, services);
+    }
+
+    public static long getDisableTime(Object loginId, String service) {
+        return stpLogic.getDisableTime(loginId, service);
+    }
+
+    public static void untieDisable(Object loginId, String... services) {
+        stpLogic.untieDisable(loginId, services);
+    }
+
+    public static void disableLevel(Object loginId, int level, long time) {
+        stpLogic.disableLevel(loginId, level, time);
+    }
+
+    public static void disableLevel(Object loginId, String service, int level, long time) {
+        stpLogic.disableLevel(loginId, service, level, time);
+    }
+
+    public static boolean isDisableLevel(Object loginId, int level) {
+        return stpLogic.isDisableLevel(loginId, level);
+    }
+
+    public static boolean isDisableLevel(Object loginId, String service, int level) {
+        return stpLogic.isDisableLevel(loginId, service, level);
+    }
+
+    public static void checkDisableLevel(Object loginId, int level) {
+        stpLogic.checkDisableLevel(loginId, level);
+    }
+
+    public static void checkDisableLevel(Object loginId, String service, int level) {
+        stpLogic.checkDisableLevel(loginId, service, level);
+    }
+
+    public static int getDisableLevel(Object loginId) {
+        return stpLogic.getDisableLevel(loginId);
+    }
+
+    public static int getDisableLevel(Object loginId, String service) {
+        return stpLogic.getDisableLevel(loginId, service);
+    }
+
+    public static void switchTo(Object loginId) {
+        stpLogic.switchTo(loginId);
+    }
+
+    public static void endSwitch() {
+        stpLogic.endSwitch();
+    }
+
+    public static boolean isSwitch() {
+        return stpLogic.isSwitch();
+    }
+
+    public static void switchTo(Object loginId, SaFunction function) {
+        stpLogic.switchTo(loginId, function);
+    }
+
+    public static void openSafe(long safeTime) {
+        stpLogic.openSafe(safeTime);
+    }
+
+    public static void openSafe(String service, long safeTime) {
+        stpLogic.openSafe(service, safeTime);
+    }
+
+    public static boolean isSafe() {
+        return stpLogic.isSafe();
+    }
+
+    public static boolean isSafe(String service) {
+        return stpLogic.isSafe(service);
+    }
+
+    public static boolean isSafe(String tokenValue, String service) {
+        return stpLogic.isSafe(tokenValue, service);
+    }
+
+    public static void checkSafe() {
+        stpLogic.checkSafe();
+    }
+
+    public static void checkSafe(String service) {
+        stpLogic.checkSafe(service);
+    }
+
+    public static long getSafeTime() {
+        return stpLogic.getSafeTime();
+    }
+
+    public static long getSafeTime(String service) {
+        return stpLogic.getSafeTime(service);
+    }
+
+    public static void closeSafe() {
+        stpLogic.closeSafe();
+    }
+
+    public static void closeSafe(String service) {
+        stpLogic.closeSafe(service);
+    }
+}

+ 17 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/account/DeviceManager.java

@@ -0,0 +1,17 @@
+package com.genersoft.iot.vmp.vmanager.account;
+
+import com.genersoft.iot.vmp.conf.security.saToken.SaUserCheckRole;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.web.bind.annotation.CrossOrigin;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@Tag(name = "普通用户设备管理")
+@CrossOrigin(origins = "*")
+@RestController
+@RequestMapping("/account")
+@SaUserCheckRole("user")
+public class DeviceManager {
+    // 根据绑定码
+
+}

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/SseController/SseController.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.SseController;
 
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.event.alarm.AlarmEventListener;
 
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -20,6 +21,7 @@ import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
 @CrossOrigin
 @Controller
 @RequestMapping("/api")
+@SaAdminCheckRole("admin")
 public class SseController {
     @Autowired
     AlarmEventListener alarmEventListener;

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/aiLib/AiApi.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.aiLib;
 
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.storager.IAiControlStorage;
 import com.genersoft.iot.vmp.vmanager.bean.*;
 import com.genersoft.iot.vmp.vmanager.bean.AiAlarm;
@@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.*;
 @Tag(name = "ai数据接口")
 @RestController
 @RequestMapping("/ai")
+@SaAdminCheckRole("admin")
 public class AiApi {
     private final static Logger logger = LoggerFactory.getLogger(AiControl.class);
     @Autowired

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/aiLib/AiControl.java

@@ -3,6 +3,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.aiLib;
 import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONArray;
 import com.genersoft.iot.vmp.conf.SipConfig;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
 import com.genersoft.iot.vmp.vmanager.bean.*;
 import com.github.pagehelper.PageInfo;
@@ -29,6 +30,7 @@ import java.util.Objects;
 @CrossOrigin
 @RestController
 @RequestMapping("/aiLib")
+@SaAdminCheckRole("admin")
 public class AiControl {
     private final static Logger logger = LoggerFactory.getLogger(AiControl.class);
     @Autowired

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/alarm/AlarmController.java

@@ -1,6 +1,7 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.alarm;
 
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.DeviceAlarm;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
@@ -37,6 +38,7 @@ import java.util.List;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/alarm")
+@SaAdminCheckRole("admin")
 public class AlarmController {
 
     private final static Logger logger = LoggerFactory.getLogger(AlarmController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java

@@ -9,6 +9,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device;
 
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.AiConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
@@ -39,6 +40,7 @@ import java.util.UUID;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/device/config")
+@SaAdminCheckRole("admin")
 public class DeviceConfig {
 
     private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceControl.java

@@ -9,6 +9,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.device;
 
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
@@ -37,6 +38,7 @@ import java.util.UUID;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/device/control")
+@SaAdminCheckRole("admin")
 public class DeviceControl {
 
     private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class);

+ 6 - 2
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java

@@ -1,8 +1,11 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.device;
 
+import cn.dev33.satoken.annotation.SaCheckRole;
 import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckLogin;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.DeviceShare;
 import com.genersoft.iot.vmp.gb28181.bean.AiConfig;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -18,6 +21,7 @@ import com.genersoft.iot.vmp.service.IDeviceChannelService;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.storager.IRedisCatchStorage;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
 import com.genersoft.iot.vmp.vmanager.bean.AiLib;
 import com.genersoft.iot.vmp.vmanager.bean.BaseTree;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
@@ -54,6 +58,7 @@ import java.util.*;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/device/query")
+@SaAdminCheckRole("admin")
 public class DeviceQuery {
 
     private final static Logger logger = LoggerFactory.getLogger(DeviceQuery.class);
@@ -286,8 +291,7 @@ public class DeviceQuery {
                                     int count,
                                     @RequestParam(value = "online", defaultValue = "false", required = false) boolean online) {
 
-//		if (page == null) page = 0;
-//		if (count == null) count = 20;
+        logger.info("[设备查询] 查询所有设备 {}", 11);
         if (online) {
             return storager.queryVideoDeviceList(page, count, online);
         }

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/gbStream/GbStreamController.java

@@ -1,5 +1,6 @@
 package com.genersoft.iot.vmp.vmanager.gb28181.gbStream;
 
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.GbStream;
 import com.genersoft.iot.vmp.service.IGbStreamService;
 import com.genersoft.iot.vmp.storager.IVideoManagerStorage;
@@ -20,6 +21,7 @@ import java.util.List;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/gbStream")
+@SaAdminCheckRole("admin")
 public class GbStreamController {
 
     private final static Logger logger = LoggerFactory.getLogger(GbStreamController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/media/MediaController.java

@@ -4,6 +4,7 @@ import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.media.zlm.dto.StreamAuthorityInfo;
 import com.genersoft.iot.vmp.service.IStreamProxyService;
 import com.genersoft.iot.vmp.service.IMediaService;
@@ -26,6 +27,7 @@ import javax.servlet.http.HttpServletRequest;
 @Controller
 @CrossOrigin
 @RequestMapping(value = "/api/media")
+@SaAdminCheckRole("admin")
 public class MediaController {
 
     private final static Logger logger = LoggerFactory.getLogger(MediaController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/platform/PlatformController.java

@@ -6,6 +6,7 @@ import com.genersoft.iot.vmp.common.VideoManagerConstants;
 import com.genersoft.iot.vmp.conf.DynamicTask;
 import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.ParentPlatform;
 import com.genersoft.iot.vmp.gb28181.bean.PlatformCatalog;
 import com.genersoft.iot.vmp.gb28181.bean.SubscribeHolder;
@@ -40,6 +41,7 @@ import java.util.List;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/platform")
+@SaAdminCheckRole("admin")
 public class PlatformController {
 
     private final static Logger logger = LoggerFactory.getLogger(PlatformController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/play/PlayController.java

@@ -8,6 +8,7 @@ import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.*;
 import com.genersoft.iot.vmp.gb28181.bean.BroadcastItem;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
@@ -50,6 +51,7 @@ import java.util.*;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/play")
+@SaAdminCheckRole("admin")
 public class PlayController {
 
     private final static Logger logger = LoggerFactory.getLogger(PlayController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/playback/PlaybackController.java

@@ -5,6 +5,7 @@ import com.genersoft.iot.vmp.conf.UserSetting;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.exception.ServiceException;
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.DeferredResultHolder;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.media.zlm.ZLMRTPServerFactory;
@@ -43,6 +44,7 @@ import java.util.UUID;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/playback")
+@SaAdminCheckRole("admin")
 public class PlaybackController {
 
 	private final static Logger logger = LoggerFactory.getLogger(PlaybackController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/ptz/PtzController.java

@@ -2,6 +2,7 @@ package com.genersoft.iot.vmp.vmanager.gb28181.ptz;
 
  
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.DeviceShare;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.gb28181.bean.PresetQuerySipReq;
@@ -32,6 +33,7 @@ import java.util.UUID;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/ptz")
+@SaAdminCheckRole("admin")
 public class PtzController {
 
 	private final static Logger logger = LoggerFactory.getLogger(PtzController.class);

+ 2 - 0
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/record/GBRecordController.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson2.JSONObject;
 import com.genersoft.iot.vmp.common.StreamInfo;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.exception.SsrcTransactionNotFoundException;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.transmit.callback.RequestMessage;
 import com.genersoft.iot.vmp.service.IDeviceService;
 import com.genersoft.iot.vmp.service.IMediaServerService;
@@ -41,6 +42,7 @@ import java.util.UUID;
 @CrossOrigin
 @RestController
 @RequestMapping("/api/gb_record")
+@SaAdminCheckRole("admin")
 public class GBRecordController {
 
 	private final static Logger logger = LoggerFactory.getLogger(GBRecordController.class);

+ 22 - 29
src/main/java/com/genersoft/iot/vmp/vmanager/user/AccountController.java

@@ -1,10 +1,14 @@
 package com.genersoft.iot.vmp.vmanager.user;
 
+import cn.dev33.satoken.annotation.SaIgnore;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.conf.security.saToken.SaUserCheckRole;
 import com.genersoft.iot.vmp.gb28181.bean.Device;
 import com.genersoft.iot.vmp.service.IAccountService;
 import com.genersoft.iot.vmp.service.IDeviceService;
+import com.genersoft.iot.vmp.storager.dao.dto.UserAccount;
+import com.genersoft.iot.vmp.utils.StpUserUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import io.swagger.v3.oas.annotations.Operation;
@@ -19,6 +23,7 @@ import org.springframework.web.bind.annotation.*;
 @CrossOrigin(origins = "*")
 @RestController
 @RequestMapping("/account")
+@SaUserCheckRole("user")
 public class AccountController {
     private Logger logger = LoggerFactory.getLogger(AccountController.class);
 
@@ -29,39 +34,36 @@ public class AccountController {
     private IDeviceService deviceService;
 
     @PostMapping("/register")
+    @SaIgnore
     @Operation(summary = "注册用户")
     @Parameter(name = "name", description = "用户名", required = true)
     @Parameter(name = "account", description = "登陆账号", required = true)
     @Parameter(name = "password", description = "密码", required = true)
     public WVPResult<String> register(String name, String account, String password) {
         logger.info("register account: " + account + " password: " + password);
-        WVPResult wvpResult = new WVPResult();
-        if(accountService.checkAccount(account) != null)
-        {
-            wvpResult.setCode(ErrorCode.ERROR100.getCode());
-            wvpResult.setMsg("账号已存在");
-            return wvpResult;
+        if(accountService.checkAccount(account) != null) {
+            return WVPResult.fail(
+                    ErrorCode.ERROR100,
+                    "账号已存在");
         }
         accountService.registerAccount(name, account, password);
-        wvpResult.setCode(ErrorCode.SUCCESS.getCode());
-        wvpResult.setMsg("注册成功");
-        return wvpResult;
+        return WVPResult.success();
     }
 
     @PostMapping("/login")
+    @SaIgnore
     @Operation(summary = "登录")
     @Parameter(name = "account", description = "登陆账号", required = true)
     @Parameter(name = "password", description = "密码", required = true)
-    public WVPResult<String> login(String account, String password)
-    {
+    public WVPResult<String> login(String account, String password) {
         logger.info("[登录账号] account {}", account);
-        if (accountService.login(account, password) == null)
-        {
+        UserAccount userAccount = accountService.login(account, password);
+        if (userAccount == null) {
             return WVPResult.fail(
                     ErrorCode.ERROR404,
                     "账号或者密码错误");
         }
-//        SecurityUtils.login(username, password, authenticationManager);
+        StpUserUtil.login(userAccount.getId());
         return WVPResult.success(null, "ok");
     }
 
@@ -72,11 +74,7 @@ public class AccountController {
     {
         logger.info("[绑定设备] bind account ");
         WVPResult wvpResult = new WVPResult();
-        LoginUser loginUser = SecurityUtils.getUserInfo();
-        if(loginUser == null){
-            logger.warn("[绑定设备] 用户未登录");
-            return WVPResult.fail(ErrorCode.ERROR401);
-        }
+        String userId = StpUserUtil.getLoginId().toString();
         Device device = deviceService.getBindDevice(devCode);
         if(device == null){
             return WVPResult.fail(ErrorCode.ERROR404, "无法找到对应设备");
@@ -88,9 +86,9 @@ public class AccountController {
                     "设备已经绑定, 无法重新绑定");
         }
         accountService.bindDevice(
-                loginUser.getId(),
+                Integer.parseInt(userId),
                 device.getId(),
-                devCode );
+                devCode);
 
         return wvpResult;
     }
@@ -98,14 +96,9 @@ public class AccountController {
     @GetMapping("/unbind/device")
     @Operation(summary = "解绑设备")
     @Parameter(name = "deviceId", description = "设备id", required = true)
-    public WVPResult<String> unbindDevice( String deviceId)
-    {
-        LoginUser loginUser = SecurityUtils.getUserInfo();
-        if(loginUser == null){
-            logger.warn("[绑定设备] 用户未登录");
-            return WVPResult.fail(ErrorCode.ERROR401);
-        }
-        accountService.unBindDevice(loginUser.getId(), Integer.parseInt(deviceId));
+    public WVPResult<String> unbindDevice( String deviceId) {
+        String userId = StpUserUtil.getLoginId().toString();
+        accountService.unBindDevice(Integer.parseInt(userId), Integer.parseInt(deviceId));
         return WVPResult.success("ok");
     }
 

+ 13 - 15
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java

@@ -1,15 +1,19 @@
 package com.genersoft.iot.vmp.vmanager.user;
 
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.dev33.satoken.stp.StpUtil;
 import com.genersoft.iot.vmp.conf.exception.ControllerException;
 import com.genersoft.iot.vmp.conf.security.JwtUtils;
 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.conf.security.saToken.SaAdminCheckRole;
 import com.genersoft.iot.vmp.gb28181.transmit.event.request.impl.message.notify.cmd.KeepaliveNotifyMessageHandler;
 import com.genersoft.iot.vmp.service.IRoleService;
 import com.genersoft.iot.vmp.service.IUserService;
 import com.genersoft.iot.vmp.storager.dao.dto.Role;
 import com.genersoft.iot.vmp.storager.dao.dto.User;
 import com.genersoft.iot.vmp.utils.DateUtil;
+import com.genersoft.iot.vmp.utils.StpAdminUtil;
 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
 import com.genersoft.iot.vmp.vmanager.bean.WVPResult;
 import com.github.pagehelper.PageInfo;
@@ -32,6 +36,7 @@ import java.util.List;
 @Tag(name  = "用户管理")
 @CrossOrigin(origins = "*")
 @RestController
+@SaAdminCheckRole("admin")
 @RequestMapping("/api/user")
 public class UserController {
     private Logger logger = LoggerFactory.getLogger(UserController.class);
@@ -44,29 +49,22 @@ public class UserController {
     @Autowired
     private IRoleService roleService;
 
-//    @GetMapping("/login")
+    //    @GetMapping("/login")
     @PostMapping("/login")
+    @SaIgnore
     @Operation(summary = "登录", description = "登录成功后返回AccessToken, 可以从返回值获取到也可以从响应头中获取到," +
             "后续的请求需要添加请求头 'access-token'或者放在参数里")
 
     @Parameter(name = "username", description = "用户名", required = true)
     @Parameter(name = "password", description = "密码(32位md5加密)", required = true)
-    public LoginUser login(HttpServletRequest request, HttpServletResponse response, @RequestParam String username, @RequestParam String password){
-        LoginUser user;
-        try {
-            user = SecurityUtils.login(username, password, authenticationManager);
-            logger.info("[用户管理] - [登录] - [{} - {} -{}] - 登录成功", user.getId(), user.getUsername(), user.getRole().getId());
-        } catch (AuthenticationException e) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
-        }
+    public WVPResult login(HttpServletRequest request, HttpServletResponse response, @RequestParam String username, @RequestParam String password) {
+
+        User user = userService.getUser(username, password);
         if (user == null) {
-            throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
-        }else {
-            String jwt = JwtUtils.createToken(username, password);
-            response.setHeader(JwtUtils.getHeader(), jwt);
-            user.setAccessToken(jwt);
+            return WVPResult.fail(ErrorCode.ERROR100);
         }
-        return user;
+        StpAdminUtil.login(user.getId());
+        return WVPResult.success();
     }
 
 

+ 42 - 10
设备绑定机制.md

@@ -1,20 +1,38 @@
 # 合方圆国标平台绑定流程
 
 ## 设备上线绑定服务流程
+
 1. 设备上线平台
 2. 用户注册账号
 3. 用户输入鉴定码
 4. 用户绑定设备
 5. 用户查询自己设备
 
+### 设计要点
+
+#### 国标id冲突
+
+> [!tip] 可能会有多个不同设备使用相同的sip id, 导致用户管理到其他设备
+
+所以, 在用户应该只与绑定码进行关联, 不关心设备id
+
+#### 设备重复注册
+
+> [!tip] 设备可能在注册后,更改国标id重新注册, 导致多台设备使用同一个绑定码
+
+如果新设备绑定码与已有设备的绑定码有冲突, 则移除已有设备的绑定码,  
+确保一个绑定码永远只对应一个设备, 不对设备国标域进行区分.
+
 ### 平台角色管理
-1. 主管理员 唯一 平台的全部权限, 包括创建域名管理员
-2. 域主管理员 多个 管理对应sip域下的对应设备 是否对对应的域信息进行设备绑定
-3. 域子管理员 多个 管理对应账户下的设备
-4. 普通用户 多个 管理对应账户下的设备
+
+1. [admin] 主管理员 唯一 平台的全部权限, 包括创建域名管理员
+2. [sub-admin] 子理员 多个 管理对应sip域下的对应设备 是否对对应的域信息进行设备绑定
+4. [user] 普通用户 多个 管理对应账户下的设备
 
 #### 用户表数据库设计
+
 ##### 普通用户表 account
+
 | 字段        | 类型           | 值介绍   | 默认     | 备注      |
 |-----------|--------------|-------|--------|---------|
 | id        | int          | 主键    | 无      | 无       |
@@ -29,12 +47,11 @@
 |------------|--------------|------|----|------|
 | bindId     | int          | 主键   | 无  | 无    |
 | accountId  | int          | 用户id | 无  | 用户id |
-| devId      | int          | 设备id | 无  | 设备id |
 | devCode    | varchar(255) | 绑定码  | 无  | 绑定码  |
-| createTime | datetime     | 创建时间 | 无  | 创建时间 |
-
+| createTime | datetime     | 绑定时间 | 无  | 创建时间 |
 
 ##### 管理员表 user
+
 | 字段      | 类型           | 值介绍  | 默认     | 备注     |
 |---------|--------------|------|--------|--------|
 | id      | int          | 主键   | 无      | 无      |
@@ -43,14 +60,29 @@
 | passwd  | varchar(255) | 密码   | 无      | 用户密码摘要 |
 
 ##### 管理员sip配置表
-| 字段      | 类型           | 值介绍  | 默认     | 备注     |
-|---------|--------------|------|--------|--------|
-| id      | int          | 主键   | 无      | 无      |
 
+> 管理员sip配置表, 用于管理sip信息, 允许多种设备同步接入到平台
+> 可以指定域启用绑定设备, 用于设备上线时获取设备绑定码, 用于app端用户绑定设备
+> 不同域允许配置为黑名单, 白名单, 无限制 等形式对设备进行管理
+
+| 字段          | 类型           | 值介绍      | 默认 | 备注                  |
+|-------------|--------------|----------|----|---------------------|
+| id          | int          | 主键       | 无  | 无                   |
+| adminId     | int          | 管理员id    | 无  | 创建者id, 在注册时不发挥作用    |
+| sipDomain   | varchar(100) | sip域名    | 无  | sip域 唯一,根据域来获取对应的密码 |
+| serverId    | varchar(100) | 服务器id    | 无  | 服务器id               |
+| password    | varchar(100) | 服务器密码    | 无  | 密码                  |
+| description | varchar(255) | 描述       | 无  | 描述                  |
+| enable      | char(1)      | 是否启用     | 1  | 只有启用的情况下才会被允许注册     |
+| createTime  | datetime     | 创建时间     | 无  | 创建时间                |
+| enableBind  | char(1)      | 是否启用设备绑定 | 1  | 是否启用设备绑定 1 允许 0 不允许 |
 
 #### 设备表扩展
+
 > 使用字段 `devCode` 设备注册时获取
+
 ### 设备上线平台
+
 1. 设备发送连接请求
 2. 平台根据域将设备分配至不同的管理账户下
 3. 对应域的管理员账户能够看自己域下方的设备