From 1ff8c1b9c98090c06a14d6274bb1a7a94a0423aa Mon Sep 17 00:00:00 2001
From: panlinlin <648540858@qq.com>
Date: Wed, 14 Apr 2021 16:33:10 +0800
Subject: [PATCH] =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=8E=A5=E5=8F=A3=E9=89=B4?=
=?UTF-8?q?=E6=9D=83=EF=BC=8C=E6=94=AF=E6=8C=81=E4=BF=AE=E6=94=B9=E5=AF=86?=
=?UTF-8?q?=E7=A0=81=EF=BC=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 4 +
.../AnonymousAuthenticationEntryPoint.java | 41 +++++
.../DefaultUserDetailsServiceImpl.java | 52 +++++++
.../conf/security/InvalidSessionHandler.java | 24 +++
.../conf/security/LoginFailureHandler.java | 65 ++++++++
.../conf/security/LoginSuccessHandler.java | 24 +++
.../iot/vmp/conf/security/LogoutHandler.java | 27 ++++
.../iot/vmp/conf/security/SecurityUtils.java | 80 ++++++++++
.../vmp/conf/security/WebSecurityConfig.java | 144 ++++++++++++++++++
.../iot/vmp/conf/security/dto/LoginUser.java | 95 ++++++++++++
.../iot/vmp/service/IUserService.java | 2 +-
.../iot/vmp/service/impl/UserServiceImpl.java | 5 +
.../iot/vmp/storager/dao/UserMapper.java | 3 +
.../iot/vmp/vmanager/user/UserController.java | 42 ++++-
web_src/config/index.js | 3 +-
web_src/src/components/DeviceList.vue | 4 +-
web_src/src/components/Login.vue | 4 +-
web_src/src/components/UiHeader.vue | 30 +++-
.../src/components/dialog/changePassword.vue | 107 +++++++++++++
web_src/src/main.js | 12 ++
20 files changed, 752 insertions(+), 16 deletions(-)
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/LoginFailureHandler.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/LogoutHandler.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/dto/LoginUser.java
create mode 100644 web_src/src/components/dialog/changePassword.vue
diff --git a/pom.xml b/pom.xml
index c07f7ad6..c1383e74 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,10 @@
mybatis-spring-boot-starter
2.1.4
+
+ org.springframework.boot
+ spring-boot-starter-security
+
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 00000000..20644709
--- /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("用户需要登录,访问[{}]失败,AuthenticationException=[{}]", 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 00000000..c0103357
--- /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 00000000..f3fd0685
--- /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 00000000..1ad05c0e
--- /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 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 00000000..9690c6d1
--- /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 00000000..790eab84
--- /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 00000000..d186d841
--- /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进行认证授权 主动调
+ * 用AuthenticationManager的authenticate方法实现
+ * 授权成功后将用户信息存入SecurityContext当中
+ * @param username 用户名
+ * @param password 密码
+ * @param authenticationManager 认证授权管理器,
+ * @see AuthenticationManager
+ * @return UserInfo 用户信息
+ */
+ 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);
+ 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 00000000..1de14e63
--- /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 00000000..4bb70178
--- /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;
+ }
+
+ /**
+ * 指定用户是否解锁,锁定的用户无法进行身份验证
+ *
+ * 密码锁定
+ *
+ */
+ @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 868118b2..cb6b6b7a 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 @@ public interface IUserService {
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 0a67a018..2539f5b5 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 @@ public class UserServiceImpl implements IUserService {
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 4608a29e..e16cadcf 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 @@ public interface UserMapper {
@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 cf781c07..4fd7b968 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.ApiImplicitParams;
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 @@ import org.springframework.web.bind.annotation.RestController;
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未md5加密)", dataTypeClass = String.class),
+ @ApiImplicitParam(name = "password", value = "密码(32位md5加密)", 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 a16611c0..e6c0f6c9 100644
--- a/web_src/config/index.js
+++ b/web_src/config/index.js
@@ -17,7 +17,8 @@ module.exports = {
pathRewrite: {
'^/debug': '/'
}
- }
+ },
+
},
// Various Dev Server settings
diff --git a/web_src/src/components/DeviceList.vue b/web_src/src/components/DeviceList.vue
index 40d21469..cdc25bcb 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 315293b2..65c27f62 100644
--- a/web_src/src/components/Login.vue
+++ b/web_src/src/components/Login.vue
@@ -63,7 +63,7 @@ export default {
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 @@ export default {
});
}
}).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 85bb2302..e5379532 100644
--- a/web_src/src/components/UiHeader.vue
+++ b/web_src/src/components/UiHeader.vue
@@ -1,21 +1,30 @@
diff --git a/web_src/src/main.js b/web_src/src/main.js
index ed1f36cc..56586f5d 100644
--- a/web_src/src/main.js
+++ b/web_src/src/main.js
@@ -40,6 +40,18 @@ Vue.prototype.$notify = Notification;
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);