From cb5849d8a14f55241c44bdf6724b18de7950564d Mon Sep 17 00:00:00 2001
From: panlinlin <648540858@qq.com>
Date: 星期三, 14 四月 2021 16:33:10 +0800
Subject: [PATCH] 支持接口鉴权,支持修改密码,

---
 web_src/src/components/DeviceList.vue                                                    |    4 
 web_src/config/index.js                                                                  |    3 
 src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java |   41 +++
 src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java               |   65 +++++
 web_src/src/components/dialog/changePassword.vue                                         |  107 ++++++++
 src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java     |   52 ++++
 src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java                    |    5 
 src/main/java/com/genersoft/iot/vmp/service/IUserService.java                            |    2 
 pom.xml                                                                                  |    4 
 web_src/src/components/Login.vue                                                         |    4 
 web_src/src/main.js                                                                      |   12 
 src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java               |   24 +
 src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java                 |  144 +++++++++++
 src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java             |   24 +
 src/main/java/com/genersoft/iot/vmp/conf/security/LogoutHandler.java                     |   27 ++
 src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java                     |   80 ++++++
 src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java                         |    3 
 src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java                    |   42 ++
 web_src/src/components/UiHeader.vue                                                      |   30 ++
 src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java                     |   95 +++++++
 20 files changed, 752 insertions(+), 16 deletions(-)

diff --git a/pom.xml b/pom.xml
index c07f7ad..c1383e7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,10 @@
 			<artifactId>mybatis-spring-boot-starter</artifactId>
 			<version>2.1.4</version>
 		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-security</artifactId>
