feat: 增加了 jwt 验证方式。

This commit is contained in:
c
2026-03-18 13:29:56 +08:00
parent 392e74134a
commit 8bb7dcca31
8 changed files with 197 additions and 53 deletions

View File

@@ -70,6 +70,10 @@ dependencies {
// Excel处理 // Excel处理
implementation("org.apache.poi:poi:5.2.5") implementation("org.apache.poi:poi:5.2.5")
implementation("org.apache.poi:poi-ooxml:5.2.5") implementation("org.apache.poi:poi-ooxml:5.2.5")
// Redis
implementation("org.springframework.boot:spring-boot-starter-data-redis")
implementation("org.apache.commons:commons-pool2")
} }
tasks.withType<Test> { tasks.withType<Test> {

View File

@@ -28,7 +28,9 @@ public class UrlPermissionAuthorizationManager implements AuthorizationManager<R
HttpServletRequest request = context.getRequest(); HttpServletRequest request = context.getRequest();
String requestURI = request.getRequestURI(); String requestURI = request.getRequestURI();
if (antPathMatcher.match("/auth/user/me", requestURI)) { // 公开接口直接放行
if (antPathMatcher.match("/auth/user/me", requestURI)
|| antPathMatcher.match("/open/**", requestURI)) {
return new AuthorizationDecision(true); return new AuthorizationDecision(true);
} }
Authentication auth = authentication.get(); Authentication auth = authentication.get();

View File

@@ -4,47 +4,66 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.niuan.erp.common.base.BaseResult; import com.niuan.erp.common.base.BaseResult;
import com.niuan.erp.common.base.LoginUser; import com.niuan.erp.common.base.LoginUser;
import com.niuan.erp.common.bean.UrlPermissionAuthorizationManager; import com.niuan.erp.common.bean.UrlPermissionAuthorizationManager;
import com.niuan.erp.common.security.JwtAuthenticationFilter;
import com.niuan.erp.common.security.TokenService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
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.context.annotation.Primary; import org.springframework.context.annotation.Primary;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
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.core.session.SessionRegistry; import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.session.ConcurrentSessionFilter; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import java.util.List; import java.util.List;
/**
* Security配置类 - 同时支持Session和JWT两种认证方式
* - Web端后台管理使用传统Session方式基于Cookie
* - 小程序端使用JWT方式基于Token
*/
@Configuration @Configuration
@EnableWebSecurity // 启用 Web 安全 @EnableWebSecurity
@EnableMethodSecurity @EnableMethodSecurity
@RequiredArgsConstructor @RequiredArgsConstructor
public class SecurityConfig { public class SecurityConfig {
private final UrlPermissionAuthorizationManager urlPermissionAuthorizationManager; private final UrlPermissionAuthorizationManager urlPermissionAuthorizationManager;
private final JwtAuthenticationFilter jwtAuthenticationFilter;
private final TokenService tokenService;
private final UserDetailsService userDetailsService;
private final PasswordEncoder passwordEncoder;
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http, SessionRegistry sessionRegistry) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http, SessionRegistry sessionRegistry) throws Exception {
http http
// 👇 1. 启用 CSRF // 禁用 CSRFJWT需要禁用Session方式通过其他方式防护
.csrf(csrf -> csrf.disable()) .csrf(csrf -> csrf.disable())
.cors(cors -> cors.configurationSource(corsConfigurationSource())) .cors(cors -> cors.configurationSource(corsConfigurationSource()))
// 👇 2. 设置 Session // 设置 Session支持Session方式同时允许JWT无状态请求
.sessionManagement(session -> session .sessionManagement(session -> session
.maximumSessions(1) .maximumSessions(1)
.maxSessionsPreventsLogin(false) .maxSessionsPreventsLogin(false)
.sessionRegistry(sessionRegistry)) .sessionRegistry(sessionRegistry))
// 👇 3. 请求授权规则 // 请求授权规则
.authorizeHttpRequests(authz -> authz .authorizeHttpRequests(authz -> authz
.requestMatchers( .requestMatchers(
"/v3/api-docs/**", "/v3/api-docs", "/v3/api-docs/**", "/v3/api-docs",
@@ -52,24 +71,25 @@ public class SecurityConfig {
"/swagger-ui.html", "/swagger-ui.html",
"/webjars/**", "/webjars/**",
"/doc.html", "/doc.html",
"/favicon.ico").permitAll() "/favicon.ico",
"/open/**",
"/api/auth/**").permitAll() // 小程序登录接口公开
.anyRequest().authenticated() .anyRequest().authenticated()
) )
// // 表单登录配置Web端使用
.formLogin(form -> form .formLogin(form -> form
.loginProcessingUrl("/auth/login") // 指定登录提交地址 .loginProcessingUrl("/auth/login")
.successHandler((request, response, authentication) -> { .successHandler((request, response, authentication) -> {
// 登录成功:返回 JSON // Web端登录成功:返回简单JSON
response.setContentType("application/json;charset=UTF-8"); response.setContentType("application/json;charset=UTF-8");
LoginUser user = (LoginUser) authentication.getPrincipal();
response.getWriter().write(new ObjectMapper().writeValueAsString(BaseResult.success())); response.getWriter().write(new ObjectMapper().writeValueAsString(BaseResult.success()));
}) })
.failureHandler((request, response, exception) -> { .failureHandler((request, response, exception) -> {
// 登录失败:返回 JSON
response.setStatus(HttpStatus.OK.value()); response.setStatus(HttpStatus.OK.value());
response.setContentType("application/json;charset=UTF-8"); response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(BaseResult.error(3, exception.getMessage()))); response.getWriter().write(new ObjectMapper().writeValueAsString(
BaseResult.error(3, exception.getMessage())));
}) })
) )
.logout(logout -> logout .logout(logout -> logout
@@ -78,47 +98,50 @@ public class SecurityConfig {
.deleteCookies("JSESSIONID") .deleteCookies("JSESSIONID")
.clearAuthentication(true) .clearAuthentication(true)
.logoutSuccessHandler((request, response, authentication) -> { .logoutSuccessHandler((request, response, authentication) -> {
// Web端登出
response.setContentType("application/json;charset=UTF-8"); response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(BaseResult.success())); response.getWriter().write(new ObjectMapper().writeValueAsString(BaseResult.success()));
}) })
) )
// 👇 6. 异常处理(认证失败 / 权限不足) // 异常处理
.exceptionHandling(ex -> ex .exceptionHandling(ex -> ex
.authenticationEntryPoint((request, response, authException) -> { .authenticationEntryPoint((request, response, authException) -> {
response.setStatus(401); response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write("Unauthorized: " + authException.getMessage()); response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(
BaseResult.error(HttpStatus.UNAUTHORIZED.value(), "未认证,请先登录")));
}) })
.accessDeniedHandler((request, response, accessDeniedException) -> { .accessDeniedHandler((request, response, accessDeniedException) -> {
response.setStatus(403); response.setStatus(HttpStatus.FORBIDDEN.value());
response.getWriter().write("Forbidden: " + accessDeniedException.getMessage()); response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(
BaseResult.error(HttpStatus.FORBIDDEN.value(), "无权访问")));
}) })
); );
// 添加JWT过滤器在UsernamePasswordAuthenticationFilter之前
// 这样JWT请求可以绕过Session认证直接通过Token认证
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }
@Bean @Bean
public SessionRegistry sessionRegistry() { public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return new SessionRegistryImpl(); return config.getAuthenticationManager();
} }
@Bean // 👇 提供 CORS 配置
public ConcurrentSessionFilter concurrentSessionFilter(SessionRegistry sessionRegistry) {
return new ConcurrentSessionFilter(sessionRegistry);
}
// 👇 提供 CORS 配置(生产环境请严格限制 origin
@Bean @Bean
@Primary @Primary
public CorsConfigurationSource corsConfigurationSource() { public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration(); CorsConfiguration configuration = new CorsConfiguration();
// 允许的前端 origin(必须是具体地址,不能 * // 允许的前端 origin
configuration.setAllowedOriginPatterns(List.of("http://localhost:*", "http://127.0.0.1:*")); configuration.setAllowedOriginPatterns(List.of("http://localhost:*", "http://127.0.0.1:*"));
// ⚠️ 注意Spring Boot 2.4+ 用 allowedOriginPatterns 支持通配符
// 允许凭证Cookie // 允许凭证Cookie
configuration.setAllowCredentials(true); configuration.setAllowCredentials(true);
// 允许的方法和头 // 允许的方法和头
@@ -130,27 +153,4 @@ public class SecurityConfig {
source.registerCorsConfiguration("/**", configuration); source.registerCorsConfiguration("/**", configuration);
return source; return source;
} }
// 👇 密码编码器(必须)
// @Bean
// public PasswordEncoder passwordEncoder() {
// return md5PasswordEncoder;
// }
// 👇 AuthenticationProvider用于 DaoAuthenticationProvider
// @Bean
// public AuthenticationProvider authenticationProvider() {
// DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
// authProvider.setUserDetailsService(userDetailsService);
// authProvider.setPasswordEncoder(passwordEncoder());
// return authProvider;
// }
// 👇 AuthenticationManager用于登录时 authenticate
// @Bean
// public AuthenticationManager authenticationManager(
// org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration config)
// throws Exception {
// return config.getAuthenticationManager();
// }
} }

