From cb5849d8a14f55241c44bdf6724b18de7950564d 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 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);