diff --git a/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java b/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java index 21411fe..3520cb5 100644 --- a/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java +++ b/src/main/java/asia/yulinling/workflow/config/SecurityConfig.java @@ -5,7 +5,6 @@ import asia.yulinling.workflow.security.JwtAuthenticationEntryPoint; import asia.yulinling.workflow.security.JwtAuthenticationFilter; import asia.yulinling.workflow.security.JwtUserDetailsService; import asia.yulinling.workflow.utils.JwtUtil; -import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; @@ -48,7 +47,7 @@ public class SecurityConfig { // 认证请求 .authorizeHttpRequests(auth -> auth .requestMatchers("/login").permitAll() - .requestMatchers("/users", "/users/**").hasRole("ADMIN") +// .requestMatchers("/users", "/users/**").hasRole("ADMIN") .anyRequest().authenticated() ) // JWT过滤器 diff --git a/src/main/java/asia/yulinling/workflow/mapper/PermissionMapper.java b/src/main/java/asia/yulinling/workflow/mapper/PermissionMapper.java index 249b112..d5ac382 100644 --- a/src/main/java/asia/yulinling/workflow/mapper/PermissionMapper.java +++ b/src/main/java/asia/yulinling/workflow/mapper/PermissionMapper.java @@ -3,8 +3,11 @@ package asia.yulinling.workflow.mapper; import asia.yulinling.workflow.model.entity.Permission; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Component; +import java.util.List; + /** *

* @@ -16,4 +19,5 @@ import org.springframework.stereotype.Component; @Mapper @Component public interface PermissionMapper extends BaseMapper { + List selectPermissionsByRoleId(@Param("roleIds") List roleIds); } diff --git a/src/main/java/asia/yulinling/workflow/mapper/RoleMapper.java b/src/main/java/asia/yulinling/workflow/mapper/RoleMapper.java index 62b0688..3030309 100644 --- a/src/main/java/asia/yulinling/workflow/mapper/RoleMapper.java +++ b/src/main/java/asia/yulinling/workflow/mapper/RoleMapper.java @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Component; +import java.util.List; + /** *

* 角色Mapper @@ -16,4 +18,5 @@ import org.springframework.stereotype.Component; @Mapper @Component public interface RoleMapper extends BaseMapper { + List selectRoleByUserId(Long userId); } diff --git a/src/main/java/asia/yulinling/workflow/mapper/RolePermissionMapper.java b/src/main/java/asia/yulinling/workflow/mapper/RolePermissionMapper.java new file mode 100644 index 0000000..2dd3d29 --- /dev/null +++ b/src/main/java/asia/yulinling/workflow/mapper/RolePermissionMapper.java @@ -0,0 +1,19 @@ +package asia.yulinling.workflow.mapper; + +import asia.yulinling.workflow.model.entity.RolePermission; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Component; + +/** + *

+ * 角色权限类 + *

+ * + * @author YLL + * @since 2025/6/15 + */ +@Mapper +@Component +public interface RolePermissionMapper extends BaseMapper { +} diff --git a/src/main/java/asia/yulinling/workflow/mapper/RoleUserMapper.java b/src/main/java/asia/yulinling/workflow/mapper/RoleUserMapper.java new file mode 100644 index 0000000..62cd248 --- /dev/null +++ b/src/main/java/asia/yulinling/workflow/mapper/RoleUserMapper.java @@ -0,0 +1,19 @@ +package asia.yulinling.workflow.mapper; + +import asia.yulinling.workflow.model.entity.RoleUser; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import org.apache.ibatis.annotations.Mapper; +import org.springframework.stereotype.Component; + +/** + *

+ * 角色用户类 + *

+ * + * @author YLL + * @since 2025/6/15 + */ +@Mapper +@Component +public interface RoleUserMapper extends BaseMapper { +} diff --git a/src/main/java/asia/yulinling/workflow/model/vo/user/UserPrincipal.java b/src/main/java/asia/yulinling/workflow/model/vo/user/UserPrincipal.java index 8c92d2f..b534816 100644 --- a/src/main/java/asia/yulinling/workflow/model/vo/user/UserPrincipal.java +++ b/src/main/java/asia/yulinling/workflow/model/vo/user/UserPrincipal.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; @@ -30,6 +31,7 @@ import java.util.stream.Collectors; @Data @NoArgsConstructor @AllArgsConstructor +@Slf4j public class UserPrincipal implements UserDetails { /** @@ -104,7 +106,19 @@ public class UserPrincipal implements UserDetails { */ private Collection authorities; - public UserPrincipal(Long id, String username, String password, String nickname, String phone, String email, String birthday, Integer sex, Integer status, Date createTime, Date updateTime, List roleNames, List authorities) { + public UserPrincipal(Long id, + String username, + String password, + String nickname, + String phone, + String email, + String birthday, + Integer sex, + Integer status, + Date createTime, + Date updateTime, + List roleNames, + List authorities) { this.id = id; this.username = username; this.password = password; @@ -125,22 +139,52 @@ public class UserPrincipal implements UserDetails { return List.of(); } - public UserPrincipal(Long id, String username, String password, - List roles, Collection authorities) { + public UserPrincipal(Long id, + String username, + String password, + List roles, + Collection authorities) { this.id = id; this.username = username; this.password = password; this.roles = roles; this.authorities = authorities; - this.status = 1; // 启用 + this.status = 1; } - public static UserPrincipal create(User user, List roles, List permissions) { - List roleNames = roles.stream().map(Role::getName).collect(Collectors.toList()); + public static UserPrincipal create(User user, + List roles, + List permissions) { - List authorities = permissions.stream().filter(permission -> StrUtil.isNotBlank(permission.getPermission())).map(permission -> new SimpleGrantedAuthority(permission.getPermission())).collect(Collectors.toList()); + log.info("roleNames{}\n{}authorities", roles, permissions); - return new UserPrincipal(user.getId(), user.getUsername(), user.getPassword(), user.getNickname(), user.getPhone(), user.getEmail(), user.getBirthday(), user.getSex(), user.getStatus(), user.getCreateTime(), user.getUpdateTime(), roleNames, authorities); + List roleNames = roles + .stream() + .map(Role::getName) + .collect(Collectors.toList()); + + List authorities = permissions + .stream() + .filter(permission -> + StrUtil.isNotBlank(permission.getPermission())) + .map(permission -> + new SimpleGrantedAuthority(permission.getPermission())) + .collect(Collectors.toList()); + + return new UserPrincipal( + user.getId(), + user.getUsername(), + user.getPassword(), + user.getNickname(), + user.getPhone(), + user.getEmail(), + user.getBirthday(), + user.getSex(), + user.getStatus(), + user.getCreateTime(), + user.getUpdateTime(), + roleNames, + authorities); } @@ -161,12 +205,12 @@ public class UserPrincipal implements UserDetails { @Override public boolean isAccountNonLocked() { - return true; + return UserDetails.super.isAccountNonLocked(); } @Override public boolean isCredentialsNonExpired() { - return true; + return UserDetails.super.isCredentialsNonExpired(); } @Override diff --git a/src/main/java/asia/yulinling/workflow/security/JwtAccessDeniedHandler.java b/src/main/java/asia/yulinling/workflow/security/JwtAccessDeniedHandler.java index 02a1d3d..97b892d 100644 --- a/src/main/java/asia/yulinling/workflow/security/JwtAccessDeniedHandler.java +++ b/src/main/java/asia/yulinling/workflow/security/JwtAccessDeniedHandler.java @@ -3,7 +3,6 @@ package asia.yulinling.workflow.security; import asia.yulinling.workflow.exception.BaseException; import asia.yulinling.workflow.model.ApiResponse; import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.security.access.AccessDeniedException; diff --git a/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationFilter.java b/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationFilter.java index e528a0f..e396e60 100644 --- a/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationFilter.java +++ b/src/main/java/asia/yulinling/workflow/security/JwtAuthenticationFilter.java @@ -1,5 +1,6 @@ package asia.yulinling.workflow.security; +import asia.yulinling.workflow.model.vo.user.UserPrincipal; import asia.yulinling.workflow.utils.JwtUtil; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; @@ -8,11 +9,8 @@ import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; @@ -31,7 +29,7 @@ import java.io.IOException; @Slf4j public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtUtil jwtUtil; - private final UserDetailsService userDetailsService; + private final JwtUserDetailsService jwtUserDetailsService; @Override protected void doFilterInternal(@NotNull HttpServletRequest request, @@ -46,11 +44,11 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { String username = jwtUtil.parseToken(token).getSubject(); // 3. 根据username验证password - UserDetails userDetails = userDetailsService.loadUserByUsername(username); - log.info("userDetails: {}", userDetails); + UserPrincipal userPrincipal = jwtUserDetailsService.loadUserByUsername(username); + log.info("userPrincipal: {}", userPrincipal); UsernamePasswordAuthenticationToken authenticationToken - = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); + = new UsernamePasswordAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities()); log.info("authenticationToken: {}", authenticationToken); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); diff --git a/src/main/java/asia/yulinling/workflow/security/JwtUserDetailsService.java b/src/main/java/asia/yulinling/workflow/security/JwtUserDetailsService.java index c32006a..3f86786 100644 --- a/src/main/java/asia/yulinling/workflow/security/JwtUserDetailsService.java +++ b/src/main/java/asia/yulinling/workflow/security/JwtUserDetailsService.java @@ -1,23 +1,22 @@ package asia.yulinling.workflow.security; +import asia.yulinling.workflow.mapper.PermissionMapper; import asia.yulinling.workflow.mapper.RoleMapper; +import asia.yulinling.workflow.mapper.RoleUserMapper; import asia.yulinling.workflow.mapper.UserMapper; +import asia.yulinling.workflow.model.entity.Permission; import asia.yulinling.workflow.model.entity.Role; import asia.yulinling.workflow.model.entity.User; +import asia.yulinling.workflow.model.vo.user.UserPrincipal; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.util.Collections; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; /** @@ -34,41 +33,45 @@ import java.util.stream.Collectors; public class JwtUserDetailsService implements UserDetailsService { private final UserMapper userMapper; private final RoleMapper roleMapper; + private final RoleUserMapper roleUserMapper; + private final PermissionMapper permissionMapper; @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + public UserPrincipal loadUserByUsername(String username) throws UsernameNotFoundException { // 1. 构建查找sql LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(User.class) - .eq(User::getUsername, username) - .or() - .eq(User::getEmail, username) - .or() - .eq(User::getPhone, username); + .eq(User::getUsername, username) + .or() + .eq(User::getEmail, username) + .or() + .eq(User::getPhone, username); // 2. 查找用户 User user = userMapper.selectOne(queryWrapper); if (user == null) { + log.error("未找到用户信息{}", username); throw new UsernameNotFoundException("未找到用户信息:" + username); } + log.info("username:{}", username); // 3. 查找用户对应的角色 - List roles = roleMapper.selectByIds(Collections.singleton(user.getId())); + List roles = roleMapper.selectRoleByUserId(user.getId()); if (roles.isEmpty()) { + log.error("未找到角色信息{}", roles); throw new UsernameNotFoundException("未找到角色信息" + roles); } - Set authorities = roles.stream() - .map((role) -> new SimpleGrantedAuthority(role.getName())) - .collect(Collectors.toSet()); + List permissions = permissionMapper.selectPermissionsByRoleId(roles.stream().map(Role::getId).collect(Collectors.toList())); + + if (permissions.isEmpty()) { + log.error("未找到权限信息{}", permissions); + throw new UsernameNotFoundException("未找到权限信息" + permissions); + } // 4. 返回User - return new org.springframework.security.core.userdetails.User( - username, - user.getPassword(), - authorities - ); + return UserPrincipal.create(user, roles, permissions); } } diff --git a/src/main/resources/mapper/PermissionMapper.xml b/src/main/resources/mapper/PermissionMapper.xml new file mode 100644 index 0000000..c06be18 --- /dev/null +++ b/src/main/resources/mapper/PermissionMapper.xml @@ -0,0 +1,14 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/RoleMapper.xml b/src/main/resources/mapper/RoleMapper.xml new file mode 100644 index 0000000..f12b551 --- /dev/null +++ b/src/main/resources/mapper/RoleMapper.xml @@ -0,0 +1,11 @@ + + + + + \ No newline at end of file