View File

@@ -3,7 +3,28 @@ package com.niuan.erp.module.sys.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.niuan.erp.module.sys.entity.SysUser; import com.niuan.erp.module.sys.entity.SysUser;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper @Mapper
public interface SysUserMapper extends BaseMapper<SysUser> { public interface SysUserMapper extends BaseMapper<SysUser> {
/**
* 根据角色ID查询用户ID列表
*/
@Select("SELECT DISTINCT ur.UserId FROM yy_usersrolemapping ur WHERE ur.RoleId = #{roleId}")
List<Long> selectUserIdsByRoleId(@Param("roleId") Long roleId);
/**
* 根据权限ID查询用户ID列表
*/
@Select("""
SELECT DISTINCT ur.UserId
FROM yy_usersrolemapping ur
INNER JOIN yy_rolepermission rp ON ur.RoleId = rp.RoleId
WHERE rp.PermissionId = #{permissionId}
""")
List<Long> selectUserIdsByPermissionId(@Param("permissionId") Long permissionId);
} }

View File

@@ -3,6 +3,7 @@ package com.niuan.erp.module.sys.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.LoginUser;
import com.niuan.erp.module.sys.controller.dto.SysUserDto; import com.niuan.erp.module.sys.controller.dto.SysUserDto;
import com.niuan.erp.module.sys.entity.SysUser; import com.niuan.erp.module.sys.entity.SysUser;
@@ -21,4 +22,19 @@ public interface SysUserService {
void deleteBatch(List<Long> ids); void deleteBatch(List<Long> ids);
void setStatus(Long id, Integer status); void setStatus(Long id, Integer status);
/**
* 根据用户ID加载用户信息
*/
LoginUser loadUserById(Long userId);
/**
* 根据角色ID查询用户ID列表
*/
List<Long> getUserIdsByRoleId(Long roleId);
/**
* 根据权限ID查询用户ID列表
*/
List<Long> getUserIdsByPermissionId(Long permissionId);
} }