+		</dependency>
 
 		<!-- druid鏁版嵁搴撹繛鎺ユ睜 -->
 		<dependency>
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
new file mode 100644
index 0000000..2064470
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
@@ -0,0 +1,41 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.alibaba.fastjson.JSONObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 澶勭悊鍖垮悕鐢ㄦ埛璁块棶閫昏緫
+ */
+@Component
+public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
+
+    private final static Logger logger = LoggerFactory.getLogger(DefaultUserDetailsServiceImpl.class);
+
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
+        logger.debug("鐢ㄦ埛闇�瑕佺櫥褰曪紝璁块棶[{}]澶辫触锛孉uthenticationException=[{}]", request.getRequestURI(), e.getMessage());
+        // 鍏佽璺ㄥ煙
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        // 鍏佽鑷畾涔夎姹傚ご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("msg", e.getMessage());
+        jsonObject.put("code", "-1");
+        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        try {
+            response.getWriter().print(jsonObject.toJSONString());
+        } catch (IOException ioException) {
+            ioException.printStackTrace();
+        }
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
new file mode 100644
index 0000000..c010335
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
@@ -0,0 +1,52 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.service.IUserService;
+import com.genersoft.iot.vmp.storager.dao.dto.User;
+import com.github.xiaoymin.knife4j.core.util.StrUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.CredentialsContainer;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.SpringSecurityCoreVersion;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+
+/**
+ * 鐢ㄦ埛鐧诲綍璁よ瘉閫昏緫
+ */
+@Component
+public class DefaultUserDetailsServiceImpl implements UserDetailsService {
+
+    private final static Logger logger = LoggerFactory.getLogger(DefaultUserDetailsServiceImpl.class);
+
+    @Autowired
+    private IUserService userService;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+        if (StrUtil.isBlank(username)) {
+            logger.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�", username);
+            throw new UsernameNotFoundException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
+        }
+
+        // 鏌ュ嚭瀵嗙爜
+        User user = userService.getUserByUsername(username);
+        String password = SecurityUtils.encryptPassword(user.getPassword());
+        user.setPassword(password);
+        if (user == null) {
+            logger.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�", username);
+            throw new UsernameNotFoundException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
+        }
+        return new LoginUser(user, LocalDateTime.now());
+    }
+
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
new file mode 100644
index 0000000..f3fd068
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.web.session.InvalidSessionStrategy;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 鐧诲綍瓒呮椂鐨勫鐞�
+ */
+public class InvalidSessionHandler implements InvalidSessionStrategy {
+
+    private final static Logger logger = LoggerFactory.getLogger(InvalidSessionHandler.class);
+
+    @Override
+    public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException, ServletException {
+        String username = request.getParameter("username");
+        logger.info("[鐧诲綍瓒呮椂] - [{}]", username);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java
new file mode 100644
index 0000000..1ad05c0
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java
@@ -0,0 +1,65 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.*;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class LoginFailureHandler implements AuthenticationFailureHandler {
+
+    private final static Logger logger = LoggerFactory.getLogger(LoginFailureHandler.class);
+
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Override
+    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
+
+        String username = request.getParameter("username");
+        if (e instanceof AccountExpiredException) {
+            // 璐﹀彿杩囨湡
+            logger.info("[鐧诲綍澶辫触] - 鐢ㄦ埛[{}]璐﹀彿杩囨湡", username);
+
+        } else if (e instanceof BadCredentialsException) {
+            // 瀵嗙爜閿欒
+            logger.info("[鐧诲綍澶辫触] - 鐢ㄦ埛[{}]瀵嗙爜閿欒", username);
+
+        } else if (e instanceof CredentialsExpiredException) {
+            // 瀵嗙爜杩囨湡
+            logger.info("[鐧诲綍澶辫触] - 鐢ㄦ埛[{}]瀵嗙爜杩囨湡", username);
+
+        } else if (e instanceof DisabledException) {
+            // 鐢ㄦ埛琚鐢�
+            logger.info("[鐧诲綍澶辫触] - 鐢ㄦ埛[{}]琚鐢�", username);
+
+        } else if (e instanceof LockedException) {
+            // 鐢ㄦ埛琚攣瀹�
+            logger.info("[鐧诲綍澶辫触] - 鐢ㄦ埛[{}]琚攣瀹�", username);
+
+        } else if (e instanceof InternalAuthenticationServiceException) {
+            // 鍐呴儴閿欒
+            logger.error(String.format("[鐧诲綍澶辫触] - [%s]鍐呴儴閿欒", username), e);
+
+        } else {
+            // 鍏朵粬閿欒
+            logger.error(String.format("[鐧诲綍澶辫触] - [%s]鍏朵粬閿欒", username), e);
+        }
+        Map<String, Object> map = new HashMap<>();
+        map.put("code","0");
+        map.put("msg","鐧诲綍澶辫触");
+        response.setContentType("application/json;charset=UTF-8");
+        response.getWriter().write(objectMapper.writeValueAsString(map));
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
new file mode 100644
index 0000000..9690c6d
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
@@ -0,0 +1,24 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@Component
+public class LoginSuccessHandler implements AuthenticationSuccessHandler {
+
+    private final static Logger logger = LoggerFactory.getLogger(LoginSuccessHandler.class);
+
+    @Override
+    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
+        String username = request.getParameter("username");
+        logger.info("[鐧诲綍鎴愬姛] - [{}]", username);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/LogoutHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/LogoutHandler.java
new file mode 100644
index 0000000..790eab8
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/LogoutHandler.java
@@ -0,0 +1,27 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import org.springframework.stereotype.Component;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * 閫�鍑虹櫥褰曟垚鍔�
+ */
+@Component
+public class LogoutHandler implements LogoutSuccessHandler {
+
+    private final static Logger logger = LoggerFactory.getLogger(LogoutHandler.class);
+
+    @Override
+    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
+        String username = request.getParameter("username");
+        logger.info("[閫�鍑虹櫥褰曟垚鍔焆 - [{}]", username);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java b/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
new file mode 100644
index 0000000..d186d84
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
@@ -0,0 +1,80 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.storager.dao.dto.User;
+import gov.nist.javax.sip.address.UserInfo;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+import javax.security.sasl.AuthenticationException;
+
+public class SecurityUtils {
+
+    /**
+     * 鎻忚堪鏍规嵁璐﹀彿瀵嗙爜杩涜璋冪敤security杩涜璁よ瘉鎺堟潈 涓诲姩璋�
+     * 鐢ˋuthenticationManager鐨刟uthenticate鏂规硶瀹炵幇
+     * 鎺堟潈鎴愬姛鍚庡皢鐢ㄦ埛淇℃伅瀛樺叆SecurityContext褰撲腑
+     * @param username 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @param authenticationManager 璁よ瘉鎺堟潈绠$悊鍣�,
+     * @see  AuthenticationManager
+     * @return UserInfo  鐢ㄦ埛淇℃伅
+     */
+    public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException {
+        //浣跨敤security妗嗘灦鑷甫鐨勯獙璇乼oken鐢熸垚鍣�  涔熷彲浠ヨ嚜瀹氫箟銆�
+        UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password);
+        Authentication authenticate = authenticationManager.authenticate(token);
+        SecurityContextHolder.getContext().setAuthentication(authenticate);
+        LoginUser user = (LoginUser) authenticate.getPrincipal();
+        return user;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧诲綍鐨勬墍鏈夎璇佷俊鎭�
+     * @return
+     */
+    public static Authentication getAuthentication(){
+        SecurityContext context = SecurityContextHolder.getContext();
+        return context.getAuthentication();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛淇℃伅
+     * @return
+     */
+    public static LoginUser getUserInfo(){
+        Authentication authentication = getAuthentication();
+        if(authentication!=null){
+            Object principal = authentication.getPrincipal();
+            if(principal!=null){
+                LoginUser user = (LoginUser) authentication.getPrincipal();
+                return user;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛ID
+     * @return
+     */
+    public static int getUserId(){
+        LoginUser user = getUserInfo();
+        return user.getId();
+    }
+
+    /**
+     * 鐢熸垚BCryptPasswordEncoder瀵嗙爜
+     *
+     * @param password 瀵嗙爜
+     * @return 鍔犲瘑瀛楃涓�
+     */
+    public static String encryptPassword(String password) {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.encode(password);
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
new file mode 100644
index 0000000..1de14e6
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -0,0 +1,144 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+/**
+ * 閰嶇疆Spring Security
+ */
+@Configuration
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true)
+public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
+
+    @Autowired
+    private DefaultUserDetailsServiceImpl userDetailsService;
+    /**
+     * 鐧诲嚭鎴愬姛鐨勫鐞�
+     */
+    @Autowired
+    private LoginFailureHandler loginFailureHandler;
+    /**
+     * 鐧诲綍鎴愬姛鐨勫鐞�
+     */
+    @Autowired
+    private LoginSuccessHandler loginSuccessHandler;
+    /**
+     * 鐧诲嚭鎴愬姛鐨勫鐞�
+     */
+    @Autowired
+    private LogoutHandler logoutHandler;
+    /**
+     * 鏈櫥褰曠殑澶勭悊
+     */
+    @Autowired
+    private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint;
+//    /**
+//     * 瓒呮椂澶勭悊
+//     */
+//    @Autowired
+//    private InvalidSessionHandler invalidSessionHandler;
+
+//    /**
+//     * 椤跺彿澶勭悊
+//     */
+//    @Autowired
+//    private SessionInformationExpiredHandler sessionInformationExpiredHandler;
+//    /**
+//     * 鐧诲綍鐢ㄦ埛娌℃湁鏉冮檺璁块棶璧勬簮
+//     */
+//    @Autowired
+//    private LoginUserAccessDeniedHandler accessDeniedHandler;
+
+
+    /**
+     * 鎻忚堪: 闈欐�佽祫婧愭斁琛岋紝杩欓噷鐨勬斁琛岋紝鏄笉璧� Spring Security 杩囨护鍣ㄩ摼
+     **/
+    @Override
+    public void configure(WebSecurity web) {
+        // 鍙互鐩存帴璁块棶鐨勯潤鎬佹暟鎹�
+        web.ignoring()
+                .antMatchers("/")
+                .antMatchers("/css/**")
+                .antMatchers("/img/**")
+                .antMatchers("/fonts/**")
+                .antMatchers("/index.html")
+                .antMatchers("/doc.html") // "/webjars/**", "/swagger-resources/**", "/v3/api-docs/**"
+                .antMatchers("/webjars/**")
+                .antMatchers("/swagger-resources/**")
+                .antMatchers("/v3/api-docs/**")
+                .antMatchers("/js/**");
+    }
+
+    /**
+     * 閰嶇疆璁よ瘉鏂瑰紡
+     * @param auth
+     * @throws Exception
+     */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
+        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
+        // 璁剧疆涓嶉殣钘� 鏈壘鍒扮敤鎴峰紓甯�
+        provider.setHideUserNotFoundExceptions(true);
+        // 鐢ㄦ埛璁よ瘉service - 鏌ヨ鏁版嵁搴撶殑閫昏緫
+        provider.setUserDetailsService(userDetailsService);
+        // 璁剧疆瀵嗙爜鍔犲瘑绠楁硶
+        provider.setPasswordEncoder(passwordEncoder());
+        auth.authenticationProvider(provider);
+    }
+
+    @Override
+    protected void configure(HttpSecurity http) throws Exception {
+        http.cors().and().csrf().disable();
+        http.authorizeRequests()
+                // 鏀捐鎺ュ彛
+                .antMatchers("/api/user/login","/index/hook/**").permitAll()
+                // 闄や笂闈㈠鐨勬墍鏈夎姹傚叏閮ㄩ渶瑕侀壌鏉冭璇�
+                .anyRequest().authenticated()
+                // 寮傚父澶勭悊(鏉冮檺鎷掔粷銆佺櫥褰曞け鏁堢瓑)
+                .and().exceptionHandling()
+                .authenticationEntryPoint(anonymousAuthenticationEntryPoint)//鍖垮悕鐢ㄦ埛璁块棶鏃犳潈闄愯祫婧愭椂鐨勫紓甯稿鐞�
+//                .accessDeniedHandler(accessDeniedHandler)//鐧诲綍鐢ㄦ埛娌℃湁鏉冮檺璁块棶璧勬簮
+                // 鐧诲叆
+                .and().formLogin().permitAll()//鍏佽鎵�鏈夌敤鎴�
+                .successHandler(loginSuccessHandler)//鐧诲綍鎴愬姛澶勭悊閫昏緫
+                .failureHandler(loginFailureHandler)//鐧诲綍澶辫触澶勭悊閫昏緫
+                // 鐧诲嚭
+                .and().logout().logoutUrl("/api/user/logout").permitAll()//鍏佽鎵�鏈夌敤鎴�
+                .logoutSuccessHandler(logoutHandler)//鐧诲嚭鎴愬姛澶勭悊閫昏緫
+                .deleteCookies("JSESSIONID")
+                // 浼氳瘽绠$悊
+//                .and().sessionManagement().invalidSessionStrategy(invalidSessionHandler) // 瓒呮椂澶勭悊
+//                .maximumSessions(1)//鍚屼竴璐﹀彿鍚屾椂鐧诲綍鏈�澶х敤鎴锋暟
+//                .expiredSessionStrategy(sessionInformationExpiredHandler) // 椤跺彿澶勭悊
+        ;
+
+    }
+
+    /**
+     * 鎻忚堪: 瀵嗙爜鍔犲瘑绠楁硶 BCrypt 鎺ㄨ崘浣跨敤
+     **/
+    @Bean
+    public BCryptPasswordEncoder passwordEncoder() {
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 鎻忚堪: 娉ㄥ叆AuthenticationManager绠$悊鍣�
+     **/
+    @Override
+    @Bean
+    public AuthenticationManager authenticationManager() throws Exception {
+        return super.authenticationManager();
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java b/src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
new file mode 100644
index 0000000..4bb7017
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
@@ -0,0 +1,95 @@
+package com.genersoft.iot.vmp.conf.security.dto;
+
+import com.genersoft.iot.vmp.storager.dao.dto.User;
+import org.springframework.security.core.CredentialsContainer;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.SpringSecurityCoreVersion;
+import org.springframework.security.core.userdetails.UserDetails;
+
+import java.time.LocalDateTime;
+import java.util.Collection;
+
+public class LoginUser implements UserDetails, CredentialsContainer {
+
+    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
+
+    /**
+     * 鐢ㄦ埛
+     */
+    private User user;
+
+
+    /**
+     * 鐧诲綍鏃堕棿
+     */
+    private LocalDateTime loginTime;
+
+    public LoginUser(User user, LocalDateTime loginTime) {
+        this.user = user;
+        this.loginTime = loginTime;
+    }
+
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities() {
+        return null;
+    }
+
+    @Override
+    public String getPassword() {
+        return user.getPassword();
+    }
+
+    @Override
+    public String getUsername() {
+        return user.getUsername();
+    }
+
+    /**
+     * 璐︽埛鏄惁鏈繃鏈燂紝杩囨湡鏃犳硶楠岃瘉
+     */
+    @Override
+    public boolean isAccountNonExpired() {
+        return true;
+    }
+
+    /**
+     * 鎸囧畾鐢ㄦ埛鏄惁瑙i攣锛岄攣瀹氱殑鐢ㄦ埛鏃犳硶杩涜韬唤楠岃瘉
+     * <p>
+     * 瀵嗙爜閿佸畾
+     * </p>
+     */
+    @Override
+    public boolean isAccountNonLocked() {
+        return true;
+    }
+
+    /**
+     * 鎸囩ず鏄惁宸茶繃鏈熺殑鐢ㄦ埛鐨勫嚟鎹�(瀵嗙爜)锛岃繃鏈熺殑鍑嵁闃叉璁よ瘉
+     */
+    @Override
+    public boolean isCredentialsNonExpired() {
+        return true;
+    }
+
+    /**
+     * 鐢ㄦ埛鏄惁琚惎鐢ㄦ垨绂佺敤銆傜鐢ㄧ殑鐢ㄦ埛鏃犳硶杩涜韬唤楠岃瘉銆�
+     */
+    @Override
+    public boolean isEnabled() {
+        return true;
+    }
+
+    /**
+     * 璁よ瘉瀹屾垚鍚庯紝鎿﹂櫎瀵嗙爜
+     */
+    @Override
+    public void eraseCredentials() {
+        user.setPassword(null);
+    }
+
+
+    public int getId() {
+        return user.getId();
+    }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/service/IUserService.java b/src/main/java/com/genersoft/iot/vmp/service/IUserService.java
index 868118b..cb6b6b7 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/IUserService.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/IUserService.java
@@ -8,5 +8,5 @@
 
     boolean changePassword(int id, String password);
 
-
+    User getUserByUsername(String username);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
index 0a67a01..2539f5b 100644
--- a/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/service/impl/UserServiceImpl.java
@@ -24,4 +24,9 @@
         user.setPassword(password);
         return userMapper.update(user) > 0;
     }
+
+    @Override
+    public User getUserByUsername(String username) {
+        return userMapper.getUserByUsername(username);
+    }
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java b/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
index 4608a29..e16cadc 100644
--- a/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
+++ b/src/main/java/com/genersoft/iot/vmp/storager/dao/UserMapper.java
@@ -28,4 +28,7 @@
 
     @Select("select * FROM user WHERE id= #{id}")
     User selectById(int id);
+
+    @Select("select * FROM user WHERE username= #{username}")
+    User getUserByUsername(String username);
 }
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
index cf781c0..4fd7b96 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -1,5 +1,7 @@
 package com.genersoft.iot.vmp.vmanager.user;
 
+import com.genersoft.iot.vmp.conf.security.SecurityUtils;
+import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
 import com.genersoft.iot.vmp.service.IUserService;
 import com.genersoft.iot.vmp.storager.dao.dto.User;
 import io.swagger.annotations.Api;
@@ -8,11 +10,12 @@
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.util.DigestUtils;
 import org.springframework.util.StringUtils;
-import org.springframework.web.bind.annotation.CrossOrigin;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import javax.security.sasl.AuthenticationException;
 
 @Api(tags = "鐢ㄦ埛绠$悊")
 @CrossOrigin
@@ -21,21 +24,46 @@
 public class UserController {
 
     @Autowired
-    private IUserService userService;
+    AuthenticationManager authenticationManager;
 
+    @Autowired
+    IUserService userService;
 
     @ApiOperation("鐧诲綍")
     @ApiImplicitParams({
             @ApiImplicitParam(name = "username", value = "鐢ㄦ埛鍚�", dataTypeClass = String.class),
-            @ApiImplicitParam(name = "password", value = "瀵嗙爜锛�32鏈猰d5鍔犲瘑锛�", dataTypeClass = String.class),
+            @ApiImplicitParam(name = "password", value = "瀵嗙爜锛�32浣峬d5鍔犲瘑锛�", dataTypeClass = String.class),
     })
     @GetMapping("/login")
     public String login(String username, String password){
-        User user = userService.getUser(username, password);
+        LoginUser user = null;
+        try {
+            user = SecurityUtils.login(username, password, authenticationManager);
+        } catch (AuthenticationException e) {
+            e.printStackTrace();
+            return "fail";
+        }
         if (user != null) {
             return "success";
         }else {
             return "fail";
         }
     }
+
+    @ApiOperation("淇敼瀵嗙爜")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "username", value = "鐢ㄦ埛鍚�", dataTypeClass = String.class),
+            @ApiImplicitParam(name = "password", value = "瀵嗙爜锛堟湭md5鍔犲瘑鐨勫瘑鐮侊級", dataTypeClass = String.class),
+    })
+    @PostMapping("/changePassword")
+    public String changePassword(String password){
+        // 鑾峰彇褰撳墠鐧诲綍鐢ㄦ埛id
+        int userId = SecurityUtils.getUserId();
+        boolean result = userService.changePassword(userId, DigestUtils.md5DigestAsHex(password.getBytes()));
+        if (result) {
+            return "success";
+        }else {
+            return "fail";
+        }
+    }
 }
diff --git a/web_src/config/index.js b/web_src/config/index.js
index a16611c..e6c0f6c 100644
--- a/web_src/config/index.js
+++ b/web_src/config/index.js
@@ -17,7 +17,8 @@
         pathRewrite: {
           '^/debug': '/'
         }
-      }
+      },
+
     },
 
     // Various Dev Server settings
diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue
index 40d2146..cdc25bc 100644
--- a/web_src/src/components/DeviceList.vue
+++ b/web_src/src/components/DeviceList.vue
@@ -215,8 +215,8 @@
         console.log(`淇敼浼犺緭鏂瑰紡涓� ${row.streamMode}锛�${row.deviceId} `);
         let that = this;
         this.$axios({
-          method: 'get',
-          url: '/api/device/query/transport' + row.deviceId + '/' + row.streamMode
+          method: 'post',
+          url: '/api/device/query/transport/' + row.deviceId + '/' + row.streamMode
         }).then(function(res) {
 
         }).catch(function(e) {
diff --git a/web_src/src/components/Login.vue b/web_src/src/components/Login.vue
index 315293b..65c27f6 100644
--- a/web_src/src/components/Login.vue
+++ b/web_src/src/components/Login.vue
@@ -63,7 +63,7 @@
 
       this.$axios({
       	method: 'get',
-	url:"/api/user/login",
+	      url:"/api/user/login",
         params: loginParam
       }).then(function (res) {
         console.log(JSON.stringify(res));
@@ -81,7 +81,7 @@
               });
           }
       }).catch(function (error) {
-        that.$message.error(error.response.statusText);
+        that.$message.error(error.response.data.msg);
         that.isLoging = false;
       });
     },
diff --git a/web_src/src/components/UiHeader.vue b/web_src/src/components/UiHeader.vue
index 85bb230..e537953 100644
--- a/web_src/src/components/UiHeader.vue
+++ b/web_src/src/components/UiHeader.vue
@@ -1,21 +1,30 @@
 <template>
 	<div id="UiHeader">
-		<el-menu router :default-active="this.$route.path" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
+		<el-menu router :default-active="this.$route.path" menu-trigger="click" background-color="#545c64" text-color="#fff" active-text-color="#ffd04b" mode="horizontal">
             <el-menu-item index="/">鎺у埗鍙�</el-menu-item>
             <el-menu-item index="/deviceList">璁惧鍒楄〃</el-menu-item>
             <el-menu-item index="/pushVideoList">鎺ㄦ祦鍒楄〃</el-menu-item>
             <el-menu-item index="/streamProxyList">鎷夋祦浠g悊</el-menu-item>
             <el-menu-item index="/parentPlatformList/15/1">鍥芥爣绾ц仈</el-menu-item>
+            <el-menu-item @click="openDoc">鍦ㄧ嚎鏂囨。</el-menu-item>
             <el-switch v-model="alarmNotify"  active-text="鎶ヨ淇℃伅鎺ㄩ��" style="display: block float: right" @change="sseControl"></el-switch>
-            <el-menu-item style="float: right;" @click="loginout">閫�鍑�</el-menu-item>
+<!--            <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>
+              <el-menu-item @click="changePassword">淇敼瀵嗙爜</el-menu-item>
+              <el-menu-item @click="loginout">娉ㄩ攢</el-menu-item>
+            </el-submenu>
         </el-menu>
+    <changePasswordDialog ref="changePasswordDialog"></changePasswordDialog>
 	</div>
 </template>
 
 <script>
+
+import changePasswordDialog from './dialog/changePassword.vue'
 export default {
     name: "UiHeader",
-    components: { Notification },
+    components: { Notification, changePasswordDialog },
     data() {
         return {
             alarmNotify: true,
@@ -24,10 +33,25 @@
     },
     methods:{
   	    loginout(){
+          this.$axios({
+            method: 'get',
+            url:"/api/user/logout"
+          }).then((res)=> {
             // 鍒犻櫎cookie锛屽洖鍒扮櫥褰曢〉闈�
             this.$cookies.remove("session");
             this.$router.push('/login');
             this.sseSource.close();
+          }).catch((error)=> {
+            console.error("鐧诲嚭澶辫触")
+            console.error(error)
+          });
+        },
+        changePassword(){
+          this.$refs.changePasswordDialog.openDialog()
+        },
+        openDoc(){
+  	      console.log(process.env.BASE_API)
+          window.open( !!process.env.BASE_API? process.env.BASE_API + "/doc.html": "/doc.html")
         },
         beforeunloadHandler() {
             this.sseSource.close();
diff --git a/web_src/src/components/dialog/changePassword.vue b/web_src/src/components/dialog/changePassword.vue
new file mode 100644
index 0000000..5842df0
--- /dev/null
+++ b/web_src/src/components/dialog/changePassword.vue
@@ -0,0 +1,107 @@
+<template>
+  <div id="changePassword" v-loading="isLoging">
+    <el-dialog
+      title="淇敼瀵嗙爜"
+      width="40%"
+      top="2rem"
+      :close-on-click-modal="false"
+      :visible.sync="showDialog"
+      :destroy-on-close="true"
+      @close="close()"
+    >
+      <div id="shared" style="margin-right: 20px;">
+        <el-form ref="passwordForm" :rules="rules" status-icon label-width="80px">
+              <el-form-item label="鏂板瘑鐮�" prop="newPassword" >
+                <el-input v-model="newPassword" autocomplete="off"></el-input>
+              </el-form-item>
+              <el-form-item label="纭瀵嗙爜" prop="confirmPassword">
+                <el-input v-model="confirmPassword" autocomplete="off"></el-input>
+              </el-form-item>
+
+              <el-form-item>
+                <div style="float: right;">
+                  <el-button type="primary" @click="onSubmit">淇濆瓨</el-button>
+                  <el-button @click="close">鍙栨秷</el-button>
+                </div>
+              </el-form-item>
+            </el-form>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "changePassword",
+  props: {},
+  computed: {},
+  created() {},
+  data() {
+    let validatePass = (rule, value, callback) => {
+      if (value === '') {
+        callback(new Error('璇疯緭鍏ュ瘑鐮�'));
+      } else {
+        if (this.confirmPassword !== '') {
+          this.$refs.passwordForm.validateField('confirmPassword');
+        }
+        callback();
+      }
+    };
+    let validatePass2 = (rule, value, callback) => {
+      if (this.confirmPassword === '') {
+        callback(new Error('璇峰啀娆¤緭鍏ュ瘑鐮�'));
+      } else if (this.confirmPassword !== this.newPassword) {
+        callback(new Error('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷�!'));
+      } else {
+        callback();
+      }
+    };
+    return {
+      newPassword: null,
+      confirmPassword: null,
+      showDialog: false,
+      isLoging: false,
+      rules: {
+        newPassword: [{ required: true, validator: validatePass, trigger: "blur" }],
+        confirmPassword: [{ required: true, validator: validatePass2, trigger: "blur" }],
+      },
+    };
+  },
+  methods: {
+    openDialog: function () {
+      this.showDialog = true;
+    },
+    onSubmit: function () {
+      this.$axios({
+        method: 'post',
+        url:"/api/user/changePassword",
+        params: {
+          password: this.newPassword
+        }
+      }).then((res)=> {
+        if (res.data === "success"){
+          this.$message({
+            showClose: true,
+            message: '淇敼鎴愬姛锛岃閲嶆柊鐧婚檰',
+            type: 'success'
+          });
+          this.showDialog = false;
+          setTimeout(()=>{
+            // 鍒犻櫎cookie锛屽洖鍒扮櫥褰曢〉闈�
+            this.$cookies.remove("session");
+            this.$router.push('/login');
+            this.sseSource.close();
+          },800)
+        }
+      }).catch((error)=> {
+        console.error(error)
+      });
+    },
+    close: function () {
+      this.showDialog = false;
+      this.newPassword= null;
+      this.confirmPassword=null;
+    },
+  },
+};
+</script>
diff --git a/web_src/src/main.js b/web_src/src/main.js
index ed1f36c..56586f5 100644
--- a/web_src/src/main.js
+++ b/web_src/src/main.js
@@ -40,6 +40,18 @@
 
 axios.defaults.baseURL = (process.env.NODE_ENV === 'development') ? process.env.BASE_API : "";
 
+// api 杩斿洖401鑷姩鍥炵櫥闄嗛〉闈�
+axios.interceptors.response.use(function (response) {
+  // 瀵瑰搷搴旀暟鎹仛鐐逛粈涔�
+  return response;
+}, function (error) {
+  // 瀵瑰搷搴旈敊璇仛鐐逛粈涔�
+  if (error.response.status === 401) {
+    router.push('/login');
+  }
+  return Promise.reject(error);
+});
+
 Vue.prototype.$cookies.config(60*30);
 
 

--
Gitblit v1.8.0