feat: 优化Security
This commit is contained in:
parent
018c644d68
commit
5d44035a2f
@ -1,5 +1,6 @@
|
|||||||
package asia.yulinling.workflow.config;
|
package asia.yulinling.workflow.config;
|
||||||
|
|
||||||
|
import asia.yulinling.workflow.scope.RequestScopeData;
|
||||||
import asia.yulinling.workflow.security.*;
|
import asia.yulinling.workflow.security.*;
|
||||||
import asia.yulinling.workflow.utils.JwtUtil;
|
import asia.yulinling.workflow.utils.JwtUtil;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -34,6 +35,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
|
private final RequestScopeData scopeData;
|
||||||
private final JwtUserDetailsService jwtUserDetailsService;
|
private final JwtUserDetailsService jwtUserDetailsService;
|
||||||
private final JwtRbacAuthenticationService jwtRbacAuthenticationService;
|
private final JwtRbacAuthenticationService jwtRbacAuthenticationService;
|
||||||
|
|
||||||
@ -56,19 +58,19 @@ public class SecurityConfig {
|
|||||||
)
|
)
|
||||||
// 认证请求
|
// 认证请求
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/auth/**").permitAll()
|
.requestMatchers("/auth/**").permitAll()
|
||||||
.requestMatchers("/auth/register").permitAll()
|
.requestMatchers("/auth/register").permitAll()
|
||||||
.anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> {
|
.anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> {
|
||||||
HttpServletRequest request = requestAuthorizationContext.getRequest();
|
HttpServletRequest request = requestAuthorizationContext.getRequest();
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
return new AuthorizationDecision(
|
return new AuthorizationDecision(
|
||||||
jwtRbacAuthenticationService.hasPermission(request, authentication)
|
jwtRbacAuthenticationService.hasPermission(request, authentication)
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
// JWT过滤器
|
// JWT过滤器
|
||||||
.addFilterBefore(
|
.addFilterBefore(
|
||||||
new JwtAuthenticationFilter(jwtUtil, jwtUserDetailsService),
|
new JwtAuthenticationFilter(jwtUtil, scopeData, jwtUserDetailsService),
|
||||||
UsernamePasswordAuthenticationFilter.class
|
UsernamePasswordAuthenticationFilter.class
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,39 @@
|
|||||||
|
package asia.yulinling.workflow.dto.request;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 更新用户信息类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author YLL
|
||||||
|
* @since 2025/6/23
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UpdateUserRequest {
|
||||||
|
/**
|
||||||
|
* 主键id
|
||||||
|
*/
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 昵称
|
||||||
|
*/
|
||||||
|
private String nickname;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生日
|
||||||
|
*/
|
||||||
|
private String birthday;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 性别,男-1,女-2
|
||||||
|
*/
|
||||||
|
private Integer sex;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机号
|
||||||
|
*/
|
||||||
|
private String phone;
|
||||||
|
}
|
||||||
@ -4,13 +4,11 @@ import asia.yulinling.workflow.model.entity.Permission;
|
|||||||
import asia.yulinling.workflow.model.entity.Role;
|
import asia.yulinling.workflow.model.entity.Role;
|
||||||
import asia.yulinling.workflow.model.entity.User;
|
import asia.yulinling.workflow.model.entity.User;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.annotation.IdType;
|
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
@ -37,7 +35,6 @@ public class UserPrincipal implements UserDetails {
|
|||||||
/**
|
/**
|
||||||
* 主键id
|
* 主键id
|
||||||
*/
|
*/
|
||||||
@TableId(type = IdType.AUTO)
|
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,7 +50,6 @@ public class UserPrincipal implements UserDetails {
|
|||||||
/**
|
/**
|
||||||
* 加密后的密码
|
* 加密后的密码
|
||||||
*/
|
*/
|
||||||
@JsonIgnore
|
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -156,8 +152,6 @@ public class UserPrincipal implements UserDetails {
|
|||||||
List<Role> roles,
|
List<Role> roles,
|
||||||
List<Permission> permissions) {
|
List<Permission> permissions) {
|
||||||
|
|
||||||
log.info("roleNames{}\n{}authorities", roles, permissions);
|
|
||||||
|
|
||||||
List<String> roleNames = roles
|
List<String> roleNames = roles
|
||||||
.stream()
|
.stream()
|
||||||
.map(Role::getName)
|
.map(Role::getName)
|
||||||
@ -171,20 +165,12 @@ public class UserPrincipal implements UserDetails {
|
|||||||
new SimpleGrantedAuthority(permission.getPermission()))
|
new SimpleGrantedAuthority(permission.getPermission()))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
return new UserPrincipal(
|
UserPrincipal userPrincipal = new UserPrincipal();
|
||||||
user.getId(),
|
BeanUtils.copyProperties(user, userPrincipal);
|
||||||
user.getUsername(),
|
userPrincipal.setRoles(roleNames);
|
||||||
user.getPassword(),
|
userPrincipal.setAuthorities(authorities);
|
||||||
user.getNickname(),
|
|
||||||
user.getPhone(),
|
return userPrincipal;
|
||||||
user.getEmail(),
|
|
||||||
user.getBirthday(),
|
|
||||||
user.getSex(),
|
|
||||||
user.getStatus(),
|
|
||||||
user.getCreateTime(),
|
|
||||||
user.getUpdateTime(),
|
|
||||||
roleNames,
|
|
||||||
authorities);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import lombok.Data;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 用户信息VO
|
* 用户信息VO
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author YLL
|
* @author YLL
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
package asia.yulinling.workflow.scope;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.annotation.RequestScope;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 请求生命周期的全局数据
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author YLL
|
||||||
|
* @since 2025/6/23
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequestScope
|
||||||
|
@Data
|
||||||
|
public class RequestScopeData {
|
||||||
|
private String token;
|
||||||
|
private Long userId;
|
||||||
|
private boolean isLogin;
|
||||||
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
package asia.yulinling.workflow.security;
|
package asia.yulinling.workflow.security;
|
||||||
|
|
||||||
import asia.yulinling.workflow.exception.SecurityException;
|
import asia.yulinling.workflow.exception.SecurityException;
|
||||||
import asia.yulinling.workflow.constant.Status;
|
|
||||||
import asia.yulinling.workflow.model.vo.user.UserPrincipal;
|
import asia.yulinling.workflow.model.vo.user.UserPrincipal;
|
||||||
|
import asia.yulinling.workflow.scope.RequestScopeData;
|
||||||
import asia.yulinling.workflow.utils.JwtUtil;
|
import asia.yulinling.workflow.utils.JwtUtil;
|
||||||
import asia.yulinling.workflow.utils.ResponseUtil;
|
import asia.yulinling.workflow.utils.ResponseUtil;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
@ -32,6 +32,7 @@ import java.io.IOException;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
||||||
private final JwtUtil jwtUtil;
|
private final JwtUtil jwtUtil;
|
||||||
|
private final RequestScopeData scopeData;
|
||||||
private final JwtUserDetailsService jwtUserDetailsService;
|
private final JwtUserDetailsService jwtUserDetailsService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -45,7 +46,12 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) {
|
if (StringUtils.hasText(token) && jwtUtil.validateToken(token)) {
|
||||||
try {
|
try {
|
||||||
// 2. 解析token获取username
|
// 2. 解析token获取username
|
||||||
String username = jwtUtil.parseToken(token).getSubject();
|
String username = jwtUtil.getUsernameByToken(token);
|
||||||
|
Long userId = jwtUtil.getUserIdByToken(token);
|
||||||
|
|
||||||
|
scopeData.setUserId(userId);
|
||||||
|
scopeData.setToken(token);
|
||||||
|
scopeData.setLogin(true);
|
||||||
|
|
||||||
// 3. 根据username验证password
|
// 3. 根据username验证password
|
||||||
UserPrincipal userPrincipal = jwtUserDetailsService.loadUserByUsername(username);
|
UserPrincipal userPrincipal = jwtUserDetailsService.loadUserByUsername(username);
|
||||||
@ -57,11 +63,12 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
|
||||||
|
|
||||||
} catch (SecurityException e) {
|
} catch (SecurityException e) {
|
||||||
log.error("Security异常:{}", e.getMessage());
|
log.error("Security异常:{}", e.getMessage());
|
||||||
ResponseUtil.renderJson(response, e);
|
ResponseUtil.renderJson(response, e);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
scopeData.setLogin(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import org.springframework.security.core.Authentication;
|
|||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.AntPathMatcher;
|
import org.springframework.util.AntPathMatcher;
|
||||||
import org.springframework.util.StringUtils;
|
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
|
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
|
||||||
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
|
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
|
||||||
@ -57,8 +56,8 @@ public class JwtRbacAuthenticationService {
|
|||||||
|
|
||||||
List<Permission> pagePerms = permissions.stream()
|
List<Permission> pagePerms = permissions.stream()
|
||||||
.filter(permission -> Objects.equals(permission.getType(), 1))
|
.filter(permission -> Objects.equals(permission.getType(), 1))
|
||||||
.filter(permission -> !StringUtils.isEmpty(permission.getUrl()))
|
.filter(permission -> !permission.getUrl().isEmpty())
|
||||||
.filter(permission -> !StringUtils.isEmpty(permission.getMethod()))
|
.filter(permission -> !permission.getMethod().isEmpty())
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
for (Permission permission : pagePerms) {
|
for (Permission permission : pagePerms) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package asia.yulinling.workflow.security;
|
|||||||
|
|
||||||
import asia.yulinling.workflow.mapper.PermissionMapper;
|
import asia.yulinling.workflow.mapper.PermissionMapper;
|
||||||
import asia.yulinling.workflow.mapper.RoleMapper;
|
import asia.yulinling.workflow.mapper.RoleMapper;
|
||||||
import asia.yulinling.workflow.mapper.RoleUserMapper;
|
|
||||||
import asia.yulinling.workflow.mapper.UserMapper;
|
import asia.yulinling.workflow.mapper.UserMapper;
|
||||||
import asia.yulinling.workflow.model.entity.Permission;
|
import asia.yulinling.workflow.model.entity.Permission;
|
||||||
import asia.yulinling.workflow.model.entity.Role;
|
import asia.yulinling.workflow.model.entity.Role;
|
||||||
@ -12,6 +11,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
@ -33,7 +33,6 @@ import java.util.stream.Collectors;
|
|||||||
public class JwtUserDetailsService implements UserDetailsService {
|
public class JwtUserDetailsService implements UserDetailsService {
|
||||||
private final UserMapper userMapper;
|
private final UserMapper userMapper;
|
||||||
private final RoleMapper roleMapper;
|
private final RoleMapper roleMapper;
|
||||||
private final RoleUserMapper roleUserMapper;
|
|
||||||
private final PermissionMapper permissionMapper;
|
private final PermissionMapper permissionMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -53,21 +52,20 @@ public class JwtUserDetailsService implements UserDetailsService {
|
|||||||
log.error("未找到用户信息{}", username);
|
log.error("未找到用户信息{}", username);
|
||||||
throw new UsernameNotFoundException("未找到用户信息:" + username);
|
throw new UsernameNotFoundException("未找到用户信息:" + username);
|
||||||
}
|
}
|
||||||
log.info("username:{}", username);
|
|
||||||
|
|
||||||
// 3. 查找用户对应的角色
|
// 3. 查找用户对应的角色
|
||||||
List<Role> roles = roleMapper.selectRoleByUserId(user.getId());
|
List<Role> roles = roleMapper.selectRoleByUserId(user.getId());
|
||||||
|
|
||||||
if (roles.isEmpty()) {
|
if (roles.isEmpty()) {
|
||||||
log.error("未找到角色信息{}", roles);
|
log.error("未找到角色信息{}", roles);
|
||||||
throw new UsernameNotFoundException("未找到角色信息" + roles);
|
throw new AccessDeniedException("未找到角色信息" + roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Permission> permissions = permissionMapper.selectPermissionsByRoleId(roles.stream().map(Role::getId).collect(Collectors.toList()));
|
List<Permission> permissions = permissionMapper.selectPermissionsByRoleId(roles.stream().map(Role::getId).collect(Collectors.toList()));
|
||||||
|
|
||||||
if (permissions.isEmpty()) {
|
if (permissions.isEmpty()) {
|
||||||
log.error("未找到权限信息{}", permissions);
|
log.error("未找到权限信息{}", permissions);
|
||||||
throw new UsernameNotFoundException("未找到权限信息" + permissions);
|
throw new AccessDeniedException("未找到权限信息" + permissions);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 返回User
|
// 4. 返回User
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
package asia.yulinling.workflow.service;
|
package asia.yulinling.workflow.service;
|
||||||
|
|
||||||
import asia.yulinling.workflow.dto.request.PageParam;
|
import asia.yulinling.workflow.dto.request.PageParam;
|
||||||
import asia.yulinling.workflow.model.ApiResponse;
|
import asia.yulinling.workflow.dto.request.UpdateUserRequest;
|
||||||
import asia.yulinling.workflow.dto.response.PageResult;
|
import asia.yulinling.workflow.dto.response.PageResult;
|
||||||
|
import asia.yulinling.workflow.model.ApiResponse;
|
||||||
import asia.yulinling.workflow.model.vo.user.UserVO;
|
import asia.yulinling.workflow.model.vo.user.UserVO;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
@ -24,4 +25,12 @@ public interface UserService {
|
|||||||
* @return 用户列表
|
* @return 用户列表
|
||||||
*/
|
*/
|
||||||
ApiResponse<PageResult<UserVO>> getUserListByPage(PageParam pageParam);
|
ApiResponse<PageResult<UserVO>> getUserListByPage(PageParam pageParam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户信息
|
||||||
|
*
|
||||||
|
* @param request UpdateUserRequest
|
||||||
|
* @return 更新状态
|
||||||
|
*/
|
||||||
|
ApiResponse<?> updateUserInfo(UpdateUserRequest request);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,23 @@
|
|||||||
package asia.yulinling.workflow.service.impl;
|
package asia.yulinling.workflow.service.impl;
|
||||||
|
|
||||||
import asia.yulinling.workflow.dto.request.PageParam;
|
import asia.yulinling.workflow.dto.request.PageParam;
|
||||||
|
import asia.yulinling.workflow.dto.request.UpdateUserRequest;
|
||||||
|
import asia.yulinling.workflow.dto.response.PageResult;
|
||||||
import asia.yulinling.workflow.mapper.UserMapper;
|
import asia.yulinling.workflow.mapper.UserMapper;
|
||||||
import asia.yulinling.workflow.model.ApiResponse;
|
import asia.yulinling.workflow.model.ApiResponse;
|
||||||
import asia.yulinling.workflow.dto.response.PageResult;
|
|
||||||
import asia.yulinling.workflow.model.entity.User;
|
import asia.yulinling.workflow.model.entity.User;
|
||||||
import asia.yulinling.workflow.model.vo.user.UserVO;
|
import asia.yulinling.workflow.model.vo.user.UserVO;
|
||||||
|
import asia.yulinling.workflow.scope.RequestScopeData;
|
||||||
import asia.yulinling.workflow.service.UserService;
|
import asia.yulinling.workflow.service.UserService;
|
||||||
import asia.yulinling.workflow.utils.PageUtil;
|
import asia.yulinling.workflow.utils.PageUtil;
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -32,6 +37,7 @@ public class UserServiceImpl implements UserService {
|
|||||||
|
|
||||||
/** 注入用户Mapper */
|
/** 注入用户Mapper */
|
||||||
private final UserMapper userMapper;
|
private final UserMapper userMapper;
|
||||||
|
private final RequestScopeData scopeData;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户列表分页
|
* 获取用户列表分页
|
||||||
@ -65,4 +71,41 @@ public class UserServiceImpl implements UserService {
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新用户信息
|
||||||
|
*
|
||||||
|
* @param request UpdateUserRequest
|
||||||
|
* @return 更新状态
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public ApiResponse<?> updateUserInfo(UpdateUserRequest request) {
|
||||||
|
|
||||||
|
Long userId = scopeData.getUserId();
|
||||||
|
Long requestUserId = request.getId();
|
||||||
|
|
||||||
|
if (!requestUserId.equals(userId)) {
|
||||||
|
log.error("user id not match, scopeData: {}, requestUserId: {}", requestUserId, userId);
|
||||||
|
throw new RuntimeException("用户Id不匹配");
|
||||||
|
}
|
||||||
|
|
||||||
|
User user = new User();
|
||||||
|
BeanUtils.copyProperties(request, user);
|
||||||
|
LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
|
||||||
|
userLambdaUpdateWrapper.eq(User::getId, userId);
|
||||||
|
|
||||||
|
userLambdaUpdateWrapper.set(StringUtils.hasText(request.getNickname()), User::getNickname, request.getNickname());
|
||||||
|
userLambdaUpdateWrapper.set(StringUtils.hasText(request.getBirthday()), User::getBirthday, request.getBirthday());
|
||||||
|
userLambdaUpdateWrapper.set(request.getSex() != null, User::getSex, request.getSex());
|
||||||
|
userLambdaUpdateWrapper.set(StringUtils.hasText(request.getPhone()), User::getPhone, request.getPhone());
|
||||||
|
|
||||||
|
try {
|
||||||
|
userMapper.update(userLambdaUpdateWrapper);
|
||||||
|
return ApiResponse.ofSuccess("更新成功");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("update user error:{}", e.getMessage());
|
||||||
|
return ApiResponse.ofSuccess("更新失败");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package asia.yulinling.workflow.utils;
|
|||||||
import asia.yulinling.workflow.constant.Const;
|
import asia.yulinling.workflow.constant.Const;
|
||||||
import asia.yulinling.workflow.constant.Status;
|
import asia.yulinling.workflow.constant.Status;
|
||||||
import asia.yulinling.workflow.exception.SecurityException;
|
import asia.yulinling.workflow.exception.SecurityException;
|
||||||
|
import asia.yulinling.workflow.model.vo.user.UserPrincipal;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import io.jsonwebtoken.*;
|
||||||
import io.jsonwebtoken.io.Decoders;
|
import io.jsonwebtoken.io.Decoders;
|
||||||
import io.jsonwebtoken.security.Keys;
|
import io.jsonwebtoken.security.Keys;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
@ -13,7 +15,6 @@ import org.jetbrains.annotations.Nullable;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import io.jsonwebtoken.*;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
@ -59,6 +60,27 @@ public class JwtUtil {
|
|||||||
* @return JWT
|
* @return JWT
|
||||||
*/
|
*/
|
||||||
public String generateToken(Authentication authentication, boolean isRememberMe) {
|
public String generateToken(Authentication authentication, boolean isRememberMe) {
|
||||||
|
// 1. 解析principal
|
||||||
|
Object principal = authentication.getPrincipal();
|
||||||
|
Long userId = null;
|
||||||
|
String username = null;
|
||||||
|
if (principal instanceof UserPrincipal) {
|
||||||
|
userId = ((UserPrincipal) principal).getId();
|
||||||
|
username = ((UserPrincipal) principal).getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
return generateToken(userId, username, isRememberMe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建JWT
|
||||||
|
*
|
||||||
|
* @param userId 用户Id
|
||||||
|
* @param username 用户名
|
||||||
|
* @param isRememberMe 记住我
|
||||||
|
* @return JWT
|
||||||
|
*/
|
||||||
|
public String generateToken(Long userId, String username, boolean isRememberMe) {
|
||||||
// 1. 当前时间
|
// 1. 当前时间
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|
||||||
@ -66,18 +88,20 @@ public class JwtUtil {
|
|||||||
long ttl = isRememberMe ? this.remember : this.ttl;
|
long ttl = isRememberMe ? this.remember : this.ttl;
|
||||||
Date expiration = new Date(now.getTime() + ttl);
|
Date expiration = new Date(now.getTime() + ttl);
|
||||||
|
|
||||||
// 3. 构建 JWT
|
// 3. 构建JwtBuilder
|
||||||
String username = authentication.getName();
|
|
||||||
JwtBuilder builder = Jwts.builder()
|
JwtBuilder builder = Jwts.builder()
|
||||||
.setSubject(username)
|
.setSubject(username)
|
||||||
|
.claim("userId", userId)
|
||||||
.setIssuedAt(now)
|
.setIssuedAt(now)
|
||||||
.setExpiration(expiration)
|
.setExpiration(expiration)
|
||||||
.signWith(this.key());
|
.signWith(this.key());
|
||||||
|
|
||||||
// 4. 生成token
|
// 4. 生成token
|
||||||
String token = builder.compact();
|
String token = builder.compact();
|
||||||
|
|
||||||
// 5. 将token存入redis
|
// 5. 将token存入redis
|
||||||
stringRedisTemplate.opsForValue().set(Const.REDIS_JWT_KEY_PREFIX + username, token, ttl, TimeUnit.SECONDS);
|
stringRedisTemplate.opsForValue().set(Const.REDIS_JWT_KEY_PREFIX + username, token, ttl, TimeUnit.SECONDS);
|
||||||
|
|
||||||
// 6. 返回生成的token
|
// 6. 返回生成的token
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
@ -122,6 +146,16 @@ public class JwtUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Long getUserIdByToken(String token) {
|
||||||
|
Claims claims = parseToken(token);
|
||||||
|
return (Long) claims.get("userId");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsernameByToken(String token) {
|
||||||
|
Claims claims = parseToken(token);
|
||||||
|
return claims.getSubject();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验Token
|
* 校验Token
|
||||||
*
|
*
|
||||||
|
|||||||
@ -1,24 +1,22 @@
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379288399872, '测试页面', '/test', 1, 'page:test', 'GET', 1, 0);
|
VALUES (1072806379288399872, '测试页面', '/test', 1, 'page:test', 'GET', 1, 0, NULL, NULL);
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379313565696, '测试页面-查询', '/**/test', 2, 'btn:test:query', 'GET', 1, 1072806379288399872);
|
VALUES (1072806379313565696, '测试页面-查询', '/**/test', 2, 'btn:test:query', 'GET', 1, 1072806379288399872, NULL,
|
||||||
|
NULL);
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379330342912, '测试页面-添加', '/**/test', 2, 'btn:test:insert', 'POST', 2, 1072806379288399872);
|
VALUES (1072806379330342912, '测试页面-添加', '/**/test', 2, 'btn:test:insert', 'POST', 2, 1072806379288399872, NULL,
|
||||||
|
NULL);
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379342925824, '监控在线用户页面', '/monitor', 1, 'page:monitor:online', NULL, 2, 0);
|
VALUES (1072806379342925824, '监控在线用户页面', '/monitor', 1, 'page:monitor:online', NULL, 2, 0, NULL, NULL);
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379363897344, '在线用户页面-查询', '/**/api/monitor/online/user', 2, 'btn:monitor:online:query', 'GET',
|
VALUES (1072806379363897344, '在线用户页面-查询', '/**/api/monitor/online/user', 2, 'btn:monitor:online:query', 'GET',
|
||||||
1,
|
1, 1072806379342925824, NULL, NULL);
|
||||||
1072806379342925824);
|
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379384868864, '在线用户页面-踢出', '/**/api/monitor/online/user/kickout', 2,
|
VALUES (1072806379384868864, '在线用户页面-踢出', '/**/api/monitor/online/user/kickout', 2,
|
||||||
'btn:monitor:online:kickout',
|
'btn:monitor:online:kickout', 'DELETE', 2, 1072806379342925824, NULL, NULL);
|
||||||
'DELETE', 2, 1072806379342925824);
|
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379384868865, '用户列表', '/users', 1,
|
VALUES (1072806379384868865, '用户列表', '/users', 1, 'page:test', 'GET', 1, 0, NULL, NULL);
|
||||||
'page:test',
|
|
||||||
'GET', 1, 0);
|
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|||||||
@ -21,11 +21,6 @@ public class UserServiceTest extends WorkFlowMainTests {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
@Test
|
|
||||||
public void getUserList() {
|
|
||||||
ApiResponse<PageResult<UserVO>> users = userService.getUserList();
|
|
||||||
Assertions.assertEquals(200, users.getCode().intValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getUserListByPage() {
|
public void getUserListByPage() {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user