View File

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.security.TokenService;
import com.niuan.erp.common.utils.SecurityUtils; import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.sys.controller.dto.SysRoleDto; import com.niuan.erp.module.sys.controller.dto.SysRoleDto;
import com.niuan.erp.module.sys.controller.dto.SysRoleSelectDto; import com.niuan.erp.module.sys.controller.dto.SysRoleSelectDto;
@@ -15,6 +16,7 @@ import com.niuan.erp.module.sys.mapper.RolePermissionMapper;
import com.niuan.erp.module.sys.mapper.SysPermissionMapper; import com.niuan.erp.module.sys.mapper.SysPermissionMapper;
import com.niuan.erp.module.sys.mapper.SysRoleMapper; import com.niuan.erp.module.sys.mapper.SysRoleMapper;
import com.niuan.erp.module.sys.service.SysRoleService; import com.niuan.erp.module.sys.service.SysRoleService;
import com.niuan.erp.module.sys.service.SysUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -34,6 +36,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
private final RolePermissionMapper rolePermissionMapper; private final RolePermissionMapper rolePermissionMapper;
private final TokenService tokenService;
private final SysUserService sysUserService;
@Override @Override
public IPage<SysRoleDto> getSysRolePage(BasePageReqParams dto, LambdaQueryWrapper<SysRole> wrapper) { public IPage<SysRoleDto> getSysRolePage(BasePageReqParams dto, LambdaQueryWrapper<SysRole> wrapper) {
IPage<SysRole> result = this.baseMapper.selectPage(new Page<>(dto.page(), dto.pageSize()), wrapper); IPage<SysRole> result = this.baseMapper.selectPage(new Page<>(dto.page(), dto.pageSize()), wrapper);
@@ -87,15 +93,34 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
// 使用循环单条插入,避免无主键实体使用批量 insert 方法的问题 // 使用循环单条插入,避免无主键实体使用批量 insert 方法的问题
newPermissions.forEach(rolePermissionMapper::insert); newPermissions.forEach(rolePermissionMapper::insert);
} }
// 角色修改后,踢掉所有拥有该角色的用户
List<Long> userIds = sysUserService.getUserIdsByRoleId(entity.getId());
if (userIds != null && !userIds.isEmpty()) {
userIds.forEach(tokenService::removeAllUserTokens);
}
} }
@Override @Override
public void deleteSysRole(Long id) { public void deleteSysRole(Long id) {
// 角色删除前,踢掉所有拥有该角色的用户
List<Long> userIds = sysUserService.getUserIdsByRoleId(id);
if (userIds != null && !userIds.isEmpty()) {
userIds.forEach(tokenService::removeAllUserTokens);
}
this.baseMapper.deleteById(id); this.baseMapper.deleteById(id);
} }
@Override @Override
public void deleteBatch(List<Long> ids) { public void deleteBatch(List<Long> ids) {
if (ids != null && !ids.isEmpty()) {
// 批量删除前,踢掉所有拥有这些角色的用户
for (Long roleId : ids) {
List<Long> userIds = sysUserService.getUserIdsByRoleId(roleId);
if (userIds != null && !userIds.isEmpty()) {
userIds.forEach(tokenService::removeAllUserTokens);
}
}
}
this.baseMapper.deleteByIds(ids); this.baseMapper.deleteByIds(ids);
} }
@@ -104,6 +129,11 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
SysRole entity = this.baseMapper.selectById(id); SysRole entity = this.baseMapper.selectById(id);
entity.setStatus(status); entity.setStatus(status);
this.baseMapper.updateById(entity); this.baseMapper.updateById(entity);
// 角色状态修改后,踢掉所有拥有该角色的用户
List<Long> userIds = sysUserService.getUserIdsByRoleId(id);
if (userIds != null && !userIds.isEmpty()) {
userIds.forEach(tokenService::removeAllUserTokens);
}
} }
@Override @Override

