#spring boot工程集成jwt 鉴权步骤
1、pom.xml依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.1</version></dependency>
2、JwtUtils.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;import java.util.Date;public class JwtUtils {private static final String SECRET_KEY = "rBSnM5GAB0T7M6mZ8Yg";//your_secret_keyprivate static final long EXPIRATION_TIME = 86400000; // 1 day// private static final long EXPIRATION_TIME = 3000;public static String generateToken(String username) {return Jwts.builder().setSubject(username).setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).signWith(SignatureAlgorithm.HS512, SECRET_KEY).compact();}/** 设置token失效*/public static void setTokenExpired(String token) {getClaimsFromToken(token).setExpiration(new Date(System.currentTimeMillis()));
// getClaimsFromToken(token).clear();}public static Claims getClaimsFromToken(String token) {return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();}public static boolean isTokenExpired(String token) {return getClaimsFromToken(token).getExpiration().before(new Date());}
}
3、JwtAuthenticationFilter.java
import com.ewaycloud.jw.common.core.util.JwtUtils;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;public class JwtAuthenticationFilter extends BasicAuthenticationFilter {public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {super(authenticationManager);}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws IOException, ServletException {String header = request.getHeader("Authorization");if (header == null || !header.startsWith("Bearer ")) {chain.doFilter(request, response);return;}String token = header.substring(7);UsernamePasswordAuthenticationToken authentication = getAuthentication(token);SecurityContextHolder.getContext().setAuthentication(authentication);chain.doFilter(request, response);}private UsernamePasswordAuthenticationToken getAuthentication(String token) {if (token != null && !JwtUtils.isTokenExpired(token)) {String user = JwtUtils.getClaimsFromToken(token).getSubject();if (user != null) {return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());}}return null;}
}
4、WebGlobalInterceptor.java
import com.ewaycloud.jw.common.core.config.CoreCommonProperties;
import com.ewaycloud.jw.common.core.config.MyCacheManager;
import com.ewaycloud.jw.common.core.util.JwtUtils;
import com.ewaycloud.jw.common.core.util.SpringContextHolder;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;/*** WEB全局拦截器*** @date 2022/8/25*/
@Slf4j
@RequiredArgsConstructor
public class WebGlobalInterceptor implements HandlerInterceptor {private final ObjectMapper objectMapper;private final CoreCommonProperties coreCommonProperties;private final CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String header = request.getHeader("Authorization");if (header == null || !header.startsWith("Bearer ")) {return false;}String token = header.substring(7);if(token == null || JwtUtils.isTokenExpired(token)){return false;}/**从缓存中获取token, 用户主动退出后清除*/if(null ==MyCacheManager.get(token)){return false;}UsernamePasswordAuthenticationToken authentication = getAuthentication(token);SecurityContextHolder.getContext().setAuthentication(authentication);return true;}private UsernamePasswordAuthenticationToken getAuthentication(String token) {if (token != null && !JwtUtils.isTokenExpired(token)) {String user = JwtUtils.getClaimsFromToken(token).getSubject();if (user != null) {return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());}}return null;}}
5、WebGlobalInterceptorConfigurer.java
import com.ewaycloud.jw.common.core.config.CoreCommonProperties;
import com.ewaycloud.jw.common.data.resolver.SqlFilterArgumentResolver;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;import java.util.List;/*** 拦截器配置* @author gwh* @date 2024/10/26*/
@Configuration
@RequiredArgsConstructor
public class WebGlobalInterceptorConfigurer implements WebMvcConfigurer {private final ObjectMapper objectMapper;private final CoreCommonProperties coreCommonProperties;/*** 增加请求参数解析器,对请求中的参数注入SQL 检查* @param resolverList 参数解析器*/@Overridepublic void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolverList) {resolverList.add(new SqlFilterArgumentResolver());}@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(webGlobalInterceptor()).addPathPatterns("/**").excludePathPatterns("/user/login","/user/logout");}@Beanpublic WebGlobalInterceptor webGlobalInterceptor(){return new WebGlobalInterceptor(objectMapper, coreCommonProperties);}}
6、SecurityUtils.java
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.ewaycloud.jw.common.core.config.MyCacheManager;
import com.ewaycloud.jw.common.core.user.SysUser;
import com.ewaycloud.jw.common.core.user.UserInfo;
import com.ewaycloud.jw.common.core.constant.CommonConstants;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
//import org.springframework.data.redis.core.RedisTemplate;import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;/*** 安全工具类** @author gwh*/
@Slf4j
@UtilityClass
public class SecurityUtils {private final CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class);// @Resource
// private RedisTemplate redisTemplate;/*** 获取用户登录信息*/public UserInfo getUserInfo() {// 获取传递的tokenString token = WebUtils.getRequest().getHeader(CommonConstants.AUTHORIZATION);if (StrUtil.isBlank(token)) token = WebUtils.getRequest().getParameter(CommonConstants.AUTHORIZATION.toLowerCase());log.debug("获取header用户token为:{}", token);// 验证登录信息if (StrUtil.isNotBlank(token)) {UserInfo userInfo = (UserInfo)MyCacheManager.get(token.substring(7));if (userInfo != null ) {if ( userInfo.getSysUser() == null) {return null;}return userInfo;} else {return null;}} else {return null;}}/*** 获取用户*/public SysUser getUser() {if (Objects.isNull(getUserInfo())) return null;return getUserInfo().getSysUser();}/*** 获取用户角色信息* @return 角色集合*/public List<Long> getRoleIds() {if (Objects.isNull(getUserInfo())) return null;return CollUtil.newArrayList(getUserInfo().getRoles());}}
7、SecurityConfig.java
import com.ewaycloud.jw.common.data.interceptor.JwtAuthenticationFilter;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/user/login","/user/logout").permitAll().anyRequest().authenticated().and().addFilter(new JwtAuthenticationFilter(authenticationManager()));}
}
8、SysUserController.java
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ewaycloud.jw.admin.api.dto.UserDTO;
import com.ewaycloud.jw.admin.api.vo.UserVO;
import com.ewaycloud.jw.admin.mapper.SysUserMapper;
import com.ewaycloud.jw.admin.service.SysUserService;
import com.ewaycloud.jw.channel.model.SysLogInfo;
import com.ewaycloud.jw.channel.service.SysLogInfoService;
import com.ewaycloud.jw.common.core.config.MyCacheManager;
import com.ewaycloud.jw.common.core.constant.CommonConstants;
import com.ewaycloud.jw.common.core.exception.ErrorCodes;
import com.ewaycloud.jw.common.core.user.SysUser;
import com.ewaycloud.jw.common.core.user.UserInfo;
import com.ewaycloud.jw.common.core.util.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.web.bind.annotation.*;import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;
import java.util.Objects;/*** * @date 2018/12/16*/
@RestController
@AllArgsConstructor
@RequestMapping("/user")
@Api(value = "user", tags = "用户管理模块")
public class SysUserController {private final SysUserService userService;private final CacheManager cacheManager;
// private final RedisTemplate redisTemplate;@Resourceprivate SysLogInfoService sysLogInfoService;@Resourceprivate SysUserMapper sysUserMapper;public static String getIpAddr(HttpServletRequest request) {String ipAddress = null;try {ipAddress = request.getHeader("x-forwarded-for");if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getHeader("WL-Proxy-Client-IP");}if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {ipAddress = request.getRemoteAddr();if (ipAddress.equals("127.0.0.1")) {// 根据网卡取本机配置的IPInetAddress inet = null;try {inet = InetAddress.getLocalHost();} catch (UnknownHostException e) {e.printStackTrace();}ipAddress = inet.getHostAddress();}}// 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length()if (ipAddress.indexOf(",") > 0) {ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));}}} catch (Exception e) {ipAddress = "";}return ipAddress;}/*** 用户登录* @return 用户信息*/@GetMapping("/login")public R login(@RequestParam String username, @RequestParam String password, HttpServletRequest request) {UserInfo userInfo = userService.login(username, password);if (null != userInfo && userInfo.getLoginCount()==0) {return R.ok(userInfo);}if (null == userInfo ) {return R.failed("用户名或密码错误");}if(null != userInfo && userInfo.getLoginCount()>0 && userInfo.getLoginCount()<5) {return R.failed("用户名或密码错误");}if(null != userInfo && userInfo.getLoginCount()>5 ) {return R.failed("密码错误次数过多,账户已被锁定");}/** 记录日志 */SysLogInfo vo = new SysLogInfo();vo.setOperate("Get登录系统/user/login");if(null != userInfo && null!= userInfo.getSysUser()){vo.setCreateBy(userInfo.getSysUser().getName());}if(null != userInfo && null!= userInfo.getAreaName()){vo.setArea(userInfo.getAreaName());}vo.setCreateTime(new Date());//查询角色if(null != userInfo && null != userInfo.getSysUser()){UserVO userVO = sysUserMapper.getUserVoById(userInfo.getSysUser().getUserId());vo.setRole(userVO.getRoleList().get(0).getRoleName());}vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return R.ok();}/*** 获取指定用户全部信息* @return 用户信息*/@GetMapping("/info/{username}")public R info(@PathVariable String username, HttpServletRequest request) {SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));if (user == null) {return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_USERINFO_EMPTY, username));}SysLogInfo vo = new SysLogInfo();vo.setOperate("Get获取指定用户全部信息/user/"+username);vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return R.ok(userService.findUserInfo(user));}/*** 获取当前用户登出* @return 用户信息*/@DeleteMapping(value = { "/logout" })public R logout( HttpServletRequest request) {if (Objects.isNull(SecurityUtils.getUser())) return R.ok();String token = WebUtils.getRequest().getHeader(CommonConstants.AUTHORIZATION).substring(7);/** 设置token失效*/if(null != token){JwtUtils.setTokenExpired(token);MyCacheManager.set(token, null);}SysLogInfo vo = new SysLogInfo();vo.setOperate("Delete退出系统/user/logout"+ token);vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return R.ok();}/*** 获取当前用户全部信息* @return 用户信息*/@GetMapping(value = { "/info" })public R info() {String username = SecurityUtils.getUser().getUsername();SysUser user = userService.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));if (user == null) {return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_QUERY_ERROR));}return R.ok(userService.findUserInfo(user));}/*** 通过ID查询用户信息* @param id ID* @return 用户信息*/@GetMapping("/{id}")public R user(@PathVariable Long id) {return R.ok(userService.selectUserVoById(id));}/*** 根据用户名查询用户信息* @param username 用户名* @return*/@GetMapping("/details/{username}")public R user(@PathVariable String username) {SysUser condition = new SysUser();condition.setUsername(username);return R.ok(userService.getOne(new QueryWrapper<>(condition)));}/*** 删除用户信息* @param id ID* @return R*/@DeleteMapping("/{id}")@ApiOperation(value = "删除用户", notes = "根据ID删除用户")@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "path")public R userDel(@PathVariable Long id, HttpServletRequest request) {SysUser sysUser = userService.getById(id);SysLogInfo vo = new SysLogInfo();vo.setOperate("Delete删除用户信息/id"+id);vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return R.ok(userService.deleteUserById(sysUser));}/*** 添加用户* @param userDto 用户信息* @return success/false*/@PostMappingpublic R user(@RequestBody UserDTO userDto, HttpServletRequest request) {SysLogInfo vo = new SysLogInfo();vo.setOperate("Post添加用户/name"+userDto.getName());vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return R.ok(userService.saveUser(userDto));}/*** 更新用户信息* @param userDto 用户信息* @return R*/@PutMappingpublic R updateUser(@Valid @RequestBody UserDTO userDto) {return R.ok(userService.updateUser(userDto));}/*** 分页查询用户* @param page 参数集* @param userDTO 查询参数列表* @return 用户集合*/@GetMapping("/page")public R getUserPage(Page page, UserDTO userDTO) {//根据当前登录人所在的区县 areaId 做权限控制, 市级用户看全部Long userId = SecurityUtils.getUser().getUserId();UserVO userVO = sysUserMapper.getUserVoById(userId);if(userVO.getAreaId() == 370300 || userVO.getUsername().equals("admin")){return R.ok(userService.getUsersWithRolePage(page, userDTO));}else {userDTO.setUserId(userId);return R.ok(userService.getUsersWithRolePage(page, userDTO));}}/*** 修改个人信息* @param userDto userDto* @return success/false*/@PutMapping("/edit")public R updateUserInfo(@Valid @RequestBody UserDTO userDto, HttpServletRequest request) {SysLogInfo vo = new SysLogInfo();vo.setOperate("Put修改个人信息/edit/"+userDto.getUserId());vo.setIp(getIpAddr(request));sysLogInfoService.addSysLogInfo(vo);return userService.updateUserInfo(userDto);}/*** @param username 用户名称* @return 上级部门用户列表*/@GetMapping("/ancestor/{username}")public R listAncestorUsers(@PathVariable String username) {return R.ok(userService.listAncestorUsers(username));}/*** 锁定指定用户* @param username 用户名* @return R*/@PutMapping("/lock/{username}")public R lockUser(@PathVariable String username) {SysLogInfo vo = new SysLogInfo();vo.setOperate("Put锁定指定用户/lock/username/"+username);sysLogInfoService.addSysLogInfo(vo);return userService.lockUser(username);}/*** 通过ID查询用户** @param id ID* @return 用户信息*/@GetMapping("/id/{id}")public R getByUserId(@PathVariable Long id) {return R.ok(userService.getById(id));}/*** 查询租户所有用户携带部门名称*/@GetMapping("/list/dept-name")public R listUsersWithDeptName(){return R.ok(userService.listUsersWithDeptName());}/*** 查询选择办理人/角色分页** @param userVO 查询参数列表* @return 用户及角色集合*/@GetMapping("/user-role/page")public R getUserRolePage(Page page, UserVO userVO) {return R.ok(userService.getUserRolePage(page, userVO));}/*** 查询租户所有用户*/@GetMapping("/list")public R listUsers(){if(null == SecurityUtils.getUser().getUserId()){return null;}//根据当前登录人所在的区县 areaId 做权限控制, 市级用户看全部Long userId = SecurityUtils.getUser().getUserId();UserVO userVO = sysUserMapper.getUserVoById(userId);if(userVO.getAreaId() == 370300){return R.ok(userService.list());}else {UserDTO userDTO = new UserDTO();userDTO.setUserId(userId);List<UserVO> userList = sysUserMapper.selectVoListByScope(userDTO);return R.ok(userList);}}}
9、SysUserServiceImpl.java
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.AES;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ewaycloud.jw.admin.api.dto.UserDTO;
import com.ewaycloud.jw.admin.api.entity.SysDept;
import com.ewaycloud.jw.admin.api.entity.SysMenu;
import com.ewaycloud.jw.admin.api.entity.SysRole;
import com.ewaycloud.jw.admin.api.entity.SysUserRole;
import com.ewaycloud.jw.admin.api.vo.RoleVO;
import com.ewaycloud.jw.admin.api.vo.UserVO;
import com.ewaycloud.jw.admin.config.LoginConfigProperties;
import com.ewaycloud.jw.admin.mapper.SysUserMapper;
import com.ewaycloud.jw.admin.service.*;
import com.ewaycloud.jw.common.core.config.MyCacheManager;
import com.ewaycloud.jw.common.core.constant.CommonConstants;
import com.ewaycloud.jw.common.core.exception.ErrorCodes;
import com.ewaycloud.jw.common.core.user.SysUser;
import com.ewaycloud.jw.common.core.user.UserInfo;
import com.ewaycloud.jw.common.core.util.JwtUtils;
import com.ewaycloud.jw.common.core.util.MsgUtils;
import com.ewaycloud.jw.common.core.util.R;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.validation.ValidationException;
import java.util.*;
import java.util.stream.Collectors;/**** @date 2017/10/31*/
@Slf4j
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();private final SysMenuService sysMenuService;private final SysRoleService sysRoleService;private final SysDeptService sysDeptService;private final SysUserRoleService sysUserRoleService;private final LoginConfigProperties loginConfigProperties;private final CacheManager cacheManager;private final SysUserMapper sysUserMapper;// private final RedisTemplate redisTemplate;private static final String KEY_ALGORITHM = "AES";private static int loginCount = 0;private static final int MAX_LOGIN_COUNT = 5;private static boolean isLocked = false;/*** 保存用户信息* @param userDto DTO 对象* @return success/fail*/@Override@Transactional(rollbackFor = Exception.class)public Boolean saveUser(UserDTO userDto) {SysUser sysUser = new SysUser();BeanUtils.copyProperties(userDto, sysUser);sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);sysUser.setPassword(ENCODER.encode(userDto.getPassword()));baseMapper.insert(sysUser);// 如果角色为空,赋默认角色if (CollUtil.isEmpty(userDto.getRole())) {// 默认角色SysRole sysRole = sysRoleService.getOne(Wrappers.<SysRole>lambdaQuery().eq(SysRole::getRoleCode, 1));userDto.setRole(Collections.singletonList(sysRole.getRoleId()));}List<SysUserRole> userRoleList = userDto.getRole().stream().map(roleId -> {SysUserRole userRole = new SysUserRole();userRole.setUserId(sysUser.getUserId());userRole.setRoleId(roleId);return userRole;}).collect(Collectors.toList());return sysUserRoleService.saveBatch(userRoleList);}@Overridepublic UserInfo login(String username, String password) {if (isLocked) {System.out.println(username+ " 账户已锁定,请稍后再试");return null;}SysUser user = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));if (user == null) {throw new ValidationException("用户名或密码错误");}if (CommonConstants.STATUS_LOCK.equals(user.getLockFlag())) {return null;}if (!ENCODER.matches(this.decryptAES(password), user.getPassword())) {loginCount++;System.out.println(username+ "密码错误,还剩余" + (MAX_LOGIN_COUNT - loginCount) + "次机会");if (loginCount < MAX_LOGIN_COUNT) {UserInfo userInfo = new UserInfo();userInfo.setLoginCount(loginCount);return userInfo;}if (loginCount >= MAX_LOGIN_COUNT) {System.out.println(username+ "密码错误次数过多,账户已被锁定");
// isLocked = true;/** 锁定用户 */this.lockUser(username);UserInfo userInfo = new UserInfo();userInfo.setLoginCount(loginCount);return userInfo;}} else {System.out.println(username+ "登录成功!");loginCount = 0;// 放入缓存UserInfo userInfo = this.findUserInfo(user);UserInfo userInfoCache = new UserInfo();BeanUtil.copyProperties(userInfo, userInfoCache);//通userId查询用户的areaIdUserVO userVO = sysUserMapper.getUserVoById(user.getUserId());userInfo.setAreaId(userVO.getAreaId());userInfo.setAreaName(userVO.getAreaName());userInfo.setLoginCount(0);userInfoCache.setToken(JwtUtils.generateToken(username));/** 设置token */String token = JwtUtils.generateToken(username);userInfo.setToken(token);/** 本地缓存 1天 */
// MyCacheManager.set(userInfo.getSysUser().getUserId().toString(), userInfoCache, 24*60*60*1000); //缓存用户信息1天,即 24*60*60*1000MyCacheManager.set(token, userInfoCache, 24*60*60*1000); //缓存用户信息1天,即 24*60*60*1000// redisTemplate.opsForValue().set(token, userInfoCache, 86400000);
// redisTemplate.opsForValue().set(username, token, 86400000);log.info("登录用户{}",userInfo.getSysUser().getUsername());
// isLocked = false;return userInfo;}return null;}/*** 原文解密*/private String decryptAES(String password) {// 构建前端对应解密AES 因子AES aes = new AES(Mode.CFB, Padding.NoPadding,new SecretKeySpec(loginConfigProperties.getEncodeKey().getBytes(), KEY_ALGORITHM),new IvParameterSpec(loginConfigProperties.getEncodeKey().getBytes()));return aes.decryptStr(password);}/*** 通过查用户的全部信息* @param sysUser 用户* @return*/@Overridepublic UserInfo findUserInfo(SysUser sysUser) {UserInfo userInfo = new UserInfo();userInfo.setSysUser(sysUser);// 设置角色列表 (ID)List<Long> roleIds = sysRoleService.findRolesByUserId(sysUser.getUserId()).stream().map(RoleVO::getRoleId).collect(Collectors.toList());userInfo.setRoles(ArrayUtil.toArray(roleIds, Long.class));// 设置权限列表(menu.permission)Set<String> permissions = new HashSet<>();roleIds.forEach(roleId -> {List<String> permissionList = sysMenuService.findMenuByRoleId(roleId).stream().map(SysMenu::getPermission).filter(StrUtil::isNotEmpty).collect(Collectors.toList());permissions.addAll(permissionList);});userInfo.setPermissions(ArrayUtil.toArray(permissions, String.class));return userInfo;}/*** 分页查询用户信息(含有角色信息)* @param page 分页对象* @param userDTO 参数列表* @return*/@Overridepublic IPage getUsersWithRolePage(Page page, UserDTO userDTO) {return baseMapper.getUserVosPage(page, userDTO);}/*** 通过ID查询用户信息* @param id 用户ID* @return 用户信息*/@Overridepublic UserVO selectUserVoById(Long id) {return baseMapper.getUserVoById(id);}/*** 删除用户* @param sysUser 用户* @return Boolean*/@Override@CacheEvict(value = CommonConstants.USER_DETAILS, key = "#sysUser.username")public Boolean deleteUserById(SysUser sysUser) {sysUserRoleService.deleteByUserId(sysUser.getUserId());this.removeById(sysUser.getUserId());return Boolean.TRUE;}@Override@CacheEvict(value = CommonConstants.USER_DETAILS, key = "#userDto.username")public R<Boolean> updateUserInfo(UserDTO userDto) {UserVO userVO = baseMapper.getUserVoByUsername(userDto.getUsername());if (!ENCODER.matches(userDto.getPassword(), userVO.getPassword())) {log.info("原密码错误,修改个人信息失败:{}", userDto.getUsername());return R.failed(MsgUtils.getMessage(ErrorCodes.SYS_USER_UPDATE_PASSWORDERROR));}SysUser sysUser = new SysUser();if (StrUtil.isNotBlank(userDto.getNewpassword1())) {sysUser.setPassword(ENCODER.encode(userDto.getNewpassword1()));}sysUser.setPhone(userDto.getPhone());sysUser.setUserId(userVO.getUserId());sysUser.setAvatar(userDto.getAvatar());sysUser.setNickname(userDto.getNickname());sysUser.setName(userDto.getName());sysUser.setEmail(userDto.getEmail());return R.ok(this.updateById(sysUser));}@Override@Transactional(rollbackFor = Exception.class)@CacheEvict(value = CommonConstants.USER_DETAILS, key = "#userDto.username")public Boolean updateUser(UserDTO userDto) {SysUser sysUser = new SysUser();BeanUtils.copyProperties(userDto, sysUser);
// sysUser.setUpdateTime(new Date());sysUser.setUpdateTime(new Date());if (StrUtil.isNotBlank(userDto.getPassword())) {sysUser.setPassword(ENCODER.encode(userDto.getPassword()));}this.updateById(sysUser);sysUserRoleService.remove(Wrappers.<SysUserRole>update().lambda().eq(SysUserRole::getUserId, userDto.getUserId()));userDto.getRole().forEach(roleId -> {SysUserRole userRole = new SysUserRole();userRole.setUserId(sysUser.getUserId());userRole.setRoleId(roleId);userRole.insert();});return Boolean.TRUE;}/*** 查询上级部门的用户信息* @param username 用户名* @return R*/@Overridepublic List<SysUser> listAncestorUsers(String username) {SysUser sysUser = this.getOne(Wrappers.<SysUser>query().lambda().eq(SysUser::getUsername, username));SysDept sysDept = sysDeptService.getById(sysUser.getDeptId());if (sysDept == null) {return null;}Long parentId = sysDept.getParentId();return this.list(Wrappers.<SysUser>query().lambda().eq(SysUser::getDeptId, parentId));}/*** 锁定用户* @param username 用户名* @return*/@Override
// @CacheEvict(value = CommonConstants.USER_DETAILS, key = "#username")public R<Boolean> lockUser(String username) {SysUser sysUser = baseMapper.selectOne(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getUsername, username));sysUser.setLockFlag(CommonConstants.STATUS_LOCK);baseMapper.updateById(sysUser);return R.ok();}@Overridepublic List<SysUser> listUsersWithDeptName() {List<SysUser> sysUsers = this.list(Wrappers.<SysUser>lambdaQuery().eq(SysUser::getLockFlag, CommonConstants.STATUS_NORMAL));// 拼接部门信息if (CollUtil.isEmpty(sysUsers)) {return sysUsers;}List<SysDept> sysDepts = sysDeptService.list();sysUsers.forEach(user -> {SysDept sysDept = sysDepts.stream().filter(f -> f.getDeptId().equals(user.getDeptId())).findAny().get();user.setName(user.getName() + "-" + sysDept.getName());});return sysUsers;}@Overridepublic IPage getUserRolePage(Page page, UserVO userVO) {return baseMapper.getUserRolePage(page, userVO);}@Overridepublic List<UserVO> listUsersByRoleIds(List<Long> roleIds) {List<SysUserRole> userRoles = sysUserRoleService.list(Wrappers.<SysUserRole>lambdaQuery().in(SysUserRole::getRoleId,roleIds));List<Long> list = userRoles.stream().map(SysUserRole::getUserId).collect(Collectors.toList());if (CollUtil.isEmpty(list)) return Collections.emptyList();return this.listByIds(list).stream().map(m->{UserVO userVO = new UserVO();BeanUtil.copyProperties(m,userVO);List<Long> userRoleIds = userRoles.stream().filter(f -> f.getUserId().equals(m.getUserId())).map(SysUserRole::getRoleId).collect(Collectors.toList());List<SysRole> sysRoles = sysRoleService.listByIds(userRoleIds);userVO.setRoleList(sysRoles);return userVO;}).collect(Collectors.toList());}@Overridepublic List<SysUser> listUsersByRoleId(Long roleId) {List<Long> list = sysUserRoleService.list(Wrappers.<SysUserRole>lambdaQuery().eq(SysUserRole::getRoleId, roleId)).stream().map(SysUserRole::getUserId).collect(Collectors.toList());return CollUtil.isEmpty(list) ? Collections.emptyList() : this.list(Wrappers.<SysUser>lambdaQuery().in(SysUser::getUserId, list).eq(SysUser::getLockFlag, CommonConstants.STATUS_NORMAL));}}
10、SysUserService.java
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ewaycloud.jw.admin.api.dto.UserDTO;
import com.ewaycloud.jw.common.core.user.UserInfo;
import com.ewaycloud.jw.common.core.user.SysUser;
import com.ewaycloud.jw.admin.api.vo.UserVO;
import com.ewaycloud.jw.common.core.util.R;import java.util.List;/*** * @date 2017/10/31*/
public interface SysUserService extends IService<SysUser> {/*** 用户登录* @param username 用户名* @param password 密码* @return UserInfo*/UserInfo login(String username, String password);/*** 查询用户信息* @param sysUser 用户* @return userInfo*/UserInfo findUserInfo(SysUser sysUser);/*** 分页查询用户信息(含有角色信息)* @param page 分页对象* @param userDTO 参数列表* @return*/IPage getUsersWithRolePage(Page page, UserDTO userDTO);/*** 删除用户* @param sysUser 用户* @return boolean*/Boolean deleteUserById(SysUser sysUser);/*** 更新当前用户基本信息* @param userDto 用户信息* @return Boolean*/R<Boolean> updateUserInfo(UserDTO userDto);/*** 更新指定用户信息* @param userDto 用户信息* @return*/Boolean updateUser(UserDTO userDto);/*** 通过ID查询用户信息* @param id 用户ID* @return 用户信息*/UserVO selectUserVoById(Long id);/*** 查询上级部门的用户信息* @param username 用户名* @return R*/List<SysUser> listAncestorUsers(String username);/*** 保存用户信息* @param userDto DTO 对象* @return success/fail*/Boolean saveUser(UserDTO userDto);/*** 锁定用户* @param username* @return*/R<Boolean> lockUser(String username);/*** 查询租户所有用户携带部门名称*/List<SysUser> listUsersWithDeptName();/*** 查询选择办理人/角色分页** @param userVO 参数列表*/IPage getUserRolePage(Page page, UserVO userVO);/*** 通过角色ID查询用户集合** @param roleIds 角色ID* @return 用户信息*/List<UserVO> listUsersByRoleIds(List<Long> roleIds);/*** 通过角色ID查询用户集合** @param roleId 角色ID* @return 用户信息*/List<SysUser> listUsersByRoleId(Long roleId);}
11、前端:user.js
import {getStore, setStore} from '@/util/store'
import {isURL, validatenull} from '@/util/validate'
import {loginByUsername, getUserInfo, logout} from '@/api/login'
import {deepClone, encryption} from '@/util'
import webiste from '@/const/website'
import {getMenu, getTopMenu} from '@/api/admin/menu'function addPath(ele, first) {const menu = webiste.menuconst propsConfig = menu.propsconst propsDefault = {label: propsConfig.label || 'name',path: propsConfig.path || 'path',icon: propsConfig.icon || 'icon',children: propsConfig.children || 'children'}const icon = ele[propsDefault.icon]ele[propsDefault.icon] = validatenull(icon) ? menu.iconDefault : iconconst isChild = ele[propsDefault.children] && ele[propsDefault.children].length !== 0if (!isChild) ele[propsDefault.children] = []if (!isChild && first && !isURL(ele[propsDefault.path])) {ele[propsDefault.path] = ele[propsDefault.path] + '/index'} else {ele[propsDefault.children].forEach(child => {addPath(child)})}
}const user = {state: {userInfo: getStore({name: 'userInfo'}) || {},permissions: getStore({name: 'permissions'}) || [],roles: [],menu: getStore({name: 'menu'}) || [],menuAll: [],userId: getStore({name: 'userId'}) || ''},actions: {// 根据用户名登录LoginByUsername({commit}, userInfo) {let user = {}if (webiste.passwordEnc) {user = encryption({data: userInfo,key: '1234567887654321',param: ['password']})} else {user = userInfo}return new Promise((resolve, reject) => {loginByUsername(user.username, user.password).then(response => {const data = response.data.data || {}commit('SET_USER_INFO', data.sysUser)commit('SET_ROLES', data.roles || [])commit('SET_PERMISSIONS', data.permissions || [])commit('SET_USERID', data.sysUser.userId)commit('CLEAR_LOCK')commit('token', data.token)localStorage.setItem('areaName', data.areaName);localStorage.setItem('areaId', data.areaId);localStorage.setItem('token', data.token);resolve()}).catch(error => {reject(error)})})},// 查询用户信息GetUserInfo({commit}) {return new Promise((resolve, reject) => {getUserInfo().then((res) => {const data = res.data.data || {}commit('SET_USER_INFO', data.sysUser)commit('SET_ROLES', data.roles || [])commit('SET_PERMISSIONS', data.permissions || [])localStorage.setItem('areaName', data.areaName);resolve(data)}).catch(() => {reject()})})},// 登出LogOut({commit}) {return new Promise((resolve, reject) => {logout().then(() => {commit('SET_MENU', [])commit('SET_PERMISSIONS', [])commit('SET_USER_INFO', {})commit('SET_USERID', '')commit('SET_ROLES', [])commit('DEL_ALL_TAG')commit('CLEAR_LOCK')resolve()}).catch(error => {reject(error)})})},// 获取系统菜单GetMenu({commit}, obj) {// 记录用户点击顶部信息,保证刷新的时候不丢失commit('LIKE_TOP_MENUID', obj)return new Promise(resolve => {getMenu(obj.id).then((res) => {const data = res.data.dataconst menu = deepClone(data)menu.forEach(ele => {addPath(ele)})let type = obj.typecommit('SET_MENU', {type, menu})resolve(menu)}).catch(error => {reject(error)})})},//顶部菜单GetTopMenu() {return new Promise(resolve => {getTopMenu().then((res) => {const data = res.data.data || []resolve(data)}).catch(error => {reject(error)})})}},mutations: {SET_USERID: (state, userId) => {state.userId = userIdsetStore({name: 'userId',content: state.userId,type: 'session'})},SET_USER_INFO: (state, userInfo) => {state.userInfo = userInfosetStore({name: 'userInfo',content: userInfo,type: 'session'})},SET_MENU: (state, params = {}) => {let {menu, type} = params;if (type !== false) state.menu = menusetStore({name: 'menu',content: menu,type: 'session'})},SET_MENU_ALL: (state, menuAll) => {state.menuAll = menuAll},SET_ROLES: (state, roles) => {state.roles = roles},SET_PERMISSIONS: (state, permissions) => {const list = {}for (let i = 0; i < permissions.length; i++) {list[permissions[i]] = true}state.permissions = listsetStore({name: 'permissions',content: list,type: 'session'})}}}
export default user
12、前端:axios.js
import axios from 'axios'
import {paramsFilter,serialize
} from '@/util'
import NProgress from 'nprogress' // progress bar
import errorCode from '@/const/errorCode'
import {Message,MessageBox
} from 'element-ui'
import 'nprogress/nprogress.css'
import qs from 'qs'
import store from '@/store' // progress bar style
import * as aesSecure from "./aes/CryptoJS";
import {dataFilter
} from "@/const/flow";
import BigNumber from 'bignumber.js';axios.defaults.timeout = 300000
// 返回其他状态吗
axios.defaults.validateStatus = function(status) {return status >= 200 && status <= 500 // 默认的
}
// 跨域请求,允许保存cookie
axios.defaults.withCredentials = true
// NProgress Configuration
NProgress.configure({showSpinner: false
})// HTTPrequest拦截
axios.interceptors.request.use(config => {NProgress.start() // start progress barconst userId = store.getters.userIdif (userId) {// config.headers['USER-ID'] = userId // 用户IDconfig.headers['authorization'] = 'Bearer ' + localStorage.getItem('token') // token}if (aesSecure.dataAesEnabled === true) config.headers['Content-Type'] = "application/json;charset=UTF-8";// 校验参数、加密if (typeof config.data === 'object' && config.responseType !== "arraybuffer") {for (const dataKey in config.data) {if (typeof config.data[dataKey] === 'number' && !isNaN(config.data[dataKey])) {// console.log(dataKey)// console.log(config.data[dataKey])// console.log(new BigNumber(config.data[dataKey] + '').toString())config.data[dataKey] = new BigNumber(config.data[dataKey] + '');}}// 这里给后端传参的时候会删除是空的字段,导致只能修改字段,不能删除字段// if (aesSecure.dataAesEnabled === false) config.data = dataFilter(config.headers, config.data)// else config.data = aesSecure.Encrypt(JSON.stringify(dataFilter(config.headers, config.data)))}if (typeof config.params === 'object' && config.responseType !== "arraybuffer") config.params = dataFilter(config.headers, config.params)// serialize为true开启序列化if (config.method === 'post' && config.headers.serialize) {config.data = serialize(config.data)delete config.data.serialize}if (config.method === 'get') {config.paramsSerializer = function(params) {return qs.stringify(paramsFilter(params), {arrayFormat: 'repeat'})}}return config
}, error => {return Promise.reject(error)
})// HTTPresponse拦截
axios.interceptors.response.use(res => {NProgress.done()// 返回值解密if (aesSecure.dataAesEnabled === true && res.config.responseType !== "arraybuffer") res.data = JSON.parse(aesSecure.Decrypt(res.data));const status = Number(res.status) || 200const message = res.data.msg || errorCode[status] || errorCode['default']// 后台定义 424if (status === 424) {MessageBox.confirm('令牌状态已过期,请点击重新登录', '系统提示', {confirmButtonText: '重新登录',cancelButtonText: '取消',type: 'warning'}).then(() => {store.dispatch('LogOut').then(() => {// 刷新登录页面,避免多次弹框window.location.reload()})}).catch(() => {});return}if (status !== 200 || res.data.code === 1) {Message({message: message,type: 'error'})return Promise.reject(new Error(message))}return res
}, error => {// 处理 503 网络异常let response = error.response;if (response && response.status === 503) {Message({message: response.data.msg,type: 'error'})}NProgress.done()return Promise.reject(new Error(error))
})export default axios