diff --git a/eladmin-common/src/main/java/me/zhengjie/config/RedisConfig.java b/eladmin-common/src/main/java/me/zhengjie/config/RedisConfig.java index aa383f64..bad7f79f 100644 --- a/eladmin-common/src/main/java/me/zhengjie/config/RedisConfig.java +++ b/eladmin-common/src/main/java/me/zhengjie/config/RedisConfig.java @@ -80,10 +80,18 @@ public class RedisConfig extends CachingConfigurerSupport { // value值的序列化采用fastJsonRedisSerializer template.setValueSerializer(fastJsonRedisSerializer); template.setHashValueSerializer(fastJsonRedisSerializer); - // 全局开启AutoType,这里方便开发,使用全局的方式 - ParserConfig.getGlobalInstance().setAutoTypeSupport(true); - // 建议使用这种方式,小范围指定白名单 - // ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain"); + // fastjson 升级到 1.2.83 后需要指定序列化白名单 + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.domain"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.service.dto"); + // 模块内的实体类 + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.mnt.domain"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.domain"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.domain"); + // 模块内的 Dto + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.mnt.service.dto"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.quartz.service.dto"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.security.service.dto"); + ParserConfig.getGlobalInstance().addAccept("me.zhengjie.modules.system.service.dto"); // key的序列化采用StringRedisSerializer template.setKeySerializer(new StringRedisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); diff --git a/eladmin-common/src/main/java/me/zhengjie/utils/RedisUtils.java b/eladmin-common/src/main/java/me/zhengjie/utils/RedisUtils.java index eeeae0f5..b49b3ca5 100644 --- a/eladmin-common/src/main/java/me/zhengjie/utils/RedisUtils.java +++ b/eladmin-common/src/main/java/me/zhengjie/utils/RedisUtils.java @@ -23,6 +23,7 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.*; +import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.stereotype.Component; import java.util.*; @@ -41,6 +42,9 @@ public class RedisUtils { public RedisUtils(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; + this.redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + this.redisTemplate.setKeySerializer(new StringRedisSerializer()); + this.redisTemplate.setStringSerializer(new StringRedisSerializer()); } /** diff --git a/eladmin-logging/src/main/java/me/zhengjie/rest/LogController.java b/eladmin-logging/src/main/java/me/zhengjie/rest/LogController.java index 4a6516a8..d4101449 100644 --- a/eladmin-logging/src/main/java/me/zhengjie/rest/LogController.java +++ b/eladmin-logging/src/main/java/me/zhengjie/rest/LogController.java @@ -71,7 +71,7 @@ public class LogController { @ApiOperation("用户日志查询") public ResponseEntity queryUserLog(LogQueryCriteria criteria, Pageable pageable){ criteria.setLogType("INFO"); - criteria.setBlurry(SecurityUtils.getCurrentUsername()); + criteria.setUsername(SecurityUtils.getCurrentUsername()); return new ResponseEntity<>(logService.queryAllByUser(criteria,pageable), HttpStatus.OK); } diff --git a/eladmin-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java b/eladmin-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java index c01812c4..83406079 100644 --- a/eladmin-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java +++ b/eladmin-logging/src/main/java/me/zhengjie/service/dto/LogQueryCriteria.java @@ -31,6 +31,9 @@ public class LogQueryCriteria { @Query(blurry = "username,description,address,requestIp,method,params") private String blurry; + @Query + private String username; + @Query private String logType; diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java b/eladmin-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java index 547e822b..a5a9c91f 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/quartz/config/JobRunner.java @@ -24,7 +24,6 @@ import org.slf4j.LoggerFactory; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; - import java.util.List; /** @@ -45,9 +44,8 @@ public class JobRunner implements ApplicationRunner { */ @Override public void run(ApplicationArguments applicationArguments) { - log.info("--------------------注入系统定时任务------------------"); List quartzJobs = quartzJobRepository.findByIsPauseIsFalse(); quartzJobs.forEach(quartzManage::addJob); - log.info("--------------------定时任务注入完成------------------"); + log.info("Timing task injection complete"); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SpringSecurityConfig.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SpringSecurityConfig.java index 2c02f4e7..ad886f31 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SpringSecurityConfig.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/SpringSecurityConfig.java @@ -20,7 +20,7 @@ import me.zhengjie.annotation.AnonymousAccess; import me.zhengjie.modules.security.config.bean.SecurityProperties; import me.zhengjie.modules.security.security.*; import me.zhengjie.modules.security.service.OnlineUserService; -import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.security.service.UserCacheManager; import me.zhengjie.utils.enums.RequestMethodEnum; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; @@ -58,7 +58,7 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { private final ApplicationContext applicationContext; private final SecurityProperties properties; private final OnlineUserService onlineUserService; - private final UserCacheClean userCacheClean; + private final UserCacheManager userCacheManager; @Bean GrantedAuthorityDefaults grantedAuthorityDefaults() { @@ -138,7 +138,7 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { } private TokenConfigurer securityConfigurerAdapter() { - return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheClean); + return new TokenConfigurer(tokenProvider, properties, onlineUserService, userCacheManager); } private Map> getAnonymousUrl(Map handlerMethodMap) { diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java index 7ce91fc8..1e00f2fe 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/config/bean/LoginProperties.java @@ -20,7 +20,6 @@ import com.wf.captcha.base.Captcha; import lombok.Data; import me.zhengjie.exception.BadConfigurationException; import me.zhengjie.utils.StringUtils; - import java.awt.*; import java.util.Objects; @@ -40,19 +39,12 @@ public class LoginProperties { private LoginCode loginCode; - /** - * 用户登录信息缓存 - */ - private boolean cacheEnable; + public static final String cacheKey = "USER-LOGIN-DATA"; public boolean isSingleLogin() { return singleLogin; } - public boolean isCacheEnable() { - return cacheEnable; - } - /** * 获取验证码生产类 * diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java index 94e25477..cff5e1ed 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/security/TokenConfigurer.java @@ -18,7 +18,7 @@ package me.zhengjie.modules.security.security; import lombok.RequiredArgsConstructor; import me.zhengjie.modules.security.config.bean.SecurityProperties; import me.zhengjie.modules.security.service.OnlineUserService; -import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.security.service.UserCacheManager; import org.springframework.security.config.annotation.SecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.web.DefaultSecurityFilterChain; @@ -33,11 +33,11 @@ public class TokenConfigurer extends SecurityConfigurerAdapter - * 用户信息变更时 - * - * @param userName / - */ - public void cleanUserCache(String userName) { - if (StringUtils.isNotEmpty(userName)) { - userCacheManager.remove(userName); - } - } - - /** - * 清理所有用户的缓存信息
- * ,如发生角色授权信息变化,可以简便的全部失效缓存 - */ - public void cleanAll() { - userCacheManager.clear(); - } -} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheManager.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheManager.java index 8eaccd5f..3a8afe72 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheManager.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserCacheManager.java @@ -1,110 +1,82 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package me.zhengjie.modules.security.service; -import lombok.extern.slf4j.Slf4j; +import cn.hutool.core.util.RandomUtil; +import me.zhengjie.modules.security.config.bean.LoginProperties; import me.zhengjie.modules.security.service.dto.JwtUserDto; +import me.zhengjie.utils.RedisUtils; +import me.zhengjie.utils.StringUtils; import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; - -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicBoolean; +import javax.annotation.Resource; /** - * 用户缓存 - * - * @author TikiWong - * @date 2022/1/27 8:23 + * @author Zheng Jie + * @description 用户缓存管理 + * @date 2022-05-26 **/ -@Slf4j @Component public class UserCacheManager { - @Value("${user-cache.min-evictable-size}") - private int minEvictableSize; - @Value("${user-cache.min-evictable-interval}") - private long minEvictableInterval; - @Value("${user-cache.min-idle-time}") - private long minIdleTime; + @Resource + private RedisUtils redisUtils; + @Value("${login.user-cache.idle-time}") + private long idleTime; - private final Map cache = new ConcurrentHashMap<>(); - private final AtomicBoolean expelLock = new AtomicBoolean(true); - private long nextMinEvictableTime = 0; - - public Future putIfAbsent(String username, Future ft) { - Node tryNode = new Node(ft); - Node node = cache.putIfAbsent(username, tryNode); - expel(); - return nodeToDate(node); + /** + * 返回用户缓存 + * @param userName 用户名 + * @return JwtUserDto + */ + public JwtUserDto getUserCache(String userName) { + if (StringUtils.isNotEmpty(userName)) { + // 获取数据 + Object obj = redisUtils.hget(LoginProperties.cacheKey, userName); + if(obj != null){ + return (JwtUserDto)obj; + } + } + return null; } /** - * 缓存回收 - * 为避免超过边界后回收热点数据设置了最小生存时间 - * 回收时会保留在最小生存时间内的数据 - **/ - public void expel() { - long now = System.currentTimeMillis(); - if (cache.size() < minEvictableSize || - now < nextMinEvictableTime || - !expelLock.compareAndSet(true, false)) { - return; - } - long oldestTime = now; - int evictedCount = 0; - try { - Iterator> iterator = cache.entrySet().iterator(); - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - long nodeTime = entry.getValue().getTime(); - if (nodeTime + minIdleTime < now) { - iterator.remove(); - evictedCount++; - } - oldestTime = Math.min(oldestTime, nodeTime); - } - } finally { - this.nextMinEvictableTime = Math.max(now + minEvictableInterval, oldestTime); - expelLock.set(true); - log.info("回收掉【{}】条用户缓存, 剩余缓存数为【{}】,下次可回收时间为【{}】秒后", - evictedCount, - cache.size(), - (this.nextMinEvictableTime - now) / 1000); + * 添加缓存到Redis + * @param userName 用户名 + */ + @Async + public void addUserCache(String userName, JwtUserDto user) { + if (StringUtils.isNotEmpty(userName)) { + // 添加数据, 避免数据同时过期 + long time = idleTime + RandomUtil.randomInt(900, 1800); + redisUtils.hset(LoginProperties.cacheKey, userName, user, time); } } - public Future get(String username) { - return nodeToDate(cache.get(username)); - } - - public void clear() { - cache.clear(); - } - - public void remove(String username) { - cache.remove(username); - } - - private Future nodeToDate(Node node) { - return node == null ? null : node.getData(); - } - - private static class Node { - private final Future data; - private final long time; - - public Node(Future data) { - this.data = data; - this.time = System.currentTimeMillis(); - } - - public Future getData() { - return data; - } - - public long getTime() { - return time; + /** + * 清理用户缓存信息 + * 用户信息变更时 + * @param userName 用户名 + */ + @Async + public void cleanUserCache(String userName) { + if (StringUtils.isNotEmpty(userName)) { + // 清除数据 + redisUtils.hdel(LoginProperties.cacheKey, userName); } } -} +} \ No newline at end of file diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java index 7e5befd9..70db5df0 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/UserDetailsServiceImpl.java @@ -16,50 +16,38 @@ package me.zhengjie.modules.security.service; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import me.zhengjie.exception.BadRequestException; import me.zhengjie.exception.EntityNotFoundException; -import me.zhengjie.modules.security.config.bean.LoginProperties; import me.zhengjie.modules.security.service.dto.JwtUserDto; import me.zhengjie.modules.system.service.DataService; import me.zhengjie.modules.system.service.RoleService; import me.zhengjie.modules.system.service.UserService; -import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.dto.UserLoginDto; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; -import java.util.List; -import java.util.concurrent.*; -import java.util.concurrent.atomic.AtomicInteger; - /** * @author Zheng Jie * @date 2018-11-22 */ +@Slf4j @RequiredArgsConstructor @Service("userDetailsService") public class UserDetailsServiceImpl implements UserDetailsService { private final UserService userService; private final RoleService roleService; private final DataService dataService; - private final LoginProperties loginProperties; - - private final UserCacheManager USER_DTO_CACHE; - - public void setEnableCache(boolean enableCache) { - this.loginProperties.setCacheEnable(enableCache); - } - - public static ExecutorService executor = newThreadPool(); + private final UserCacheManager userCacheManager; @Override public JwtUserDto loadUserByUsername(String username) { - JwtUserDto jwtUserDto = null; - Future future = USER_DTO_CACHE.get(username); - if (!loginProperties.isCacheEnable()) { - UserDto user; + JwtUserDto jwtUserDto = userCacheManager.getUserCache(username); + if(jwtUserDto == null){ + UserLoginDto user; try { - user = userService.findByName(username); + user = userService.getLoginData(username); } catch (EntityNotFoundException e) { // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException throw new UsernameNotFoundException(username, e); @@ -75,85 +63,10 @@ public class UserDetailsServiceImpl implements UserDetailsService { dataService.getDeptIds(user), roleService.mapToGrantedAuthorities(user) ); + // 添加缓存数据 + userCacheManager.addUserCache(username, jwtUserDto); } - return jwtUserDto; - } - - if (future == null) { - Callable call = () -> getJwtBySearchDb(username); - FutureTask ft = new FutureTask<>(call); - future = USER_DTO_CACHE.putIfAbsent(username, ft); - if (future == null) { - future = ft; - executor.submit(ft); - } - try { - return future.get(); - } catch (CancellationException e) { - USER_DTO_CACHE.remove(username); - System.out.println("error" + Thread.currentThread().getName()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e.getMessage()); - } - } else { - try { - jwtUserDto = future.get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e.getMessage()); - } - // 检查dataScope是否修改 - List dataScopes = jwtUserDto.getDataScopes(); - dataScopes.clear(); - dataScopes.addAll(dataService.getDeptIds(jwtUserDto.getUser())); - } return jwtUserDto; - - } - - private JwtUserDto getJwtBySearchDb(String username) { - UserDto user; - try { - user = userService.findByName(username); - } catch (EntityNotFoundException e) { - // SpringSecurity会自动转换UsernameNotFoundException为BadCredentialsException - throw new UsernameNotFoundException("", e); - } - if (user == null) { - throw new UsernameNotFoundException(""); - } else { - if (!user.getEnabled()) { - throw new BadRequestException("账号未激活!"); - } - return new JwtUserDto( - user, - dataService.getDeptIds(user), - roleService.mapToGrantedAuthorities(user) - ); - } - - } - - public static ExecutorService newThreadPool() { - ThreadFactory namedThreadFactory = new ThreadFactory() { - final AtomicInteger sequence = new AtomicInteger(1); - - @Override - public Thread newThread(Runnable r) { - Thread thread = new Thread(r); - int seq = this.sequence.getAndIncrement(); - thread.setName("future-task-thread" + (seq > 1 ? "-" + seq : "")); - if (!thread.isDaemon()) { - thread.setDaemon(true); - } - - return thread; - } - }; - return new ThreadPoolExecutor(10, 200, - 0L, TimeUnit.MILLISECONDS, - new LinkedBlockingQueue<>(1024), - namedThreadFactory, - new ThreadPoolExecutor.AbortPolicy()); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthorityDto.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthorityDto.java new file mode 100644 index 00000000..888cceb6 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/AuthorityDto.java @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.security.service.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; + +/** + * 避免序列化问题 + * @author Zheng Jie + * @date 2018-11-30 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AuthorityDto implements GrantedAuthority { + + private String authority; +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java index 00f4372c..5aa0c45f 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/security/service/dto/JwtUserDto.java @@ -18,8 +18,7 @@ package me.zhengjie.modules.security.service.dto; import com.alibaba.fastjson.annotation.JSONField; import lombok.AllArgsConstructor; import lombok.Getter; -import me.zhengjie.modules.system.service.dto.UserDto; -import org.springframework.security.core.GrantedAuthority; +import me.zhengjie.modules.system.service.dto.UserLoginDto; import org.springframework.security.core.userdetails.UserDetails; import java.util.List; import java.util.Set; @@ -33,15 +32,14 @@ import java.util.stream.Collectors; @AllArgsConstructor public class JwtUserDto implements UserDetails { - private final UserDto user; + private final UserLoginDto user; private final List dataScopes; - @JSONField(serialize = false) - private final List authorities; + private final List authorities; public Set getRoles() { - return authorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet()); + return authorities.stream().map(AuthorityDto::getAuthority).collect(Collectors.toSet()); } @Override diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java index 65e4f587..feb614b9 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/RoleService.java @@ -15,13 +15,13 @@ */ package me.zhengjie.modules.system.service; +import me.zhengjie.modules.security.service.dto.AuthorityDto; import me.zhengjie.modules.system.domain.Role; import me.zhengjie.modules.system.service.dto.RoleDto; import me.zhengjie.modules.system.service.dto.RoleQueryCriteria; import me.zhengjie.modules.system.service.dto.RoleSmallDto; import me.zhengjie.modules.system.service.dto.UserDto; import org.springframework.data.domain.Pageable; -import org.springframework.security.core.GrantedAuthority; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.List; @@ -119,7 +119,7 @@ public interface RoleService { * @param user 用户信息 * @return 权限信息 */ - List mapToGrantedAuthorities(UserDto user); + List mapToGrantedAuthorities(UserDto user); /** * 验证是否被用户关联 diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/UserService.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/UserService.java index babf592f..8d63fa86 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/UserService.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/UserService.java @@ -17,6 +17,7 @@ package me.zhengjie.modules.system.service; import me.zhengjie.modules.system.domain.User; import me.zhengjie.modules.system.service.dto.UserDto; +import me.zhengjie.modules.system.service.dto.UserLoginDto; import me.zhengjie.modules.system.service.dto.UserQueryCriteria; import org.springframework.data.domain.Pageable; import org.springframework.web.multipart.MultipartFile; @@ -65,6 +66,13 @@ public interface UserService { */ UserDto findByName(String userName); + /** + * 根据用户名查询 + * @param userName / + * @return / + */ + UserLoginDto getLoginData(String userName); + /** * 修改密码 * @param username 用户名 diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/UserLoginDto.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/UserLoginDto.java new file mode 100644 index 00000000..13a51f77 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/dto/UserLoginDto.java @@ -0,0 +1,28 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.dto; + +/** + * @author Zheng Jie + * @description 用户缓存时使用 + * @date 2022-05-26 + **/ +public class UserLoginDto extends UserDto { + + private String password; + + private Boolean isAdmin; +} diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java index e8b41438..def575ea 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/RoleServiceImpl.java @@ -18,7 +18,8 @@ package me.zhengjie.modules.system.service.impl; import cn.hutool.core.collection.CollectionUtil; import lombok.RequiredArgsConstructor; import me.zhengjie.exception.BadRequestException; -import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.security.service.UserCacheManager; +import me.zhengjie.modules.security.service.dto.AuthorityDto; import me.zhengjie.modules.system.domain.Menu; import me.zhengjie.modules.system.domain.Role; import me.zhengjie.exception.EntityExistException; @@ -38,11 +39,8 @@ import org.springframework.cache.annotation.Cacheable; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.*; @@ -62,7 +60,7 @@ public class RoleServiceImpl implements RoleService { private final RoleSmallMapper roleSmallMapper; private final RedisUtils redisUtils; private final UserRepository userRepository; - private final UserCacheClean userCacheClean; + private final UserCacheManager userCacheManager; @Override public List queryAll() { @@ -166,19 +164,19 @@ public class RoleServiceImpl implements RoleService { @Override @Cacheable(key = "'auth:' + #p0.id") - public List mapToGrantedAuthorities(UserDto user) { + public List mapToGrantedAuthorities(UserDto user) { Set permissions = new HashSet<>(); // 如果是管理员直接返回 if (user.getIsAdmin()) { permissions.add("admin"); - return permissions.stream().map(SimpleGrantedAuthority::new) + return permissions.stream().map(AuthorityDto::new) .collect(Collectors.toList()); } Set roles = roleRepository.findByUserId(user.getId()); permissions = roles.stream().flatMap(role -> role.getMenus().stream()) - .filter(menu -> StringUtils.isNotBlank(menu.getPermission())) - .map(Menu::getPermission).collect(Collectors.toSet()); - return permissions.stream().map(SimpleGrantedAuthority::new) + .map(Menu::getPermission) + .filter(StringUtils::isNotBlank).collect(Collectors.toSet()); + return permissions.stream().map(AuthorityDto::new) .collect(Collectors.toList()); } @@ -215,7 +213,7 @@ public class RoleServiceImpl implements RoleService { public void delCaches(Long id, List users) { users = CollectionUtil.isEmpty(users) ? userRepository.findByRoleId(id) : users; if (CollectionUtil.isNotEmpty(users)) { - users.forEach(item -> userCacheClean.cleanUserCache(item.getUsername())); + users.forEach(item -> userCacheManager.cleanUserCache(item.getUsername())); Set userIds = users.stream().map(User::getId).collect(Collectors.toSet()); redisUtils.delByKeys(CacheKey.DATA_USER, userIds); redisUtils.delByKeys(CacheKey.MENU_USER, userIds); diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java index 3d96c23e..6342d130 100644 --- a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/impl/UserServiceImpl.java @@ -19,16 +19,14 @@ import lombok.RequiredArgsConstructor; import me.zhengjie.config.FileProperties; import me.zhengjie.exception.BadRequestException; import me.zhengjie.modules.security.service.OnlineUserService; -import me.zhengjie.modules.security.service.UserCacheClean; +import me.zhengjie.modules.security.service.UserCacheManager; import me.zhengjie.modules.system.domain.User; import me.zhengjie.exception.EntityExistException; import me.zhengjie.exception.EntityNotFoundException; import me.zhengjie.modules.system.repository.UserRepository; import me.zhengjie.modules.system.service.UserService; -import me.zhengjie.modules.system.service.dto.JobSmallDto; -import me.zhengjie.modules.system.service.dto.RoleSmallDto; -import me.zhengjie.modules.system.service.dto.UserDto; -import me.zhengjie.modules.system.service.dto.UserQueryCriteria; +import me.zhengjie.modules.system.service.dto.*; +import me.zhengjie.modules.system.service.mapstruct.UserLoginMapper; import me.zhengjie.modules.system.service.mapstruct.UserMapper; import me.zhengjie.utils.*; import org.springframework.cache.annotation.CacheConfig; @@ -58,8 +56,9 @@ public class UserServiceImpl implements UserService { private final UserMapper userMapper; private final FileProperties properties; private final RedisUtils redisUtils; - private final UserCacheClean userCacheClean; + private final UserCacheManager userCacheManager; private final OnlineUserService onlineUserService; + private final UserLoginMapper userLoginMapper; @Override public Object queryAll(UserQueryCriteria criteria, Pageable pageable) { @@ -175,6 +174,16 @@ public class UserServiceImpl implements UserService { } } + @Override + public UserLoginDto getLoginData(String userName) { + User user = userRepository.findByUsername(userName); + if (user == null) { + throw new EntityNotFoundException(User.class, "name", userName); + } else { + return userLoginMapper.toDto(user); + } + } + @Override @Transactional(rollbackFor = Exception.class) public void updatePass(String username, String pass) { @@ -252,6 +261,6 @@ public class UserServiceImpl implements UserService { * @param username / */ private void flushCache(String username) { - userCacheClean.cleanUserCache(username); + userCacheManager.cleanUserCache(username); } } diff --git a/eladmin-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserLoginMapper.java b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserLoginMapper.java new file mode 100644 index 00000000..fbb88139 --- /dev/null +++ b/eladmin-system/src/main/java/me/zhengjie/modules/system/service/mapstruct/UserLoginMapper.java @@ -0,0 +1,30 @@ +/* + * Copyright 2019-2020 Zheng Jie + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package me.zhengjie.modules.system.service.mapstruct; + +import me.zhengjie.base.BaseMapper; +import me.zhengjie.modules.system.domain.User; +import me.zhengjie.modules.system.service.dto.UserLoginDto; +import org.mapstruct.Mapper; +import org.mapstruct.ReportingPolicy; + +/** + * @author Zheng Jie + * @date 2018-11-23 + */ +@Mapper(componentModel = "spring",uses = {RoleMapper.class, DeptMapper.class, JobMapper.class},unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface UserLoginMapper extends BaseMapper { +} diff --git a/eladmin-system/src/main/resources/banner.txt b/eladmin-system/src/main/resources/banner.txt index d0f401a8..fc2a4370 100644 --- a/eladmin-system/src/main/resources/banner.txt +++ b/eladmin-system/src/main/resources/banner.txt @@ -5,4 +5,4 @@ | __| | | (_| | (_| | | | | | | | | | | \___|_| \__,_|\__,_|_| |_| |_|_|_| |_| - :: Spring Boot :: (v2.1.0.RELEASE) \ No newline at end of file + :: Spring Boot :: (v2.2.10.RELEASE) \ No newline at end of file diff --git a/eladmin-system/src/main/resources/config/application-dev.yml b/eladmin-system/src/main/resources/config/application-dev.yml index c7188533..c96a9233 100644 --- a/eladmin-system/src/main/resources/config/application-dev.yml +++ b/eladmin-system/src/main/resources/config/application-dev.yml @@ -51,10 +51,12 @@ spring: # 登录相关配置 login: - # 登录缓存 - cache-enable: true # 是否限制单用户登录 single-login: false + # Redis用户登录缓存配置 + user-cache: + # 存活时间/秒 + idle-time: 7200 # 验证码 login-code: # 验证码类型配置 查看 LoginProperties 类 diff --git a/eladmin-system/src/main/resources/config/application-prod.yml b/eladmin-system/src/main/resources/config/application-prod.yml index 52e52ddf..03b6e994 100644 --- a/eladmin-system/src/main/resources/config/application-prod.yml +++ b/eladmin-system/src/main/resources/config/application-prod.yml @@ -33,6 +33,7 @@ spring: webStatFilter: enabled: true stat-view-servlet: + allow: enabled: true # 控制台管理用户名和密码 url-pattern: /druid/* @@ -52,10 +53,12 @@ spring: # 登录相关配置 login: - # 登录缓存 - cache-enable: true # 是否限制单用户登录 single-login: false + # Redis用户登录缓存配置 + user-cache: + # 存活时间/秒 + idle-time: 7200 # 验证码 login-code: # 验证码类型配置 查看 LoginProperties 类 @@ -93,7 +96,7 @@ jwt: # IP 本地解析 ip: - local-parsing: false + local-parsing: true #是否允许生成代码,生产环境设置为false generator: diff --git a/eladmin-system/src/main/resources/config/application.yml b/eladmin-system/src/main/resources/config/application.yml index 587785ab..6caf386c 100644 --- a/eladmin-system/src/main/resources/config/application.yml +++ b/eladmin-system/src/main/resources/config/application.yml @@ -55,13 +55,4 @@ code: #密码加密传输,前端公钥加密,后端私钥解密 rsa: - private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== - -# 内存用户缓存配置 -user-cache: - # 最小回收数(当缓存数量达到此值时进行回收) - min-evictable-size: 512 - # 最小回收间隔 - min-evictable-interval: 1800000 - # 最小存活时间 (ms) - min-idle-time: 3600000 \ No newline at end of file + private_key: MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEA0vfvyTdGJkdbHkB8mp0f3FE0GYP3AYPaJF7jUd1M0XxFSE2ceK3k2kw20YvQ09NJKk+OMjWQl9WitG9pB6tSCQIDAQABAkA2SimBrWC2/wvauBuYqjCFwLvYiRYqZKThUS3MZlebXJiLB+Ue/gUifAAKIg1avttUZsHBHrop4qfJCwAI0+YRAiEA+W3NK/RaXtnRqmoUUkb59zsZUBLpvZgQPfj1MhyHDz0CIQDYhsAhPJ3mgS64NbUZmGWuuNKp5coY2GIj/zYDMJp6vQIgUueLFXv/eZ1ekgz2Oi67MNCk5jeTF2BurZqNLR3MSmUCIFT3Q6uHMtsB9Eha4u7hS31tj1UWE+D+ADzp59MGnoftAiBeHT7gDMuqeJHPL4b+kC+gzV4FGTfhR9q3tTbklZkD2A== \ No newline at end of file diff --git a/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java b/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java deleted file mode 100644 index 4cae4a8f..00000000 --- a/eladmin-system/src/test/java/me/zhengjie/LoginCacheTest.java +++ /dev/null @@ -1,64 +0,0 @@ -package me.zhengjie; - -import me.zhengjie.modules.security.service.UserDetailsServiceImpl; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit4.SpringRunner; - -import javax.annotation.Resource; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; - -@RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) -public class LoginCacheTest { - - @Resource(name = "userDetailsService") - private UserDetailsServiceImpl userDetailsService; - ExecutorService executor = Executors.newCachedThreadPool(); - - @Test - public void testCache() throws InterruptedException { - long start1 = System.currentTimeMillis(); - int size = 1000; - CountDownLatch latch = new CountDownLatch(size); - for (int i = 0; i < size; i++) { - executor.submit(() -> userDetailsService.loadUserByUsername("admin")); - latch.countDown(); - } - latch.await(); - - long end1 = System.currentTimeMillis(); - //关闭缓存 - userDetailsService.setEnableCache(false); - long start2 = System.currentTimeMillis(); - for (int i = 0; i < size; i++) { - userDetailsService.loadUserByUsername("admin"); - } - long end2 = System.currentTimeMillis(); - System.out.print("使用缓存:" + (end1 - start1) + "毫秒\n 不使用缓存:" + (end2 - start2) + "毫秒"); - } - - @Test - public void testCacheManager() throws InterruptedException { - int size = 1000; - CountDownLatch latch = new CountDownLatch(size); - for (int i = 0; i < size; i++) { - int mod = i % 10; - executor.submit(() -> { - try { - Thread.sleep(mod * 2 + (int) (Math.random() * 10000)); - } catch (InterruptedException e) { - e.printStackTrace(); - } - userDetailsService.loadUserByUsername("admin" + mod); - latch.countDown(); - System.out.println("剩余未完成数量" + latch.getCount()); - }); - } - latch.await(); - } - -} diff --git a/pom.xml b/pom.xml index 0f82d1a1..1f64d700 100644 --- a/pom.xml +++ b/pom.xml @@ -34,7 +34,7 @@ 1.8 1.16 2.9.2 - 1.2.70 + 1.2.83 1.1.24 2.5.0 1.3.1.Final