Compare commits
2 Commits
5a6402f7fd
...
9239ad51a6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9239ad51a6 | ||
|
|
8935c9f0c5 |
@ -1,20 +1,20 @@
|
|||||||
package asia.yulinling.workflow.config;
|
package asia.yulinling.workflow.config;
|
||||||
|
|
||||||
import asia.yulinling.workflow.security.JwtAccessDeniedHandler;
|
import asia.yulinling.workflow.security.*;
|
||||||
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 asia.yulinling.workflow.utils.JwtUtil;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
|
import org.springframework.security.authorization.AuthorizationDecision;
|
||||||
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
|
||||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
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.EnableWebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
@ -27,6 +27,7 @@ import org.springframework.security.web.authentication.UsernamePasswordAuthentic
|
|||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
|
||||||
private final JwtUserDetailsService jwtUserDetailsService;
|
private final JwtUserDetailsService jwtUserDetailsService;
|
||||||
|
private final JwtRbacAuthenticationService jwtRbacAuthenticationService;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtUtil jwtUtil,
|
public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtUtil jwtUtil,
|
||||||
@ -47,16 +48,21 @@ public class SecurityConfig {
|
|||||||
)
|
)
|
||||||
// 认证请求
|
// 认证请求
|
||||||
.authorizeHttpRequests(auth -> auth
|
.authorizeHttpRequests(auth -> auth
|
||||||
.requestMatchers("/login").permitAll()
|
.requestMatchers("/login").permitAll()
|
||||||
.requestMatchers("/users", "/users/**").hasRole("ADMIN")
|
// .requestMatchers("/users", "/users/**").hasRole("ADMIN")
|
||||||
.anyRequest().authenticated()
|
.anyRequest().access((authenticationSupplier, requestAuthorizationContext) -> {
|
||||||
|
HttpServletRequest request = requestAuthorizationContext.getRequest();
|
||||||
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
return new AuthorizationDecision(
|
||||||
|
jwtRbacAuthenticationService.hasPermission(request, authentication)
|
||||||
|
);
|
||||||
|
})
|
||||||
)
|
)
|
||||||
// JWT过滤器
|
// JWT过滤器
|
||||||
.addFilterBefore(
|
.addFilterBefore(
|
||||||
new JwtAuthenticationFilter(jwtUtil, jwtUserDetailsService),
|
new JwtAuthenticationFilter(jwtUtil, jwtUserDetailsService),
|
||||||
UsernamePasswordAuthenticationFilter.class
|
UsernamePasswordAuthenticationFilter.class
|
||||||
)
|
);
|
||||||
.userDetailsService(jwtUserDetailsService);
|
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,11 @@ package asia.yulinling.workflow.mapper;
|
|||||||
import asia.yulinling.workflow.model.entity.Permission;
|
import asia.yulinling.workflow.model.entity.Permission;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
*
|
*
|
||||||
@ -16,4 +19,11 @@ import org.springframework.stereotype.Component;
|
|||||||
@Mapper
|
@Mapper
|
||||||
@Component
|
@Component
|
||||||
public interface PermissionMapper extends BaseMapper<Permission> {
|
public interface PermissionMapper extends BaseMapper<Permission> {
|
||||||
|
/**
|
||||||
|
* 查找当前角色列表所有的权限
|
||||||
|
*
|
||||||
|
* @param roleIds 角色列表id
|
||||||
|
* @return 权限列表
|
||||||
|
*/
|
||||||
|
List<Permission> selectPermissionsByRoleId(@Param("roleIds") List<Long> roleIds);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 角色Mapper
|
* 角色Mapper
|
||||||
@ -16,4 +18,5 @@ import org.springframework.stereotype.Component;
|
|||||||
@Mapper
|
@Mapper
|
||||||
@Component
|
@Component
|
||||||
public interface RoleMapper extends BaseMapper<Role> {
|
public interface RoleMapper extends BaseMapper<Role> {
|
||||||
|
List<Role> selectRoleByUserId(Long userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色权限类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author YLL
|
||||||
|
* @since 2025/6/15
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
@Component
|
||||||
|
public interface RolePermissionMapper extends BaseMapper<RolePermission> {
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 角色用户类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author YLL
|
||||||
|
* @since 2025/6/15
|
||||||
|
*/
|
||||||
|
@Mapper
|
||||||
|
@Component
|
||||||
|
public interface RoleUserMapper extends BaseMapper<RoleUser> {
|
||||||
|
}
|
||||||
@ -48,6 +48,11 @@ public class Permission {
|
|||||||
*/
|
*/
|
||||||
private String permission;
|
private String permission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 方法
|
||||||
|
*/
|
||||||
|
private String method;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 排序
|
* 排序
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -10,6 +10,7 @@ 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 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;
|
||||||
@ -30,6 +31,7 @@ import java.util.stream.Collectors;
|
|||||||
@Data
|
@Data
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class UserPrincipal implements UserDetails {
|
public class UserPrincipal implements UserDetails {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -104,7 +106,19 @@ public class UserPrincipal implements UserDetails {
|
|||||||
*/
|
*/
|
||||||
private Collection<? extends GrantedAuthority> authorities;
|
private Collection<? extends GrantedAuthority> 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<String> roleNames, List<GrantedAuthority> 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<String> roleNames,
|
||||||
|
List<GrantedAuthority> authorities) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
@ -125,22 +139,52 @@ public class UserPrincipal implements UserDetails {
|
|||||||
return List.of();
|
return List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
public UserPrincipal(Long id, String username, String password,
|
public UserPrincipal(Long id,
|
||||||
List<String> roles, Collection<? extends GrantedAuthority> authorities) {
|
String username,
|
||||||
|
String password,
|
||||||
|
List<String> roles,
|
||||||
|
Collection<? extends GrantedAuthority> authorities) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.roles = roles;
|
this.roles = roles;
|
||||||
this.authorities = authorities;
|
this.authorities = authorities;
|
||||||
this.status = 1; // 启用
|
this.status = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static UserPrincipal create(User user, List<Role> roles, List<Permission> permissions) {
|
public static UserPrincipal create(User user,
|
||||||
List<String> roleNames = roles.stream().map(Role::getName).collect(Collectors.toList());
|
List<Role> roles,
|
||||||
|
List<Permission> permissions) {
|
||||||
|
|
||||||
List<GrantedAuthority> 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<String> roleNames = roles
|
||||||
|
.stream()
|
||||||
|
.map(Role::getName)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<GrantedAuthority> 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
|
@Override
|
||||||
public boolean isAccountNonLocked() {
|
public boolean isAccountNonLocked() {
|
||||||
return true;
|
return UserDetails.super.isAccountNonLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCredentialsNonExpired() {
|
public boolean isCredentialsNonExpired() {
|
||||||
return true;
|
return UserDetails.super.isCredentialsNonExpired();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package asia.yulinling.workflow.security;
|
|||||||
import asia.yulinling.workflow.exception.BaseException;
|
import asia.yulinling.workflow.exception.BaseException;
|
||||||
import asia.yulinling.workflow.model.ApiResponse;
|
import asia.yulinling.workflow.model.ApiResponse;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import jakarta.servlet.ServletException;
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package asia.yulinling.workflow.security;
|
package asia.yulinling.workflow.security;
|
||||||
|
|
||||||
|
import asia.yulinling.workflow.model.vo.user.UserPrincipal;
|
||||||
import asia.yulinling.workflow.utils.JwtUtil;
|
import asia.yulinling.workflow.utils.JwtUtil;
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
@ -8,11 +9,8 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
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.security.web.authentication.WebAuthenticationDetailsSource;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
@ -31,7 +29,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 UserDetailsService userDetailsService;
|
private final JwtUserDetailsService jwtUserDetailsService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(@NotNull HttpServletRequest request,
|
protected void doFilterInternal(@NotNull HttpServletRequest request,
|
||||||
@ -46,11 +44,11 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {
|
|||||||
String username = jwtUtil.parseToken(token).getSubject();
|
String username = jwtUtil.parseToken(token).getSubject();
|
||||||
|
|
||||||
// 3. 根据username验证password
|
// 3. 根据username验证password
|
||||||
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
|
UserPrincipal userPrincipal = jwtUserDetailsService.loadUserByUsername(username);
|
||||||
log.info("userDetails: {}", userDetails);
|
log.info("userPrincipal: {}", userPrincipal);
|
||||||
|
|
||||||
UsernamePasswordAuthenticationToken authenticationToken
|
UsernamePasswordAuthenticationToken authenticationToken
|
||||||
= new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
|
= new UsernamePasswordAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities());
|
||||||
log.info("authenticationToken: {}", authenticationToken);
|
log.info("authenticationToken: {}", authenticationToken);
|
||||||
|
|
||||||
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
|
||||||
|
|||||||
@ -0,0 +1,125 @@
|
|||||||
|
package asia.yulinling.workflow.security;
|
||||||
|
|
||||||
|
import asia.yulinling.workflow.mapper.PermissionMapper;
|
||||||
|
import asia.yulinling.workflow.mapper.RoleMapper;
|
||||||
|
import asia.yulinling.workflow.model.entity.Permission;
|
||||||
|
import asia.yulinling.workflow.model.entity.Role;
|
||||||
|
import asia.yulinling.workflow.model.vo.user.UserPrincipal;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.method.HandlerMethod;
|
||||||
|
import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition;
|
||||||
|
import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition;
|
||||||
|
import org.springframework.web.servlet.mvc.condition.RequestMethodsRequestCondition;
|
||||||
|
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||||
|
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||||
|
import org.springframework.web.util.pattern.PathPattern;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 自定义权限服务类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author YLL
|
||||||
|
* @since 2025/6/16
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
|
public class JwtRbacAuthenticationService {
|
||||||
|
|
||||||
|
private final PermissionMapper permissionMapper;
|
||||||
|
private final RequestMappingHandlerMapping requestMappingHandlerMapping;
|
||||||
|
private final RoleMapper roleMapper;
|
||||||
|
|
||||||
|
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
|
||||||
|
|
||||||
|
checkRequest(request);
|
||||||
|
|
||||||
|
Object userInfo = authentication.getPrincipal();
|
||||||
|
boolean hasPermission = false;
|
||||||
|
|
||||||
|
if (userInfo instanceof UserDetails) {
|
||||||
|
UserPrincipal userPrincipal = (UserPrincipal) userInfo;
|
||||||
|
Long userId = userPrincipal.getId();
|
||||||
|
|
||||||
|
List<Role> roles = roleMapper.selectRoleByUserId(userId);
|
||||||
|
List<Long> roleIds = roles.stream().map(Role::getId).toList();
|
||||||
|
List<Permission> permissions = permissionMapper.selectPermissionsByRoleId(roleIds);
|
||||||
|
|
||||||
|
List<Permission> pagePerms = permissions.stream()
|
||||||
|
.filter(permission -> Objects.equals(permission.getType(), 1))
|
||||||
|
.filter(permission -> !StringUtils.isEmpty(permission.getUrl()))
|
||||||
|
.filter(permission -> !StringUtils.isEmpty(permission.getMethod()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
for (Permission permission : pagePerms) {
|
||||||
|
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||||
|
if (antPathMatcher.match(permission.getUrl(), request.getRequestURI())) {
|
||||||
|
hasPermission = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasPermission;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkRequest(HttpServletRequest request) {
|
||||||
|
String method = request.getMethod();
|
||||||
|
Map<String, List<String>> urlMapping = getAllUrlMapping();
|
||||||
|
log.info("方法" + method + "url" + urlMapping.toString());
|
||||||
|
|
||||||
|
for (String url : urlMapping.keySet()) {
|
||||||
|
AntPathMatcher antPathMatcher = new AntPathMatcher();
|
||||||
|
if (antPathMatcher.match(urlMapping.get(url).toString(), method)) {
|
||||||
|
if (!antPathMatcher.match(url, method)) {
|
||||||
|
throw new SecurityException("请求不支持");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new SecurityException("请求不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有url对应的方法
|
||||||
|
*
|
||||||
|
* @return Map<String, List < String>>
|
||||||
|
* {
|
||||||
|
* "/user/{id}": "GET",
|
||||||
|
* "/user/": "POST"
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
public Map<String, List<String>> getAllUrlMapping() {
|
||||||
|
Map<String, List<String>> urlMapping = new HashMap<>();
|
||||||
|
|
||||||
|
Map<RequestMappingInfo, HandlerMethod> handlerMethods = requestMappingHandlerMapping.getHandlerMethods();
|
||||||
|
|
||||||
|
handlerMethods.forEach((mapping, handlerMethod) -> {
|
||||||
|
PathPatternsRequestCondition pathPatternsCondition = mapping.getPathPatternsCondition();
|
||||||
|
if (pathPatternsCondition == null) return;
|
||||||
|
Set<PathPattern> urlTemplates = pathPatternsCondition.getPatterns();
|
||||||
|
RequestMethodsRequestCondition methodsCondition = mapping.getMethodsCondition();
|
||||||
|
List<String> httpMethods = methodsCondition.getMethods().stream()
|
||||||
|
.map(Enum::toString)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
urlTemplates.forEach(url -> {
|
||||||
|
urlMapping.put(url.toString(), httpMethods);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info("urlMapping :{}", urlMapping);
|
||||||
|
return urlMapping;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,23 +1,22 @@
|
|||||||
package asia.yulinling.workflow.security;
|
package asia.yulinling.workflow.security;
|
||||||
|
|
||||||
|
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.Role;
|
import asia.yulinling.workflow.model.entity.Role;
|
||||||
import asia.yulinling.workflow.model.entity.User;
|
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.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.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.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;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,41 +33,45 @@ 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;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserPrincipal loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
// 1. 构建查找sql
|
// 1. 构建查找sql
|
||||||
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery(User.class)
|
LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery(User.class)
|
||||||
.eq(User::getUsername, username)
|
.eq(User::getUsername, username)
|
||||||
.or()
|
.or()
|
||||||
.eq(User::getEmail, username)
|
.eq(User::getEmail, username)
|
||||||
.or()
|
.or()
|
||||||
.eq(User::getPhone, username);
|
.eq(User::getPhone, username);
|
||||||
|
|
||||||
// 2. 查找用户
|
// 2. 查找用户
|
||||||
User user = userMapper.selectOne(queryWrapper);
|
User user = userMapper.selectOne(queryWrapper);
|
||||||
|
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
|
log.error("未找到用户信息{}", username);
|
||||||
throw new UsernameNotFoundException("未找到用户信息:" + username);
|
throw new UsernameNotFoundException("未找到用户信息:" + username);
|
||||||
}
|
}
|
||||||
|
log.info("username:{}", username);
|
||||||
|
|
||||||
// 3. 查找用户对应的角色
|
// 3. 查找用户对应的角色
|
||||||
List<Role> roles = roleMapper.selectByIds(Collections.singleton(user.getId()));
|
List<Role> roles = roleMapper.selectRoleByUserId(user.getId());
|
||||||
|
|
||||||
if (roles.isEmpty()) {
|
if (roles.isEmpty()) {
|
||||||
|
log.error("未找到角色信息{}", roles);
|
||||||
throw new UsernameNotFoundException("未找到角色信息" + roles);
|
throw new UsernameNotFoundException("未找到角色信息" + roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<GrantedAuthority> authorities = roles.stream()
|
List<Permission> permissions = permissionMapper.selectPermissionsByRoleId(roles.stream().map(Role::getId).collect(Collectors.toList()));
|
||||||
.map((role) -> new SimpleGrantedAuthority(role.getName()))
|
|
||||||
.collect(Collectors.toSet());
|
if (permissions.isEmpty()) {
|
||||||
|
log.error("未找到权限信息{}", permissions);
|
||||||
|
throw new UsernameNotFoundException("未找到权限信息" + permissions);
|
||||||
|
}
|
||||||
|
|
||||||
// 4. 返回User
|
// 4. 返回User
|
||||||
return new org.springframework.security.core.userdetails.User(
|
return UserPrincipal.create(user, roles, permissions);
|
||||||
username,
|
|
||||||
user.getPassword(),
|
|
||||||
authorities
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
# 服务端配置
|
# 服务端配置
|
||||||
server.port=8080
|
server.port=8080
|
||||||
server.servlet.context-path=/demo
|
#server.servlet.context-path=/demo
|
||||||
# mysql配置
|
# mysql配置
|
||||||
spring.datasource.url=jdbc:mysql://122.152.201.90:9912/workflow?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
|
spring.datasource.url=jdbc:mysql://122.152.201.90:9912/workflow?useUnicode=true&characterEncoding=UTF-8&useSSL=false&autoReconnect=true&failOverReadOnly=false&serverTimezone=GMT%2B8
|
||||||
spring.datasource.username=root
|
spring.datasource.username=root
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
BEGIN;
|
BEGIN;
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
VALUES (1072806379288399872, '测试页面', '/test', 1, 'page:test', NULL, 1, 0);
|
VALUES (1072806379288399872, '测试页面', '/test', 1, 'page:test', 'GET', 1, 0);
|
||||||
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);
|
||||||
INSERT INTO `wk_permission`
|
INSERT INTO `wk_permission`
|
||||||
@ -15,6 +15,10 @@ 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);
|
'DELETE', 2, 1072806379342925824);
|
||||||
|
INSERT INTO `wk_permission`
|
||||||
|
VALUES (1072806379384868865, '用户列表', '/users', 1,
|
||||||
|
'page:test',
|
||||||
|
'GET', 1, 0);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
@ -41,6 +45,8 @@ INSERT INTO `wk_role_permission`
|
|||||||
VALUES (1072806379238068224, 1072806379288399872);
|
VALUES (1072806379238068224, 1072806379288399872);
|
||||||
INSERT INTO `wk_role_permission`
|
INSERT INTO `wk_role_permission`
|
||||||
VALUES (1072806379238068224, 1072806379313565696);
|
VALUES (1072806379238068224, 1072806379313565696);
|
||||||
|
INSERT INTO `wk_role_permission`
|
||||||
|
VALUES (1072806379208708096, 1072806379384868865);
|
||||||
COMMIT;
|
COMMIT;
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|||||||
14
src/main/resources/mapper/PermissionMapper.xml
Normal file
14
src/main/resources/mapper/PermissionMapper.xml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="asia.yulinling.workflow.mapper.PermissionMapper">
|
||||||
|
<select id="selectPermissionsByRoleId" resultType="asia.yulinling.workflow.model.entity.Permission">
|
||||||
|
SELECT DISTINCT wp.*
|
||||||
|
FROM wk_permission wp
|
||||||
|
JOIN wk_role_permission wrp ON wp.id = wrp.permission_id
|
||||||
|
JOIN wk_role wr ON wr.id = wrp.role_id
|
||||||
|
WHERE wr.id in
|
||||||
|
<foreach collection="roleIds" item="roleId" open="(" separator="," close=")">
|
||||||
|
#{roleId}
|
||||||
|
</foreach>
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
11
src/main/resources/mapper/RoleMapper.xml
Normal file
11
src/main/resources/mapper/RoleMapper.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||||
|
<mapper namespace="asia.yulinling.workflow.mapper.RoleMapper">
|
||||||
|
<select id="selectRoleByUserId" resultType="asia.yulinling.workflow.model.entity.Role">
|
||||||
|
SELECT DISTINCT r.*
|
||||||
|
FROM wk_role r
|
||||||
|
JOIN wk_role_user ur ON r.id = ur.role_id
|
||||||
|
JOIN wk_user u ON u.id = ur.user_id
|
||||||
|
WHERE u.id = #{userId}
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
Loading…
Reference in New Issue
Block a user