#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_key
private 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);
}
@Override
protected 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);
@Override
public 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 参数解析器
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolverList) {
resolverList.add(new SqlFilterArgumentResolver());
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(webGlobalInterceptor()).addPathPatterns("/**")
.excludePathPatterns("/user/login","/user/logout");
}
@Bean
public 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() {
// 获取传递的token
String 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 {
@Override
protected 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;
@Resource
private SysLogInfoService sysLogInfoService;
@Resource
private 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")) {
// 根据网卡取本机配置的IP
InetAddress 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
*/
@PostMapping
public 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
*/
@PutMapping
public 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);
}
@Override
public 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查询用户的areaId
UserVO 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*1000
MyCacheManager.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
*/
@Override
public 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
*/
@Override
public IPage getUsersWithRolePage(Page page, UserDTO userDTO) {
return baseMapper.getUserVosPage(page, userDTO);
}
/**
* 通过ID查询用户信息
* @param id 用户ID
* @return 用户信息
*/
@Override
public 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
*/
@Override
public 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();
}
@Override
public 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;
}
@Override
public IPage getUserRolePage(Page page, UserVO userVO) {
return baseMapper.getUserRolePage(page, userVO);
}
@Override
public 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());
}
@Override
public 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.menu
const propsConfig = menu.props
const 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 : icon
const isChild = ele[propsDefault.children] && ele[propsDefault.children].length !== 0
if (!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.data
const menu = deepClone(data)
menu.forEach(ele => {
addPath(ele)
})
let type = obj.type
commit('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 = userId
setStore({
name: 'userId',
content: state.userId,
type: 'session'
})
},
SET_USER_INFO: (state, userInfo) => {
state.userInfo = userInfo
setStore({
name: 'userInfo',
content: userInfo,
type: 'session'
})
},
SET_MENU: (state, params = {}) => {
let {menu, type} = params;
if (type !== false) state.menu = menu
setStore({
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 = list
setStore({
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 bar
const userId = store.getters.userId
if (userId) {
// config.headers['USER-ID'] = userId // 用户ID
config.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) || 200
const message = res.data.msg || errorCode[status] || errorCode['default']
// 后台定义 424
if (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