View File

@@ -5,18 +5,24 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.niuan.erp.common.base.BasePageReqParams; import com.niuan.erp.common.base.BasePageReqParams;
import com.niuan.erp.common.base.LoginUser;
import com.niuan.erp.common.exception.BusinessException; import com.niuan.erp.common.exception.BusinessException;
import com.niuan.erp.common.security.TokenService;
import com.niuan.erp.common.utils.SecurityUtils; import com.niuan.erp.common.utils.SecurityUtils;
import com.niuan.erp.module.sys.controller.dto.SysUserDto; import com.niuan.erp.module.sys.controller.dto.SysUserDto;
import com.niuan.erp.module.sys.converter.SysUserConverter; import com.niuan.erp.module.sys.converter.SysUserConverter;
import com.niuan.erp.module.sys.entity.SysPermission;
import com.niuan.erp.module.sys.entity.SysRole; import com.niuan.erp.module.sys.entity.SysRole;
import com.niuan.erp.module.sys.entity.SysUser; import com.niuan.erp.module.sys.entity.SysUser;
import com.niuan.erp.module.sys.entity.UserRole; import com.niuan.erp.module.sys.entity.UserRole;
import com.niuan.erp.module.sys.mapper.SysPermissionMapper;
import com.niuan.erp.module.sys.mapper.SysRoleMapper; import com.niuan.erp.module.sys.mapper.SysRoleMapper;
import com.niuan.erp.module.sys.mapper.SysUserMapper; import com.niuan.erp.module.sys.mapper.SysUserMapper;
import com.niuan.erp.module.sys.mapper.UserRoleMapper; import com.niuan.erp.module.sys.mapper.UserRoleMapper;
import com.niuan.erp.module.sys.service.SysUserService; import com.niuan.erp.module.sys.service.SysUserService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -38,6 +44,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private final SysRoleMapper sysRoleMapper; private final SysRoleMapper sysRoleMapper;
private final SysPermissionMapper sysPermissionMapper;
private final TokenService tokenService;
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
@Override @Override
@@ -175,10 +185,16 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 更新用户角色关联 // 更新用户角色关联
updateUserRoles(id, dto.roleIds()); updateUserRoles(id, dto.roleIds());
// 用户修改后,踢掉该用户
tokenService.removeAllUserTokens(id);
} }
@Override @Override
public void deleteUser(Long id) { public void deleteUser(Long id) {
// 用户删除前,踢掉该用户
tokenService.removeAllUserTokens(id);
// 删除用户角色关联 // 删除用户角色关联
LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UserRole::getUserId, id); wrapper.eq(UserRole::getUserId, id);
@@ -194,6 +210,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return; return;
} }
// 批量删除前,踢掉这些用户
ids.forEach(tokenService::removeAllUserTokens);
// 删除用户角色关联 // 删除用户角色关联
LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>(); LambdaQueryWrapper<UserRole> wrapper = new LambdaQueryWrapper<>();
wrapper.in(UserRole::getUserId, ids); wrapper.in(UserRole::getUserId, ids);
@@ -218,6 +237,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
updateUser.setUpdateDate(LocalDateTime.now()); updateUser.setUpdateDate(LocalDateTime.now());
this.baseMapper.updateById(updateUser); this.baseMapper.updateById(updateUser);
// 用户状态修改后,踢掉该用户
tokenService.removeAllUserTokens(id);
} }
private void checkLoginNameExists(String loginName, Long excludeId) { private void checkLoginNameExists(String loginName, Long excludeId) {
@@ -258,4 +280,35 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 保存新的角色关联 // 保存新的角色关联
saveUserRoles(userId, roleIds); saveUserRoles(userId, roleIds);
} }
@Override
public LoginUser loadUserById(Long userId) {
SysUser user = this.baseMapper.selectById(userId);
if (user == null) {
return null;
}
List<SysRole> roleList = sysRoleMapper.selectByUserId(userId);
List<SysPermission> permissionList = sysPermissionMapper.selectByUserId(userId);
List<GrantedAuthority> authorities = permissionList.stream()
.filter(p -> StringUtils.hasText(p.getPermissionCode()))
.map(p -> new SimpleGrantedAuthority(p.getPermissionCode()))
.collect(Collectors.toUnmodifiableList());
return LoginUser.builder()
.user(user)
.roleList(roleList)
.authorities(authorities)
.build();
}
@Override
public List<Long> getUserIdsByRoleId(Long roleId) {
return this.baseMapper.selectUserIdsByRoleId(roleId);
}
@Override
public List<Long> getUserIdsByPermissionId(Long permissionId) {
return this.baseMapper.selectUserIdsByPermissionId(permissionId);
}
} }

View File

@@ -10,6 +10,24 @@ spring:
url: jdbc:mysql://localhost:3306/ai url: jdbc:mysql://localhost:3306/ai
username: steven username: steven
password: 781203 password: 781203
data:
redis:
host: localhost
port: 6379
password:
database: 0
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
max-wait: 1000ms
# jwt配置
jwt:
secret: your-256-bit-secret-key-here-must-be-at-least-32-characters
expiration: 86400000
refresh-expiration: 604800000
# mybatis 设置 # mybatis 设置
mybatis-plus: mybatis-plus: