648540858
2023-03-15 5fab97cf7e49636d446e063ee6e0eea80c124bd2
支持不同域的前后端分离部署
22个文件已修改
1个文件已添加
381 ■■■■■ 已修改文件
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java 99 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/all-application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/package-lock.json 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/App.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/Login.vue 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/changePassword.vue 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/dialog/importChannel.vue 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/components/service/UserService.js 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/layout/UiHeader.vue 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
web_src/src/main.js 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/genersoft/iot/vmp/conf/ApiAccessFilter.java
@@ -14,7 +14,8 @@
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.*;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -48,13 +49,6 @@
        long start = System.currentTimeMillis(); // 请求进入时间
        String uriName = ApiSaveConstant.getVal(servletRequest.getRequestURI());
        String origin = servletRequest.getHeader("Origin");
        servletResponse.setContentType("application/json;charset=UTF-8");
        servletResponse.setHeader("Access-Control-Allow-Origin", origin != null ? origin : "*");
        servletResponse.setHeader("Access-Control-Allow-Credentials", "true");
        servletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        servletResponse.setHeader("Access-Control-Max-Age", "3600");
        servletResponse.setHeader("Access-Control-Allow-Headers", "token,Content-Type,Content-Length, Authorization, Accept,X-Requested-With,domain,zdy");
        filterChain.doFilter(servletRequest, servletResponse);
        if (uriName != null && userSetting != null && userSetting.getLogInDatebase() != null && userSetting.getLogInDatebase()) {
src/main/java/com/genersoft/iot/vmp/conf/GlobalExceptionHandler.java
@@ -32,6 +32,17 @@
        return WVPResult.fail(ErrorCode.ERROR500.getCode(), e.getMessage());
    }
    /**
     * 默认异常处理
     * @param e 异常
     * @return 统一返回结果
     */
    @ExceptionHandler(IllegalStateException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public WVPResult<String> exceptionHandler(IllegalStateException e) {
        return WVPResult.fail(ErrorCode.ERROR400);
    }
    /**
     * 自定义异常处理, 处理controller中返回的错误
src/main/java/com/genersoft/iot/vmp/conf/UserSetting.java
@@ -55,6 +55,8 @@
    private List<String> interfaceAuthenticationExcludes = new ArrayList<>();
    private List<String> allowedOrigins = new ArrayList<>();
    public Boolean getSavePositionHistory() {
        return savePositionHistory;
    }
@@ -218,4 +220,12 @@
    public void setSipLog(Boolean sipLog) {
        this.sipLog = sipLog;
    }
    public List<String> getAllowedOrigins() {
        return allowedOrigins;
    }
    public void setAllowedOrigins(List<String> allowedOrigins) {
        this.allowedOrigins = allowedOrigins;
    }
}
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
@@ -28,15 +28,6 @@
        String username = jwtUser.getUserName();
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword() );
        SecurityContextHolder.getContext().setAuthentication(token);
        System.out.println(jwt);
        // 允许跨域
        String origin = request.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Origin", origin != null ? origin : "*");
        response.setHeader("Access-Control-Allow-Methods", "PUT,POST,    GET,DELETE,OPTIONS");
        // 允许自定义请求头token(允许head跨域)
        response.setHeader("Access-Control-Allow-Headers", "token, Accept, Origin, X-Requested-With, Content-Type, Last-Modified");
        response.setHeader("Content-type", "application/json;charset=UTF-8");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", ErrorCode.ERROR401.getCode());
        jsonObject.put("msg", ErrorCode.ERROR401.getMsg());
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
@@ -24,14 +24,23 @@
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 忽略登录请求的token验证
        String requestURI = request.getRequestURI();
        if (requestURI.equalsIgnoreCase("/api/user/login")) {
            chain.doFilter(request, response);
            return;
        }
        String jwt = request.getHeader(JwtUtils.getHeader());
        // 这里如果没有jwt,继续往后走,因为后面还有鉴权管理器等去判断是否拥有身份凭证,所以是可以放行的
        // 没有jwt相当于匿名访问,若有一些接口是需要权限的,则不能访问这些接口
        if (StringUtils.isBlank(jwt)) {
            chain.doFilter(request, response);
            return;
            jwt = request.getParameter(JwtUtils.getHeader());
            if (StringUtils.isBlank(jwt)) {
                chain.doFilter(request, response);
                return;
            }
        }
        JwtUser jwtUser = JwtUtils.verifyToken(jwt);
        String username = jwtUser.getUserName();
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
@@ -23,7 +23,7 @@
    private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
    private static final String HEADER = "Access-Token";
    private static final String HEADER = "access-token";
    private static final String AUDIENCE = "Audience";
    private static final long EXPIRED_THRESHOLD = 10 * 60;
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
@@ -27,16 +27,13 @@
    public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException {
        //使用security框架自带的验证token生成器  也可以自定义。
        UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password);
//        Authentication authenticate = authenticationManager.authenticate(token);
//        SecurityContextHolder.getContext().setAuthentication(authenticate);
        //认证 如果失败,这里会自动异常后返回,所以这里不需要判断返回值是否为空,确定是否登录成功
        Authentication authenticate = authenticationManager.authenticate(token);
        LoginUser user = (LoginUser) authenticate.getPrincipal();
        SecurityContextHolder.getContext().setAuthentication(token);
//        LoginUser user = (LoginUser) authenticate.getPrincipal();
        User user = new User();
        user.setUsername(username);
        LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
        return loginUser;
        return user;
    }
    /**
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -18,8 +18,13 @@
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
/**
 * 配置Spring Security
@@ -61,12 +66,6 @@
    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
//    @Bean
//    JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
//        JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
//        return jwtAuthenticationFilter;
//    }
    /**
     * 描述: 静态资源放行,这里的放行,是不走 Spring Security 过滤器链
@@ -77,27 +76,19 @@
        if (!userSetting.isInterfaceAuthentication()) {
            web.ignoring().antMatchers("**");
        }else {
            ArrayList<String> matchers = new ArrayList<>();
            matchers.add("/");
            matchers.add("/#/**");
            matchers.add("/static/**");
            matchers.add("/index.html");
            matchers.add("/doc.html");
            matchers.add("/webjars/**");
            matchers.add("/swagger-resources/**");
            matchers.add("/v3/api-docs/**");
            matchers.add("/js/**");
            matchers.addAll(userSetting.getInterfaceAuthenticationExcludes());
            // 可以直接访问的静态数据
            web.ignoring()
                    .antMatchers("/")
                    .antMatchers("/#/**")
                    .antMatchers("/static/**")
                    .antMatchers("/index.html")
                    .antMatchers("/doc.html") // "/webjars/**", "/swagger-resources/**", "/v3/api-docs/**"
                    .antMatchers("/webjars/**")
                    .antMatchers("/swagger-resources/**")
                    .antMatchers("/v3/api-docs/**")
                    .antMatchers("/favicon.ico")
                    .antMatchers("/js/**");
            List<String> interfaceAuthenticationExcludes = userSetting.getInterfaceAuthenticationExcludes();
            for (String interfaceAuthenticationExclude : interfaceAuthenticationExcludes) {
                if (interfaceAuthenticationExclude.split("/").length < 4 ) {
                    logger.warn("{}不满足两级目录,已忽略", interfaceAuthenticationExclude);
                }else {
                    web.ignoring().antMatchers(interfaceAuthenticationExclude);
                }
            }
            web.ignoring().antMatchers(matchers.toArray(new String[0]));
        }
    }
@@ -121,7 +112,7 @@
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().contentTypeOptions().disable()
                .and().cors()
                .and().cors().configurationSource(configurationSource())
                .and().csrf().disable()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
@@ -129,50 +120,36 @@
                // 配置拦截规则
                .and()
                .authorizeRequests()
                .requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .antMatchers(userSetting.getInterfaceAuthenticationExcludes().toArray(new String[0])).permitAll()
                .antMatchers("/api/user/login","/index/hook/**").permitAll()
                .anyRequest().authenticated()
                // 异常处理器
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
//                .accessDeniedHandler(jwtAccessDeniedHandler)
                // 配置自定义的过滤器
//                .and()
//                .addFilter(jwtAuthenticationFilter)
                // 验证码过滤器放在UsernamePassword过滤器之前
//                .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
                .and().logout().logoutUrl("/api/user/logout").permitAll()
                .logoutSuccessHandler(logoutHandler)
        ;
        http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
//        // 设置允许添加静态文件
//        http.headers().contentTypeOptions().disable();
//        http.authorizeRequests()
//                // 放行接口
//                .antMatchers("/api/user/login","/index/hook/**").permitAll()
//                // 除上面外的所有请求全部需要鉴权认证
//                .anyRequest().authenticated()
//                // 禁用session
//                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
//                // 异常处理(权限拒绝、登录失效等)
//                .and().exceptionHandling()
//                // 匿名用户访问无权限资源时的异常处理
//                .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
//                // 登录 允许所有用户
//                .and().formLogin()
//                // 登录成功处理逻辑 在这里给出JWT
//                .successHandler(loginSuccessHandler)
//                // 登录失败处理逻辑
//                .failureHandler(loginFailureHandler)
//                // 登出
//                .and().logout().logoutUrl("/api/user/logout").permitAll()
//                // 登出成功处理逻辑
//                .logoutSuccessHandler(logoutHandler)
//                // 配置自定义的过滤器
//                .and()
//                .addFilter(jwtAuthenticationFilter())
//        ;
    }
    CorsConfigurationSource configurationSource(){
        // 配置跨域
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedOrigins(userSetting.getAllowedOrigins());
        corsConfiguration.setExposedHeaders(Arrays.asList(JwtUtils.getHeader()));
        UrlBasedCorsConfigurationSource url = new UrlBasedCorsConfigurationSource();
        url.registerCorsConfiguration("/**",corsConfiguration);
        return url;
    }
    /**
     * 描述: 密码加密算法 BCrypt 推荐使用
     **/
src/main/java/com/genersoft/iot/vmp/vmanager/bean/WVPResult.java
@@ -28,6 +28,10 @@
        return new WVPResult<>(ErrorCode.SUCCESS.getCode(), msg, t);
    }
    public static WVPResult success() {
        return new WVPResult<>(ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg(), null);
    }
    public static <T> WVPResult<T> success(T t) {
        return success(t, ErrorCode.SUCCESS.getMsg());
    }
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceConfig.java
@@ -31,7 +31,6 @@
import java.util.UUID;
@Tag(name = "国标设备配置")
@RestController
@RequestMapping("/api/device/config")
public class DeviceConfig {
src/main/java/com/genersoft/iot/vmp/vmanager/gb28181/device/DeviceQuery.java
@@ -24,6 +24,7 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.ibatis.annotations.Options;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -97,8 +98,10 @@
    @Parameter(name = "page", description = "当前页", required = true)
    @Parameter(name = "count", description = "每页查询数量", required = true)
    @GetMapping("/devices")
    @Options()
    public PageInfo<Device> devices(int page, int count){
//        if (page == null) page = 0;
//        if (count == null) count = 20;
        return storager.queryVideoDeviceList(page, count,null);
    }
src/main/java/com/genersoft/iot/vmp/vmanager/server/ServerController.java
@@ -23,7 +23,6 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
@@ -69,9 +68,6 @@
    @Value("${server.port}")
    private int serverPort;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;
    @Autowired
    private IRedisCatchStorage redisCatchStorage;
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -27,7 +27,6 @@
import java.util.List;
@Tag(name  = "用户管理")
@RestController
@RequestMapping("/api/user")
public class UserController {
@@ -47,7 +46,7 @@
    @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 = null;
        LoginUser user;
        try {
            user = SecurityUtils.login(username, password, authenticationManager);
        } catch (AuthenticationException e) {
@@ -62,6 +61,25 @@
        return user;
    }
//    @GetMapping("/logout")
//    @PostMapping("/logout")
//    @Operation(summary = "登出")
//    public LoginUser logout(){
//        LoginUser user;
//        try {
//            user = SecurityUtils.login(username, password, authenticationManager);
//        } catch (AuthenticationException e) {
//            throw new ControllerException(ErrorCode.ERROR100.getCode(), e.getMessage());
//        }
//        if (user == null) {
//            throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
//        }else {
//            String jwt = JwtUtils.createToken(username, password);
//            response.setHeader(JwtUtils.getHeader(), jwt);
//        }
//        return user;
//    }
    @PostMapping("/changePassword")
    @Operation(summary = "修改密码")
    @Parameter(name = "username", description = "用户名", required = true)
src/main/resources/all-application.yml
@@ -201,6 +201,10 @@
    sip-log: true
    # 自动数据库升级,保证表结构完整
    sync-db: true
    # 跨域配置,配置你访问前端页面的地址即可, 可以配置多个
    allowed-origins:
        - http://localhost:8008
        - http://192.168.1.3:8008
# 关闭在线文档(生产环境建议关闭)
springdoc:
web_src/package-lock.json
@@ -23,7 +23,7 @@
        "vue-clipboard2": "^0.3.1",
        "vue-clipboards": "^1.3.0",
        "vue-contextmenujs": "^1.3.13",
        "vue-cookies": "^1.7.4",
        "vue-cookies": "^1.8.3",
        "vue-giant-tree": "^0.1.5",
        "vue-router": "^3.1.6",
        "vue-ztree-2.0": "^1.0.4"
@@ -13135,9 +13135,9 @@
      "integrity": "sha1-O9rgI8e9QgleeNpCWAACUNUKuO8="
    },
    "node_modules/vue-cookies": {
      "version": "1.7.4",
      "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",
      "integrity": "sha1-0kHQoEMdoHlYN2UdELTXPnyNPo0="
      "version": "1.8.3",
      "resolved": "https://registry.npmmirror.com/vue-cookies/-/vue-cookies-1.8.3.tgz",
      "integrity": "sha512-VBRsyRMVdahBgFfh389TMHPmDdr4URDJNMk4FKSCfuNITs7+jitBDhwyL4RJd3WUsfOYNNjPAkfbehyH9AFuoA=="
    },
    "node_modules/vue-giant-tree": {
      "version": "0.1.5",
@@ -25489,9 +25489,9 @@
      "integrity": "sha1-O9rgI8e9QgleeNpCWAACUNUKuO8="
    },
    "vue-cookies": {
      "version": "1.7.4",
      "resolved": "https://registry.npm.taobao.org/vue-cookies/download/vue-cookies-1.7.4.tgz?cache=0&sync_timestamp=1598941352058&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fvue-cookies%2Fdownload%2Fvue-cookies-1.7.4.tgz",
      "integrity": "sha1-0kHQoEMdoHlYN2UdELTXPnyNPo0="
      "version": "1.8.3",
      "resolved": "https://registry.npmmirror.com/vue-cookies/-/vue-cookies-1.8.3.tgz",
      "integrity": "sha512-VBRsyRMVdahBgFfh389TMHPmDdr4URDJNMk4FKSCfuNITs7+jitBDhwyL4RJd3WUsfOYNNjPAkfbehyH9AFuoA=="
    },
    "vue-giant-tree": {
      "version": "0.1.5",
web_src/package.json
@@ -25,7 +25,7 @@
    "vue-clipboard2": "^0.3.1",
    "vue-clipboards": "^1.3.0",
    "vue-contextmenujs": "^1.3.13",
    "vue-cookies": "^1.7.4",
    "vue-cookies": "^1.8.3",
    "vue-giant-tree": "^0.1.5",
    "vue-router": "^3.1.6",
    "vue-ztree-2.0": "^1.0.4"
web_src/src/App.vue
@@ -5,6 +5,7 @@
</template>
<script>
import  userService from './components/service/UserService'
export default {
  name: 'app',
  data(){
@@ -19,7 +20,7 @@
    }
  },
  created() {
    if(!this.$cookies.get("session")){
    if (userService.getToken() == null){
      //如果没有登录状态则跳转到登录页
      this.$router.push('/login');
    }
@@ -33,28 +34,14 @@
    // this.getUserInfo();
  },
  methods: {
    //请求用户的一些信息
    getUserInfo(){
      var userinfo = this.$cookies.get("session");
    },
    checkLogin(){
      //检查是否存在session
      //cookie操作方法在源码里有或者参考网上的即可
      if(!this.$cookies.get("session")){
      if (userService.getToken() == null){
        //如果没有登录状态则跳转到登录页
        this.$router.push('/login');
        // this.$router.push('/login');
      }
    },
    getCookie: function (cname) {
      var name = cname + "=";
      var ca = document.cookie.split(';');
      for (var i = 0; i < ca.length; i++) {
        var c = ca[i];
        while (c.charAt(0) == ' ') c = c.substring(1);
        if (c.indexOf(name) != -1) return c.substring(name.length, c.length);
      }
      return "";
    }
  },
  components: {}
};
web_src/src/components/Login.vue
@@ -35,6 +35,7 @@
<script>
import crypto from 'crypto'
import userService from "./service/UserService";
export default {
  name: 'Login',
  data(){
@@ -85,9 +86,10 @@
        params: loginParam
      }).then(function (res) {
        window.clearTimeout(timeoutTask)
        console.log(JSON.stringify(res));
        console.log(res);
        console.log("登录成功");
          if (res.data.code === 0 ) {
            that.$cookies.set("session", {"username": that.username,"roleId":res.data.data.role.id}) ;
            userService.setUser(res.data.data)
            //登录成功后
            that.cancelEnterkeyDefaultAction();
            that.$router.push('/');
@@ -105,14 +107,6 @@
        that.$message.error(error.response.data.msg);
        that.isLoging = false;
      });
    },
    setCookie: function (cname, cvalue, exdays) {
      var d = new Date();
      d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
      var expires = "expires=" + d.toUTCString();
      console.info(cname + "=" + cvalue + "; " + expires);
      document.cookie = cname + "=" + cvalue + "; " + expires;
      console.info(document.cookie);
    },
    cancelEnterkeyDefaultAction: function() {
        document.onkeydown = function(e) {
web_src/src/components/dialog/changePassword.vue
@@ -35,6 +35,7 @@
<script>
import crypto from 'crypto'
import userService from "../service/UserService";
export default {
  name: "changePassword",
  props: {},
@@ -105,7 +106,7 @@
          this.showDialog = false;
          setTimeout(()=>{
            // 删除cookie,回到登录页面
            this.$cookies.remove("session");
            userService.clearUserInfo();
            this.$router.push('/login');
            this.sseSource.close();
          },800)
web_src/src/components/dialog/importChannel.vue
@@ -16,6 +16,7 @@
          drag
          :action="uploadUrl"
          name="file"
          :headers="headers"
          :on-success="successHook"
          :on-error="errorHook"
          >
@@ -33,6 +34,8 @@
import ShowErrorData from './importChannelShowErrorData.vue'
import userService from "../service/UserService";
export default {
  name: "importChannel",
  components: {
@@ -47,7 +50,10 @@
      isEdit: false,
      errorStreams: [],
      errorGBIds: [],
      uploadUrl: process.env.NODE_ENV === 'development'?`debug/api/push/upload`:`api/push/upload`,
      headers: {
        "access-token": userService.getToken()
      },
      uploadUrl: process.env.NODE_ENV === 'development'? `http://127.0.0.1:8080/debug/api/push/upload`: (window.baseUrl ? window.baseUrl : "") + `/api/push/upload`,
    };
  },
  methods: {
web_src/src/components/service/UserService.js
New file
@@ -0,0 +1,42 @@
export default {
  /**
   * 存储用户信息
   * @param username
   * @param token
   */
  setUser(user){
    localStorage.setItem("wvp-user", JSON.stringify(user));
  },
  /**
   * 获取用户
   */
  getUser(){
    return JSON.parse(localStorage.getItem("wvp-user"));
  },
  /**
   * 获取登录token
   */
  getToken(){
    return localStorage.getItem("wvp-token");
  },
  /**
   * 清理用户信息
   */
  clearUserInfo(){
    localStorage.removeItem("wvp-user");
    localStorage.removeItem("wvp-token");
  },
  /**
   * 更新token
   * @param header
   */
  setToken(token) {
    localStorage.setItem("wvp-token", token);
  }
}
web_src/src/layout/UiHeader.vue
@@ -23,9 +23,9 @@
      <!--            </el-submenu>-->
      <!--            <el-menu-item style="float: right;" @click="loginout">退出</el-menu-item>-->
      <el-submenu index="" style="float: right;">
        <template slot="title">欢迎,{{ this.$cookies.get("session").username }}</template>
        <template slot="title">欢迎,{{ username }}</template>
        <el-menu-item @click="openDoc">在线文档</el-menu-item>
        <el-menu-item >
        <el-menu-item>
          <el-switch v-model="alarmNotify" inactive-text="报警信息推送" @change="alarmNotifyChannge"></el-switch>
        </el-menu-item>
        <el-menu-item @click="changePassword">修改密码</el-menu-item>
@@ -39,6 +39,7 @@
<script>
import changePasswordDialog from '../components/dialog/changePassword.vue'
import userService from '../components/service/UserService'
export default {
  name: "UiHeader",
@@ -47,14 +48,17 @@
    return {
      alarmNotify: false,
      sseSource: null,
      username: userService.getUser().username,
      activeIndex: this.$route.path,
      editUser: this.$cookies.get("session").roleId==1
      editUser: userService.getUser() ? userService.getUser().role.id === 1 : false
    };
  },
  created() {
    console.log(this.$cookies.get("session"))
    console.log(4444)
    console.log(JSON.stringify(userService.getUser()))
    if (this.$route.path.startsWith("/channelList")) {
      this.activeIndex = "/deviceList"
    }
  },
  mounted() {
@@ -69,10 +73,13 @@
        method: 'get',
        url: "/api/user/logout"
      }).then((res) => {
        // 删除cookie,回到登录页面
        this.$cookies.remove("session");
        // 删除用户信息,回到登录页面
        userService.clearUserInfo()
        this.$router.push('/login');
        this.sseSource.close();
        if (this.sseSource != null) {
          this.sseSource.close();
        }
      }).catch((error) => {
        console.error("登出失败")
        console.error(error)
@@ -151,16 +158,19 @@
</script>
<style>
#UiHeader .el-switch__label {
  color: white ;
  color: white;
}
.el-menu--popup .el-menu-item .el-switch .el-switch__label {
  color: white !important;
}
#UiHeader .el-switch__label.is-active{
#UiHeader .el-switch__label.is-active {
  color: #409EFF;
}
#UiHeader .el-menu-item.is-active {
  color: #fff!important;
  background-color: #1890ff!important;
  color: #fff !important;
  background-color: #1890ff !important;
}
</style>
web_src/src/main.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import App from './App.vue';
Vue.config.productionTip = false;
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
@@ -10,15 +11,16 @@
import VCharts from 'v-charts';
import VueClipboard from 'vue-clipboard2';
import { Notification } from 'element-ui';
import {Notification} from 'element-ui';
import Fingerprint2 from 'fingerprintjs2';
import VueClipboards from 'vue-clipboards';
import Contextmenu from "vue-contextmenujs"
import userService from "./components/service/UserService"
// 生成唯一ID
Fingerprint2.get(function(components) {
  const values = components.map(function(component,index) {
Fingerprint2.get(function (components) {
  const values = components.map(function (component, index) {
    if (index === 0) { //把微信浏览器里UA的wifi或4G等网络替换成空,不然切换网络会ID不一样
      return component.value.replace(/\bNetType\/\w+\b/, '');
    }
@@ -42,13 +44,17 @@
Vue.use(Contextmenu);
Vue.use(VCharts);
axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : (window.baseUrl?window.baseUrl:"");
axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : (window.baseUrl ? window.baseUrl : "");
axios.defaults.withCredentials = true;
// api 返回401自动回登陆页面
axios.interceptors.response.use(function (response) {
axios.interceptors.response.use((response) => {
  // 对响应数据做点什么
  let token = response.headers["access-token"];
  if (token) {
    userService.setToken(token)
  }
  return response;
}, function (error) {
}, (error) => {
  // 对响应错误做点什么
  if (error.response.status === 401) {
    console.log("Received 401 Response")
@@ -56,10 +62,22 @@
  }
  return Promise.reject(error);
});
axios.interceptors.request.use(
  config => {
    if (userService.getToken() != null && config.url !== "/api/user/login") {
      config.headers['access-token'] = `${userService.getToken()}`;
    }
    return config;
  },
  error => {
    return Promise.reject(error);
  }
);
Vue.prototype.$axios = axios;
Vue.prototype.$cookies.config(60*30);
new Vue({
    router: router,
    render: h => h(App),
  router: router,
  render: h => h(App),
}).$mount('#app')