成功集成ehcache,并拿到了它的缓存
This commit is contained in:
parent
675a953025
commit
1c768d6607
@ -12,18 +12,15 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.google.code.kaptcha.Producer;
|
import com.google.code.kaptcha.Producer;
|
||||||
import com.ruoyi.common.annotation.Anonymous;
|
|
||||||
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.common.config.RuoYiConfig;
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.sign.Base64;
|
import com.ruoyi.common.utils.sign.Base64;
|
||||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||||
import com.ruoyi.system.service.ISysConfigService;
|
import com.ruoyi.system.service.ISysConfigService;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
@ -32,7 +29,6 @@ import jakarta.servlet.http.HttpServletResponse;
|
|||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Tag(name = "验证码")
|
|
||||||
@RestController
|
@RestController
|
||||||
public class CaptchaController {
|
public class CaptchaController {
|
||||||
@Resource(name = "captchaProducer")
|
@Resource(name = "captchaProducer")
|
||||||
@ -41,17 +37,12 @@ public class CaptchaController {
|
|||||||
@Resource(name = "captchaProducerMath")
|
@Resource(name = "captchaProducerMath")
|
||||||
private Producer captchaProducerMath;
|
private Producer captchaProducerMath;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysConfigService configService;
|
private ISysConfigService configService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成验证码
|
* 生成验证码
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "获取验证码")
|
|
||||||
@Anonymous
|
|
||||||
@GetMapping("/captchaImage")
|
@GetMapping("/captchaImage")
|
||||||
public AjaxResult getCode(HttpServletResponse response) throws IOException {
|
public AjaxResult getCode(HttpServletResponse response) throws IOException {
|
||||||
AjaxResult ajax = AjaxResult.success();
|
AjaxResult ajax = AjaxResult.success();
|
||||||
@ -60,14 +51,10 @@ public class CaptchaController {
|
|||||||
if (!captchaEnabled) {
|
if (!captchaEnabled) {
|
||||||
return ajax;
|
return ajax;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存验证码信息
|
// 保存验证码信息
|
||||||
String uuid = IdUtils.simpleUUID();
|
String uuid = IdUtils.simpleUUID();
|
||||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
|
|
||||||
|
|
||||||
String capStr = null, code = null;
|
String capStr = null, code = null;
|
||||||
BufferedImage image = null;
|
BufferedImage image = null;
|
||||||
|
|
||||||
// 生成验证码
|
// 生成验证码
|
||||||
String captchaType = RuoYiConfig.getCaptchaType();
|
String captchaType = RuoYiConfig.getCaptchaType();
|
||||||
if ("math".equals(captchaType)) {
|
if ("math".equals(captchaType)) {
|
||||||
@ -79,8 +66,7 @@ public class CaptchaController {
|
|||||||
capStr = code = captchaProducer.createText();
|
capStr = code = captchaProducer.createText();
|
||||||
image = captchaProducer.createImage(capStr);
|
image = captchaProducer.createImage(capStr);
|
||||||
}
|
}
|
||||||
|
CacheUtils.put(CacheConstants.CAPTCHA_CODE_KEY, uuid, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
||||||
redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
|
|
||||||
// 转换流信息写出
|
// 转换流信息写出
|
||||||
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
FastByteArrayOutputStream os = new FastByteArrayOutputStream();
|
||||||
try {
|
try {
|
||||||
@ -88,7 +74,6 @@ public class CaptchaController {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return AjaxResult.error(e.getMessage());
|
return AjaxResult.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
ajax.put("uuid", uuid);
|
ajax.put("uuid", uuid);
|
||||||
ajax.put("img", Base64.encode(os.toByteArray()));
|
ajax.put("img", Base64.encode(os.toByteArray()));
|
||||||
return ajax;
|
return ajax;
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
package com.ruoyi.web.controller.monitor;
|
package com.ruoyi.web.controller.monitor;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.cache.Cache.ValueWrapper;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
import org.springframework.data.redis.core.RedisCallback;
|
import org.springframework.data.redis.core.RedisCallback;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
@ -20,6 +19,8 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
|
import com.ruoyi.common.core.text.Convert;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.system.domain.SysCache;
|
import com.ruoyi.system.domain.SysCache;
|
||||||
|
|
||||||
@ -38,8 +39,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
@RequestMapping("/monitor/cache")
|
@RequestMapping("/monitor/cache")
|
||||||
public class CacheController
|
public class CacheController
|
||||||
{
|
{
|
||||||
@Autowired
|
private static String tmpCacheName = "";
|
||||||
private RedisTemplate<String, String> redisTemplate;
|
|
||||||
|
|
||||||
private final static List<SysCache> caches = new ArrayList<SysCache>();
|
private final static List<SysCache> caches = new ArrayList<SysCache>();
|
||||||
{
|
{
|
||||||
@ -57,11 +57,12 @@ public class CacheController
|
|||||||
@GetMapping()
|
@GetMapping()
|
||||||
public AjaxResult getInfo() throws Exception
|
public AjaxResult getInfo() throws Exception
|
||||||
{
|
{
|
||||||
Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.serverCommands().info());
|
|
||||||
Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.serverCommands().info("commandstats"));
|
|
||||||
Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.serverCommands().dbSize());
|
|
||||||
|
|
||||||
Map<String, Object> result = new HashMap<>(3);
|
Map<String, Object> result = new HashMap<>(3);
|
||||||
|
if (CacheUtils.getCacheManager() instanceof RedisCacheManager)
|
||||||
|
{
|
||||||
|
Properties info = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info());
|
||||||
|
Properties commandStats = (Properties) CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
|
||||||
|
Object dbSize = CacheUtils.getRedisTemplate().execute((RedisCallback<Object>) connection -> connection.dbSize());
|
||||||
result.put("info", info);
|
result.put("info", info);
|
||||||
result.put("dbSize", dbSize);
|
result.put("dbSize", dbSize);
|
||||||
|
|
||||||
@ -74,6 +75,7 @@ public class CacheController
|
|||||||
pieList.add(data);
|
pieList.add(data);
|
||||||
});
|
});
|
||||||
result.put("commandStats", pieList);
|
result.put("commandStats", pieList);
|
||||||
|
}
|
||||||
return AjaxResult.success(result);
|
return AjaxResult.success(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +93,11 @@ public class CacheController
|
|||||||
})
|
})
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@GetMapping("/getKeys/{cacheName}")
|
@GetMapping("/getKeys/{cacheName}")
|
||||||
public AjaxResult getCacheKeys(@PathVariable( name = "cacheName" ) String cacheName)
|
public AjaxResult getCacheKeys(@PathVariable String cacheName)
|
||||||
{
|
{
|
||||||
Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
|
tmpCacheName = cacheName;
|
||||||
return AjaxResult.success(cacheKeys);
|
Set<String> keyset = CacheUtils.getkeys(cacheName);
|
||||||
|
return AjaxResult.success(keyset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "获取缓存值列表")
|
@Operation(summary = "获取缓存值列表")
|
||||||
@ -104,10 +107,16 @@ public class CacheController
|
|||||||
})
|
})
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@GetMapping("/getValue/{cacheName}/{cacheKey}")
|
@GetMapping("/getValue/{cacheName}/{cacheKey}")
|
||||||
public AjaxResult getCacheValue(@PathVariable( name = "cacheKey" ) String cacheName, @PathVariable String cacheKey)
|
public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
|
||||||
{
|
{
|
||||||
String cacheValue = redisTemplate.opsForValue().get(cacheKey);
|
ValueWrapper valueWrapper = CacheUtils.get(cacheName, cacheKey);
|
||||||
SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
|
SysCache sysCache = new SysCache();
|
||||||
|
sysCache.setCacheName(cacheName);
|
||||||
|
sysCache.setCacheKey(cacheKey);
|
||||||
|
if (StringUtils.isNotNull(valueWrapper))
|
||||||
|
{
|
||||||
|
sysCache.setCacheValue(Convert.toStr(valueWrapper.get(), ""));
|
||||||
|
}
|
||||||
return AjaxResult.success(sysCache);
|
return AjaxResult.success(sysCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,10 +126,9 @@ public class CacheController
|
|||||||
})
|
})
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@DeleteMapping("/clearCacheName/{cacheName}")
|
@DeleteMapping("/clearCacheName/{cacheName}")
|
||||||
public AjaxResult clearCacheName(@PathVariable( name = "cacheName" ) String cacheName)
|
public AjaxResult clearCacheName(@PathVariable String cacheName)
|
||||||
{
|
{
|
||||||
Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
|
CacheUtils.clear(cacheName);
|
||||||
redisTemplate.delete(cacheKeys);
|
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,19 +138,20 @@ public class CacheController
|
|||||||
})
|
})
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@DeleteMapping("/clearCacheKey/{cacheKey}")
|
@DeleteMapping("/clearCacheKey/{cacheKey}")
|
||||||
public AjaxResult clearCacheKey(@PathVariable( name = "cacheKey" ) String cacheKey)
|
public AjaxResult clearCacheKey(@PathVariable String cacheKey)
|
||||||
{
|
{
|
||||||
redisTemplate.delete(cacheKey);
|
CacheUtils.removeIfPresent(tmpCacheName, cacheKey);
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Operation(summary = "清除所有缓存")
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
|
||||||
@DeleteMapping("/clearCacheAll")
|
@DeleteMapping("/clearCacheAll")
|
||||||
public AjaxResult clearCacheAll()
|
public AjaxResult clearCacheAll()
|
||||||
{
|
{
|
||||||
Collection<String> cacheKeys = redisTemplate.keys("*");
|
for (String cacheName : CacheUtils.getCacheManager().getCacheNames())
|
||||||
redisTemplate.delete(cacheKeys);
|
{
|
||||||
|
CacheUtils.clear(cacheName);
|
||||||
|
}
|
||||||
return AjaxResult.success();
|
return AjaxResult.success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.DeleteMapping;
|
|||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.annotation.Log;
|
||||||
@ -20,52 +19,47 @@ import com.ruoyi.common.core.controller.BaseController;
|
|||||||
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.enums.BusinessType;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.system.domain.SysUserOnline;
|
import com.ruoyi.system.domain.SysUserOnline;
|
||||||
import com.ruoyi.system.service.ISysUserOnlineService;
|
import com.ruoyi.system.service.ISysUserOnlineService;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter;
|
|
||||||
import io.swagger.v3.oas.annotations.Parameters;
|
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 在线用户监控
|
* 在线用户监控
|
||||||
*
|
*
|
||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Tag(name = "在线用户监控")
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/monitor/online")
|
@RequestMapping("/monitor/online")
|
||||||
public class SysUserOnlineController extends BaseController {
|
public class SysUserOnlineController extends BaseController
|
||||||
|
{
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserOnlineService userOnlineService;
|
private ISysUserOnlineService userOnlineService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@Operation(summary = "获取在线用户列表")
|
|
||||||
@Parameters({
|
|
||||||
@Parameter(name = "ipaddr", description = "ip地址", required = false),
|
|
||||||
@Parameter(name = "userName", description = "用户名", required = false),
|
|
||||||
})
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
|
@PreAuthorize("@ss.hasPermi('monitor:online:list')")
|
||||||
@GetMapping("/list")
|
@GetMapping("/list")
|
||||||
public TableDataInfo list(@RequestParam(name = "ipaddr", required = false) String ipaddr,
|
public TableDataInfo list(String ipaddr, String userName)
|
||||||
@RequestParam(name = "userName", required = false) String userName) {
|
{
|
||||||
Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
|
Collection<String> keys = CacheUtils.getkeys(CacheConstants.LOGIN_TOKEN_KEY);
|
||||||
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
|
List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
|
||||||
for (String key : keys) {
|
for (String key : keys)
|
||||||
LoginUser user = redisCache.getCacheObject(key);
|
{
|
||||||
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
|
LoginUser user = CacheUtils.get(CacheConstants.LOGIN_TOKEN_KEY, key, LoginUser.class);
|
||||||
|
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
|
||||||
|
{
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
|
userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
|
||||||
} else if (StringUtils.isNotEmpty(ipaddr)) {
|
}
|
||||||
|
else if (StringUtils.isNotEmpty(ipaddr))
|
||||||
|
{
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
|
userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
|
||||||
} else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) {
|
}
|
||||||
|
else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
|
||||||
|
{
|
||||||
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
|
userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
|
userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,15 +71,12 @@ public class SysUserOnlineController extends BaseController {
|
|||||||
/**
|
/**
|
||||||
* 强退用户
|
* 强退用户
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "强退用户")
|
|
||||||
@Parameters({
|
|
||||||
@Parameter(name = "tokenId", description = "用户凭证", required = true),
|
|
||||||
})
|
|
||||||
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
|
@PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
|
||||||
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
||||||
@DeleteMapping("/{tokenId}")
|
@DeleteMapping("/{tokenId}")
|
||||||
public AjaxResult forceLogout(@PathVariable(name = "tokenId") String tokenId) {
|
public AjaxResult forceLogout(@PathVariable String tokenId)
|
||||||
redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
|
{
|
||||||
|
CacheUtils.removeIfPresent(CacheConstants.LOGIN_TOKEN_KEY, tokenId);
|
||||||
return success();
|
return success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,16 @@ user:
|
|||||||
|
|
||||||
# Spring配置
|
# Spring配置
|
||||||
spring:
|
spring:
|
||||||
|
cache:
|
||||||
|
# 指定缓存类型 jcache 本地缓存 redis 缓存
|
||||||
|
type: jcache
|
||||||
|
redis:
|
||||||
|
# 指定存活时间(ms)
|
||||||
|
time-to-live: 86400000
|
||||||
|
# 指定前缀
|
||||||
|
use-key-prefix: true
|
||||||
|
# 是否缓存空值,可以防止缓存穿透
|
||||||
|
cache-null-values: true
|
||||||
mvc:
|
mvc:
|
||||||
pathmatch:
|
pathmatch:
|
||||||
matching-strategy: ANT_PATH_MATCHER
|
matching-strategy: ANT_PATH_MATCHER
|
||||||
|
@ -105,6 +105,11 @@
|
|||||||
<groupId>javax.xml.bind</groupId>
|
<groupId>javax.xml.bind</groupId>
|
||||||
<artifactId>jaxb-api</artifactId>
|
<artifactId>jaxb-api</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.sun.xml.bind</groupId>
|
||||||
|
<artifactId>jaxb-core</artifactId>
|
||||||
|
<version>2.3.0.1</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- redis 缓存操作 -->
|
<!-- redis 缓存操作 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -157,6 +162,23 @@
|
|||||||
<groupId>org.projectlombok</groupId>
|
<groupId>org.projectlombok</groupId>
|
||||||
<artifactId>lombok</artifactId>
|
<artifactId>lombok</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- SpringCache的依赖配置 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Ehcache缓存管理器 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.ehcache</groupId>
|
||||||
|
<artifactId>ehcache</artifactId>
|
||||||
|
<version>3.10.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javax.cache</groupId>
|
||||||
|
<artifactId>cache-api</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@ -10,35 +10,35 @@ public class CacheConstants
|
|||||||
/**
|
/**
|
||||||
* 登录用户 redis key
|
* 登录用户 redis key
|
||||||
*/
|
*/
|
||||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
public static final String LOGIN_TOKEN_KEY = "login_tokens";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码 redis key
|
* 验证码 redis key
|
||||||
*/
|
*/
|
||||||
public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
|
public static final String CAPTCHA_CODE_KEY = "captcha_codes";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数管理 cache key
|
* 参数管理 cache key
|
||||||
*/
|
*/
|
||||||
public static final String SYS_CONFIG_KEY = "sys_config:";
|
public static final String SYS_CONFIG_KEY = "sys_config";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字典管理 cache key
|
* 字典管理 cache key
|
||||||
*/
|
*/
|
||||||
public static final String SYS_DICT_KEY = "sys_dict:";
|
public static final String SYS_DICT_KEY = "sys_dict";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 防重提交 redis key
|
* 防重提交 redis key
|
||||||
*/
|
*/
|
||||||
public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
|
public static final String REPEAT_SUBMIT_KEY = "repeat_submit";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 限流 redis key
|
* 限流 redis key
|
||||||
*/
|
*/
|
||||||
public static final String RATE_LIMIT_KEY = "rate_limit:";
|
public static final String RATE_LIMIT_KEY = "rate_limit";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录账户密码错误次数 redis key
|
* 登录账户密码错误次数 redis key
|
||||||
*/
|
*/
|
||||||
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
|
public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt";
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,201 @@
|
|||||||
|
package com.ruoyi.common.utils;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.ehcache.core.EhcacheBase;
|
||||||
|
import org.ehcache.impl.internal.concurrent.ConcurrentHashMap;
|
||||||
|
import org.ehcache.impl.internal.store.heap.OnHeapStore;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
|
import org.springframework.cache.jcache.JCacheCache;
|
||||||
|
import org.springframework.cache.transaction.TransactionAwareCacheDecorator;
|
||||||
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
||||||
|
|
||||||
|
public class CacheUtils {
|
||||||
|
/**
|
||||||
|
* 使用redis时对redis进行单独特殊操作需要使用
|
||||||
|
*
|
||||||
|
* @param <K>
|
||||||
|
* @param <V>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <K, V> RedisTemplate<K, V> getRedisTemplate() {
|
||||||
|
return SpringUtils.getBean("redisTemplate");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取CacheManager
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static CacheManager getCacheManager() {
|
||||||
|
return SpringUtils.getBean(CacheManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据cacheName从CacheManager中获取cache
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Cache getCache(String cacheName) {
|
||||||
|
return getCacheManager().getCache(cacheName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取缓存的所有key值(由于springcache不支持获取所有key,只能根据cache类型来单独获取)
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||||
|
public static Set<String> getkeys(String cacheName) {
|
||||||
|
Cache cache = getCacheManager().getCache(cacheName);
|
||||||
|
Set<String> keyset = new HashSet<>();
|
||||||
|
if (cache instanceof JCacheCache) {
|
||||||
|
try {
|
||||||
|
JCacheCache jehcache = (JCacheCache) cache;
|
||||||
|
// org.ehcache.jsr107.Eh107Cache 不公开
|
||||||
|
Object nativeCache = jehcache.getNativeCache();
|
||||||
|
Class<?> nativeCacheClass = nativeCache.getClass();
|
||||||
|
Field ehCacheField = nativeCacheClass.getDeclaredField("ehCache");
|
||||||
|
ehCacheField.setAccessible(true);
|
||||||
|
EhcacheBase ehcache = (EhcacheBase) ehCacheField.get(nativeCache);
|
||||||
|
Field storeField = EhcacheBase.class.getDeclaredField("store");
|
||||||
|
storeField.setAccessible(true);
|
||||||
|
OnHeapStore store = (OnHeapStore) storeField.get(ehcache);
|
||||||
|
Field mapField = OnHeapStore.class.getDeclaredField("map");
|
||||||
|
mapField.setAccessible(true);
|
||||||
|
// org.ehcache.impl.internal.store.heap.Backend 不公开
|
||||||
|
Object map = mapField.get(store);
|
||||||
|
Class<?> mapClass = map.getClass();
|
||||||
|
Field realMapField = mapClass.getDeclaredField("realMap");
|
||||||
|
realMapField.setAccessible(true);
|
||||||
|
ConcurrentHashMap<String, ?> realMap = (ConcurrentHashMap<String, ?>) realMapField.get(map);
|
||||||
|
keyset = realMap.keySet();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (cache instanceof TransactionAwareCacheDecorator) {
|
||||||
|
Set<Object> keysets = getRedisTemplate().keys(cache.getName() + "*");
|
||||||
|
for (Object s : keysets) {
|
||||||
|
keyset.add(StringUtils.replace(s.toString(), cache.getName() + ":", ""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyset;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据cacheName,key缓存数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static <T> void put(String cacheName, String key, T value) {
|
||||||
|
put(cacheName, key, value, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果没有则进行缓存,根据cacheName,key缓存数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static <T> void putIfAbsent(String cacheName, String key, T value) {
|
||||||
|
if (ObjectUtils.isEmpty(get(cacheName, key))) {
|
||||||
|
put(cacheName, key, value, 0, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据cacheName,key和缓存过期时间进行缓存数据,使用各种不同缓存可以单独进行操作
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param value
|
||||||
|
* @param timeout
|
||||||
|
* @param unit
|
||||||
|
* @param <T>
|
||||||
|
*/
|
||||||
|
public static <T> void put(String cacheName, String key, T value, long timeout, TimeUnit unit) {
|
||||||
|
Cache cache = getCacheManager().getCache(cacheName);
|
||||||
|
if (cache instanceof JCacheCache) {
|
||||||
|
JCacheCache ehcache = (JCacheCache) cache;
|
||||||
|
ehcache.put(key, value);
|
||||||
|
} else if (cache instanceof TransactionAwareCacheDecorator) {
|
||||||
|
if (timeout != 0 && unit != null) {
|
||||||
|
getRedisTemplate().opsForValue().set(cacheName + ":" + key, value, timeout, unit);
|
||||||
|
} else {
|
||||||
|
getRedisTemplate().opsForValue().set(cacheName + ":" + key, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cache.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static Cache.ValueWrapper get(String cacheName, String key) {
|
||||||
|
return getCacheManager().getCache(cacheName).get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据类型获取数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @param type
|
||||||
|
* @param <T>
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static <T> T get(String cacheName, String key, @Nullable Class<T> type) {
|
||||||
|
return getCacheManager().getCache(cacheName).get(key, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除缓存数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
*/
|
||||||
|
public static void remove(String cacheName, String key) {
|
||||||
|
getCacheManager().getCache(cacheName).evict(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 如果存在则移除缓存数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
* @param key
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static boolean removeIfPresent(String cacheName, String key) {
|
||||||
|
remove(cacheName, key);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清除缓存名称为cacheName的所有缓存数据
|
||||||
|
*
|
||||||
|
* @param cacheName
|
||||||
|
*/
|
||||||
|
public static void clear(String cacheName) {
|
||||||
|
getCacheManager().getCache(cacheName).clear();
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,11 @@
|
|||||||
package com.ruoyi.common.utils;
|
package com.ruoyi.common.utils;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.alibaba.fastjson2.JSONArray;
|
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.core.domain.entity.SysDictData;
|
import com.ruoyi.common.core.domain.entity.SysDictData;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.utils.spring.SpringUtils;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 字典工具类
|
* 字典工具类
|
||||||
@ -28,7 +27,7 @@ public class DictUtils
|
|||||||
*/
|
*/
|
||||||
public static void setDictCache(String key, List<SysDictData> dictDatas)
|
public static void setDictCache(String key, List<SysDictData> dictDatas)
|
||||||
{
|
{
|
||||||
SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
|
getDictCacheKey().put(key, dictDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,12 +36,13 @@ public class DictUtils
|
|||||||
* @param key 参数键
|
* @param key 参数键
|
||||||
* @return dictDatas 字典数据列表
|
* @return dictDatas 字典数据列表
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
public static List<SysDictData> getDictCache(String key)
|
public static List<SysDictData> getDictCache(String key)
|
||||||
{
|
{
|
||||||
JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
|
List<SysDictData> arrayCache = (List<SysDictData>) getDictCacheKey().get(key, List.class);
|
||||||
if (StringUtils.isNotNull(arrayCache))
|
if (StringUtils.isNotNull(arrayCache))
|
||||||
{
|
{
|
||||||
return arrayCache.toList(SysDictData.class);
|
return arrayCache;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -83,7 +83,6 @@ public class DictUtils
|
|||||||
{
|
{
|
||||||
StringBuilder propertyString = new StringBuilder();
|
StringBuilder propertyString = new StringBuilder();
|
||||||
List<SysDictData> datas = getDictCache(dictType);
|
List<SysDictData> datas = getDictCache(dictType);
|
||||||
|
|
||||||
if (StringUtils.isNotNull(datas))
|
if (StringUtils.isNotNull(datas))
|
||||||
{
|
{
|
||||||
if (StringUtils.containsAny(separator, dictValue))
|
if (StringUtils.containsAny(separator, dictValue))
|
||||||
@ -126,7 +125,6 @@ public class DictUtils
|
|||||||
{
|
{
|
||||||
StringBuilder propertyString = new StringBuilder();
|
StringBuilder propertyString = new StringBuilder();
|
||||||
List<SysDictData> datas = getDictCache(dictType);
|
List<SysDictData> datas = getDictCache(dictType);
|
||||||
|
|
||||||
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
|
if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
|
||||||
{
|
{
|
||||||
for (SysDictData dict : datas)
|
for (SysDictData dict : datas)
|
||||||
@ -161,7 +159,7 @@ public class DictUtils
|
|||||||
*/
|
*/
|
||||||
public static void removeDictCache(String key)
|
public static void removeDictCache(String key)
|
||||||
{
|
{
|
||||||
SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
|
getDictCacheKey().evict(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -169,18 +167,16 @@ public class DictUtils
|
|||||||
*/
|
*/
|
||||||
public static void clearDictCache()
|
public static void clearDictCache()
|
||||||
{
|
{
|
||||||
Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
|
getDictCacheKey().clear();
|
||||||
SpringUtils.getBean(RedisCache.class).deleteObject(keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置cache key
|
* 获取dict缓存
|
||||||
*
|
*
|
||||||
* @param configKey 参数键
|
* @return 缓存Cache
|
||||||
* @return 缓存键key
|
|
||||||
*/
|
*/
|
||||||
public static String getCacheKey(String configKey)
|
public static Cache getDictCacheKey()
|
||||||
{
|
{
|
||||||
return CacheConstants.SYS_DICT_KEY + configKey;
|
return CacheUtils.getCache(CacheConstants.SYS_DICT_KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import org.aspectj.lang.reflect.MethodSignature;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.core.script.RedisScript;
|
import org.springframework.data.redis.core.script.RedisScript;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
@ -18,7 +19,6 @@ import org.springframework.stereotype.Component;
|
|||||||
import com.ruoyi.common.annotation.RateLimiter;
|
import com.ruoyi.common.annotation.RateLimiter;
|
||||||
import com.ruoyi.common.enums.LimitType;
|
import com.ruoyi.common.enums.LimitType;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
import com.ruoyi.common.utils.ip.IpUtils;
|
||||||
|
|
||||||
@ -29,7 +29,9 @@ import com.ruoyi.common.utils.ip.IpUtils;
|
|||||||
*/
|
*/
|
||||||
@Aspect
|
@Aspect
|
||||||
@Component
|
@Component
|
||||||
public class RateLimiterAspect {
|
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false)
|
||||||
|
public class RateLimiterAspect
|
||||||
|
{
|
||||||
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
|
||||||
|
|
||||||
private RedisTemplate<Object, Object> redisTemplate;
|
private RedisTemplate<Object, Object> redisTemplate;
|
||||||
@ -37,43 +39,49 @@ public class RateLimiterAspect {
|
|||||||
private RedisScript<Long> limitScript;
|
private RedisScript<Long> limitScript;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate) {
|
public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
|
||||||
|
{
|
||||||
this.redisTemplate = redisTemplate;
|
this.redisTemplate = redisTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public void setLimitScript(RedisScript<Long> limitScript) {
|
public void setLimitScript(RedisScript<Long> limitScript)
|
||||||
|
{
|
||||||
this.limitScript = limitScript;
|
this.limitScript = limitScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before("@annotation(rateLimiter)")
|
@Before("@annotation(rateLimiter)")
|
||||||
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable {
|
public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
|
||||||
|
{
|
||||||
int time = rateLimiter.time();
|
int time = rateLimiter.time();
|
||||||
int count = rateLimiter.count();
|
int count = rateLimiter.count();
|
||||||
|
|
||||||
String combineKey = getCombineKey(rateLimiter, point);
|
String combineKey = getCombineKey(rateLimiter, point);
|
||||||
List<Object> keys = Collections.singletonList(combineKey);
|
List<Object> keys = Collections.singletonList(combineKey);
|
||||||
try {
|
try
|
||||||
|
{
|
||||||
Long number = redisTemplate.execute(limitScript, keys, count, time);
|
Long number = redisTemplate.execute(limitScript, keys, count, time);
|
||||||
if (StringUtils.isNull(number) || number.intValue() > count) {
|
if (StringUtils.isNull(number) || number.intValue() > count)
|
||||||
|
{
|
||||||
throw new ServiceException("访问过于频繁,请稍候再试");
|
throw new ServiceException("访问过于频繁,请稍候再试");
|
||||||
}
|
}
|
||||||
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
|
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
|
||||||
} catch (ServiceException e) {
|
}
|
||||||
|
catch (ServiceException e)
|
||||||
|
{
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
throw new RuntimeException("服务器限流异常,请稍候再试");
|
throw new RuntimeException("服务器限流异常,请稍候再试");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point) {
|
public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
|
||||||
|
{
|
||||||
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
|
StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
|
||||||
if (rateLimiter.limitType() == LimitType.IP) {
|
if (rateLimiter.limitType() == LimitType.IP)
|
||||||
|
{
|
||||||
stringBuffer.append(IpUtils.getIpAddr()).append("-");
|
stringBuffer.append(IpUtils.getIpAddr()).append("-");
|
||||||
} else if (rateLimiter.limitType() == LimitType.USER) {
|
|
||||||
stringBuffer.append(SecurityUtils.getUserId()).append("-");
|
|
||||||
} else if (rateLimiter.limitType() == LimitType.DEPT) {
|
|
||||||
stringBuffer.append(SecurityUtils.getDeptId()).append("-");
|
|
||||||
}
|
}
|
||||||
MethodSignature signature = (MethodSignature) point.getSignature();
|
MethodSignature signature = (MethodSignature) point.getSignature();
|
||||||
Method method = signature.getMethod();
|
Method method = signature.getMethod();
|
||||||
|
@ -0,0 +1,48 @@
|
|||||||
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import javax.cache.CacheManager;
|
||||||
|
import javax.cache.Caching;
|
||||||
|
import javax.cache.configuration.MutableConfiguration;
|
||||||
|
import javax.cache.expiry.CreatedExpiryPolicy;
|
||||||
|
import javax.cache.expiry.Duration;
|
||||||
|
|
||||||
|
import org.ehcache.jsr107.EhcacheCachingProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.cache.annotation.EnableCaching;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableCaching
|
||||||
|
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "jcache", matchIfMissing = false)
|
||||||
|
public class Ehcache3Config {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CacheManager ehcacheManager() {
|
||||||
|
EhcacheCachingProvider cachingProvider = (EhcacheCachingProvider) Caching.getCachingProvider();
|
||||||
|
|
||||||
|
CacheManager cacheManager = (CacheManager) cachingProvider.getCacheManager();
|
||||||
|
MutableConfiguration<String, Object> mutableConfiguration = new MutableConfiguration<>();
|
||||||
|
mutableConfiguration.setTypes(String.class, Object.class);
|
||||||
|
mutableConfiguration.setStoreByValue(false); // 默认值为 true,可根据需求调整
|
||||||
|
mutableConfiguration.setManagementEnabled(true); // 启用管理功能(可选)
|
||||||
|
mutableConfiguration.setStatisticsEnabled(true); // 启用统计功能(可选)
|
||||||
|
// 设置缓存过期策略(以 timeToIdle 为例,根据实际需求调整)
|
||||||
|
mutableConfiguration.setExpiryPolicyFactory(CreatedExpiryPolicy.factoryOf(new Duration(TimeUnit.HOURS,1)));
|
||||||
|
|
||||||
|
cacheManager.createCache("temp_cache", mutableConfiguration);
|
||||||
|
cacheManager.createCache("eternal_cache", mutableConfiguration);
|
||||||
|
cacheManager.createCache("sys_dict", mutableConfiguration);
|
||||||
|
cacheManager.createCache("sys_config", mutableConfiguration);
|
||||||
|
cacheManager.createCache("repeat_submit", mutableConfiguration);
|
||||||
|
cacheManager.createCache("captcha_codes", mutableConfiguration);
|
||||||
|
cacheManager.createCache("login_tokens", mutableConfiguration);
|
||||||
|
cacheManager.createCache("rate_limit", mutableConfiguration);
|
||||||
|
cacheManager.createCache("pwd_err_cnt", mutableConfiguration);
|
||||||
|
|
||||||
|
return cacheManager;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,19 @@
|
|||||||
package com.ruoyi.framework.config;
|
package com.ruoyi.framework.config;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
|
import org.springframework.cache.CacheManager;
|
||||||
import org.springframework.cache.annotation.CachingConfigurer;
|
import org.springframework.cache.annotation.CachingConfigurer;
|
||||||
import org.springframework.cache.annotation.EnableCaching;
|
|
||||||
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.data.redis.cache.RedisCacheConfiguration;
|
||||||
|
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
import org.springframework.data.redis.core.RedisTemplate;
|
import org.springframework.data.redis.core.RedisTemplate;
|
||||||
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
import org.springframework.data.redis.core.script.DefaultRedisScript;
|
||||||
|
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||||
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
import org.springframework.data.redis.serializer.StringRedisSerializer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,9 +22,34 @@ import org.springframework.data.redis.serializer.StringRedisSerializer;
|
|||||||
* @author ruoyi
|
* @author ruoyi
|
||||||
*/
|
*/
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableCaching
|
@ConditionalOnProperty(prefix = "spring.cache", name = { "type" }, havingValue = "redis", matchIfMissing = false)
|
||||||
public class RedisConfig implements CachingConfigurer
|
public class RedisConfig implements CachingConfigurer
|
||||||
{
|
{
|
||||||
|
@Bean
|
||||||
|
@Primary
|
||||||
|
public CacheManager cacheManager(RedisConnectionFactory connectionFactory)
|
||||||
|
{
|
||||||
|
RedisCacheConfiguration config = instanceConfig(3600 * 24 * 15L);
|
||||||
|
return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public CacheManager cacheManager30m(RedisConnectionFactory connectionFactory)
|
||||||
|
{
|
||||||
|
RedisCacheConfiguration config = instanceConfig(1800L);
|
||||||
|
return RedisCacheManager.builder(connectionFactory).cacheDefaults(config).transactionAware().build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||||
|
private RedisCacheConfiguration instanceConfig(Long ttl)
|
||||||
|
{
|
||||||
|
FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
|
||||||
|
return RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(ttl)).disableCachingNullValues()
|
||||||
|
.computePrefixWith(name -> name + ":")
|
||||||
|
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
|
||||||
|
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(serializer));
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
@SuppressWarnings(value = { "unchecked", "rawtypes" })
|
||||||
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
|
||||||
|
@ -3,19 +3,21 @@ package com.ruoyi.framework.interceptor.impl;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSON;
|
||||||
import com.ruoyi.common.annotation.RepeatSubmit;
|
import com.ruoyi.common.annotation.RepeatSubmit;
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
|
import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.http.HttpHelper;
|
import com.ruoyi.common.utils.http.HttpHelper;
|
||||||
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
|
||||||
|
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断请求url和数据是否和上一次相同,
|
* 判断请求url和数据是否和上一次相同,
|
||||||
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
|
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
|
||||||
@ -33,9 +35,6 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|||||||
@Value("${token.header}")
|
@Value("${token.header}")
|
||||||
private String header;
|
private String header;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
|
public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
|
||||||
@ -46,7 +45,6 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|||||||
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
|
RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
|
||||||
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
|
nowParams = HttpHelper.getBodyString(repeatedlyRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
// body参数为空,获取Parameter的数据
|
// body参数为空,获取Parameter的数据
|
||||||
if (StringUtils.isEmpty(nowParams))
|
if (StringUtils.isEmpty(nowParams))
|
||||||
{
|
{
|
||||||
@ -55,17 +53,13 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|||||||
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
Map<String, Object> nowDataMap = new HashMap<String, Object>();
|
||||||
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
nowDataMap.put(REPEAT_PARAMS, nowParams);
|
||||||
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
|
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
|
||||||
|
|
||||||
// 请求地址(作为存放cache的key值)
|
// 请求地址(作为存放cache的key值)
|
||||||
String url = request.getRequestURI();
|
String url = request.getRequestURI();
|
||||||
|
|
||||||
// 唯一值(没有消息头则使用请求地址)
|
// 唯一值(没有消息头则使用请求地址)
|
||||||
String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
|
String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
|
||||||
|
|
||||||
// 唯一标识(指定key + url + 消息头)
|
// 唯一标识(指定key + url + 消息头)
|
||||||
String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
|
String cacheRepeatKey = url + submitKey;
|
||||||
|
Object sessionObj = CacheUtils.get(CacheConstants.REPEAT_SUBMIT_KEY, cacheRepeatKey);
|
||||||
Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
|
|
||||||
if (sessionObj != null)
|
if (sessionObj != null)
|
||||||
{
|
{
|
||||||
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
|
Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
|
||||||
@ -80,7 +74,7 @@ public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
|
|||||||
}
|
}
|
||||||
Map<String, Object> cacheMap = new HashMap<String, Object>();
|
Map<String, Object> cacheMap = new HashMap<String, Object>();
|
||||||
cacheMap.put(url, nowDataMap);
|
cacheMap.put(url, nowDataMap);
|
||||||
redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
|
CacheUtils.put(CacheConstants.REPEAT_SUBMIT_KEY, cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
package com.ruoyi.framework.web.service;
|
package com.ruoyi.framework.web.service;
|
||||||
|
|
||||||
import jakarta.annotation.Resource;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.constant.UserConstants;
|
import com.ruoyi.common.constant.UserConstants;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.common.exception.user.BlackListException;
|
import com.ruoyi.common.exception.user.BlackListException;
|
||||||
import com.ruoyi.common.exception.user.CaptchaException;
|
import com.ruoyi.common.exception.user.CaptchaException;
|
||||||
import com.ruoyi.common.exception.user.CaptchaExpireException;
|
import com.ruoyi.common.exception.user.CaptchaExpireException;
|
||||||
import com.ruoyi.common.exception.user.UserNotExistsException;
|
import com.ruoyi.common.exception.user.UserNotExistsException;
|
||||||
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.DateUtils;
|
import com.ruoyi.common.utils.DateUtils;
|
||||||
import com.ruoyi.common.utils.MessageUtils;
|
import com.ruoyi.common.utils.MessageUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@ -29,6 +29,8 @@ import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
|||||||
import com.ruoyi.system.service.ISysConfigService;
|
import com.ruoyi.system.service.ISysConfigService;
|
||||||
import com.ruoyi.system.service.ISysUserService;
|
import com.ruoyi.system.service.ISysUserService;
|
||||||
|
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录校验方法
|
* 登录校验方法
|
||||||
*
|
*
|
||||||
@ -43,9 +45,6 @@ public class SysLoginService
|
|||||||
@Resource
|
@Resource
|
||||||
private AuthenticationManager authenticationManager;
|
private AuthenticationManager authenticationManager;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISysUserService userService;
|
private ISysUserService userService;
|
||||||
|
|
||||||
@ -113,9 +112,8 @@ public class SysLoginService
|
|||||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||||
if (captchaEnabled)
|
if (captchaEnabled)
|
||||||
{
|
{
|
||||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
|
String captcha = CacheUtils.get(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""), String.class);
|
||||||
String captcha = redisCache.getCacheObject(verifyKey);
|
CacheUtils.removeIfPresent(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""));
|
||||||
redisCache.deleteObject(verifyKey);
|
|
||||||
if (captcha == null)
|
if (captcha == null)
|
||||||
{
|
{
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
|
||||||
@ -146,7 +144,7 @@ public class SysLoginService
|
|||||||
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
|
||||||
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
|| password.length() > UserConstants.PASSWORD_MAX_LENGTH)
|
||||||
{
|
{
|
||||||
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,MessageUtils.message("user.password.not.match")));
|
||||||
throw new UserPasswordNotMatchException();
|
throw new UserPasswordNotMatchException();
|
||||||
}
|
}
|
||||||
// 用户名不在指定范围内 错误
|
// 用户名不在指定范围内 错误
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
package com.ruoyi.framework.web.service;
|
package com.ruoyi.framework.web.service;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
|
||||||
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
|
import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
|
import com.ruoyi.common.utils.MessageUtils;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.framework.manager.AsyncManager;
|
||||||
|
import com.ruoyi.framework.manager.factory.AsyncFactory;
|
||||||
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -23,9 +25,6 @@ import com.ruoyi.framework.security.context.AuthenticationContextHolder;
|
|||||||
@Component
|
@Component
|
||||||
public class SysPasswordService
|
public class SysPasswordService
|
||||||
{
|
{
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
@Value(value = "${user.password.maxRetryCount}")
|
@Value(value = "${user.password.maxRetryCount}")
|
||||||
private int maxRetryCount;
|
private int maxRetryCount;
|
||||||
|
|
||||||
@ -35,12 +34,11 @@ public class SysPasswordService
|
|||||||
/**
|
/**
|
||||||
* 登录账户密码错误次数缓存键名
|
* 登录账户密码错误次数缓存键名
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @return 缓存Cache
|
||||||
* @return 缓存键key
|
|
||||||
*/
|
*/
|
||||||
private String getCacheKey(String username)
|
private Cache getCache()
|
||||||
{
|
{
|
||||||
return CacheConstants.PWD_ERR_CNT_KEY + username;
|
return CacheUtils.getCache(CacheConstants.PWD_ERR_CNT_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void validate(SysUser user)
|
public void validate(SysUser user)
|
||||||
@ -48,23 +46,23 @@ public class SysPasswordService
|
|||||||
Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
|
Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
|
||||||
String username = usernamePasswordAuthenticationToken.getName();
|
String username = usernamePasswordAuthenticationToken.getName();
|
||||||
String password = usernamePasswordAuthenticationToken.getCredentials().toString();
|
String password = usernamePasswordAuthenticationToken.getCredentials().toString();
|
||||||
|
Integer retryCount = getCache().get(username, Integer.class);
|
||||||
Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
|
|
||||||
|
|
||||||
if (retryCount == null)
|
if (retryCount == null)
|
||||||
{
|
{
|
||||||
retryCount = 0;
|
retryCount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
|
if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
|
||||||
{
|
{
|
||||||
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||||
|
MessageUtils.message("user.password.retry.limit.exceed", maxRetryCount, lockTime)));
|
||||||
throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
|
throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matches(user, password))
|
if (!matches(user, password))
|
||||||
{
|
{
|
||||||
retryCount = retryCount + 1;
|
retryCount = retryCount + 1;
|
||||||
redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL,
|
||||||
|
MessageUtils.message("user.password.retry.limit.count", retryCount)));
|
||||||
|
getCache().put(username, retryCount);
|
||||||
throw new UserPasswordNotMatchException();
|
throw new UserPasswordNotMatchException();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -80,9 +78,6 @@ public class SysPasswordService
|
|||||||
|
|
||||||
public void clearLoginRecordCache(String loginName)
|
public void clearLoginRecordCache(String loginName)
|
||||||
{
|
{
|
||||||
if (redisCache.hasKey(getCacheKey(loginName)))
|
getCache().evictIfPresent(loginName);
|
||||||
{
|
|
||||||
redisCache.deleteObject(getCacheKey(loginName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,15 @@ package com.ruoyi.framework.web.service;
|
|||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.constant.UserConstants;
|
import com.ruoyi.common.constant.UserConstants;
|
||||||
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
||||||
import com.ruoyi.common.core.domain.model.RegisterBody;
|
import com.ruoyi.common.core.domain.model.RegisterBody;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.exception.user.CaptchaException;
|
import com.ruoyi.common.exception.user.CaptchaException;
|
||||||
import com.ruoyi.common.exception.user.CaptchaExpireException;
|
import com.ruoyi.common.exception.user.CaptchaExpireException;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.MessageUtils;
|
import com.ruoyi.common.utils.MessageUtils;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
@ -32,9 +33,6 @@ public class SysRegisterService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private ISysConfigService configService;
|
private ISysConfigService configService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 注册
|
* 注册
|
||||||
*/
|
*/
|
||||||
@ -43,14 +41,12 @@ public class SysRegisterService
|
|||||||
String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
|
String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
|
||||||
SysUser sysUser = new SysUser();
|
SysUser sysUser = new SysUser();
|
||||||
sysUser.setUserName(username);
|
sysUser.setUserName(username);
|
||||||
|
|
||||||
// 验证码开关
|
// 验证码开关
|
||||||
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
||||||
if (captchaEnabled)
|
if (captchaEnabled)
|
||||||
{
|
{
|
||||||
validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
|
validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isEmpty(username))
|
if (StringUtils.isEmpty(username))
|
||||||
{
|
{
|
||||||
msg = "用户名不能为空";
|
msg = "用户名不能为空";
|
||||||
@ -100,9 +96,8 @@ public class SysRegisterService
|
|||||||
*/
|
*/
|
||||||
public void validateCaptcha(String username, String code, String uuid)
|
public void validateCaptcha(String username, String code, String uuid)
|
||||||
{
|
{
|
||||||
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
|
String captcha = CacheUtils.get(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""), String.class);
|
||||||
String captcha = redisCache.getCacheObject(verifyKey);
|
CacheUtils.removeIfPresent(CacheConstants.CAPTCHA_CODE_KEY, StringUtils.nvl(uuid, ""));
|
||||||
redisCache.deleteObject(verifyKey);
|
|
||||||
if (captcha == null)
|
if (captcha == null)
|
||||||
{
|
{
|
||||||
throw new CaptchaExpireException();
|
throw new CaptchaExpireException();
|
||||||
|
@ -3,23 +3,25 @@ package com.ruoyi.framework.web.service;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.constant.Constants;
|
import com.ruoyi.common.constant.Constants;
|
||||||
import com.ruoyi.common.core.domain.model.LoginUser;
|
import com.ruoyi.common.core.domain.model.LoginUser;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.ServletUtils;
|
import com.ruoyi.common.utils.ServletUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.common.utils.ip.AddressUtils;
|
import com.ruoyi.common.utils.ip.AddressUtils;
|
||||||
import com.ruoyi.common.utils.ip.IpUtils;
|
import com.ruoyi.common.utils.ip.IpUtils;
|
||||||
import com.ruoyi.common.utils.uuid.IdUtils;
|
import com.ruoyi.common.utils.uuid.IdUtils;
|
||||||
|
|
||||||
import eu.bitwalker.useragentutils.UserAgent;
|
import eu.bitwalker.useragentutils.UserAgent;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.Jwts;
|
||||||
import io.jsonwebtoken.SignatureAlgorithm;
|
import io.jsonwebtoken.SignatureAlgorithm;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* token验证处理
|
* token验证处理
|
||||||
@ -47,9 +49,6 @@ public class TokenService
|
|||||||
|
|
||||||
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
|
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户身份信息
|
* 获取用户身份信息
|
||||||
*
|
*
|
||||||
@ -66,8 +65,7 @@ public class TokenService
|
|||||||
Claims claims = parseToken(token);
|
Claims claims = parseToken(token);
|
||||||
// 解析对应的权限以及用户信息
|
// 解析对应的权限以及用户信息
|
||||||
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
||||||
String userKey = getTokenKey(uuid);
|
LoginUser user = CacheUtils.get(CacheConstants.LOGIN_TOKEN_KEY, uuid, LoginUser.class);
|
||||||
LoginUser user = redisCache.getCacheObject(userKey);
|
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -95,8 +93,7 @@ public class TokenService
|
|||||||
{
|
{
|
||||||
if (StringUtils.isNotEmpty(token))
|
if (StringUtils.isNotEmpty(token))
|
||||||
{
|
{
|
||||||
String userKey = getTokenKey(token);
|
CacheUtils.removeIfPresent(CacheConstants.LOGIN_TOKEN_KEY, token);
|
||||||
redisCache.deleteObject(userKey);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +109,6 @@ public class TokenService
|
|||||||
loginUser.setToken(token);
|
loginUser.setToken(token);
|
||||||
setUserAgent(loginUser);
|
setUserAgent(loginUser);
|
||||||
refreshToken(loginUser);
|
refreshToken(loginUser);
|
||||||
|
|
||||||
Map<String, Object> claims = new HashMap<>();
|
Map<String, Object> claims = new HashMap<>();
|
||||||
claims.put(Constants.LOGIN_USER_KEY, token);
|
claims.put(Constants.LOGIN_USER_KEY, token);
|
||||||
return createToken(claims);
|
return createToken(claims);
|
||||||
@ -144,8 +140,7 @@ public class TokenService
|
|||||||
loginUser.setLoginTime(System.currentTimeMillis());
|
loginUser.setLoginTime(System.currentTimeMillis());
|
||||||
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
|
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
|
||||||
// 根据uuid将loginUser缓存
|
// 根据uuid将loginUser缓存
|
||||||
String userKey = getTokenKey(loginUser.getToken());
|
CacheUtils.put(CacheConstants.LOGIN_TOKEN_KEY, loginUser.getToken(), loginUser, expireTime, TimeUnit.MINUTES);
|
||||||
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -218,9 +213,4 @@ public class TokenService
|
|||||||
}
|
}
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getTokenKey(String uuid)
|
|
||||||
{
|
|
||||||
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,22 +1,25 @@
|
|||||||
package com.ruoyi.system.service.impl;
|
package com.ruoyi.system.service.impl;
|
||||||
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.cache.Cache;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import com.ruoyi.common.annotation.DataSource;
|
import com.ruoyi.common.annotation.DataSource;
|
||||||
import com.ruoyi.common.constant.CacheConstants;
|
import com.ruoyi.common.constant.CacheConstants;
|
||||||
import com.ruoyi.common.constant.UserConstants;
|
import com.ruoyi.common.constant.UserConstants;
|
||||||
import com.ruoyi.common.core.redis.RedisCache;
|
|
||||||
import com.ruoyi.common.core.text.Convert;
|
import com.ruoyi.common.core.text.Convert;
|
||||||
import com.ruoyi.common.enums.DataSourceType;
|
import com.ruoyi.common.enums.DataSourceType;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
|
import com.ruoyi.common.utils.CacheUtils;
|
||||||
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
||||||
import com.ruoyi.system.domain.SysConfig;
|
import com.ruoyi.system.domain.SysConfig;
|
||||||
import com.ruoyi.system.mapper.SysConfigMapper;
|
import com.ruoyi.system.mapper.SysConfigMapper;
|
||||||
import com.ruoyi.system.service.ISysConfigService;
|
import com.ruoyi.system.service.ISysConfigService;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 参数配置 服务层实现
|
* 参数配置 服务层实现
|
||||||
*
|
*
|
||||||
@ -28,9 +31,6 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private SysConfigMapper configMapper;
|
private SysConfigMapper configMapper;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private RedisCache redisCache;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目启动时,初始化参数到缓存
|
* 项目启动时,初始化参数到缓存
|
||||||
*/
|
*/
|
||||||
@ -64,7 +64,7 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
@Override
|
@Override
|
||||||
public String selectConfigByKey(String configKey)
|
public String selectConfigByKey(String configKey)
|
||||||
{
|
{
|
||||||
String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
|
String configValue = Convert.toStr(getCache().get(configKey, String.class));
|
||||||
if (StringUtils.isNotEmpty(configValue))
|
if (StringUtils.isNotEmpty(configValue))
|
||||||
{
|
{
|
||||||
return configValue;
|
return configValue;
|
||||||
@ -74,7 +74,7 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
SysConfig retConfig = configMapper.selectConfig(config);
|
SysConfig retConfig = configMapper.selectConfig(config);
|
||||||
if (StringUtils.isNotNull(retConfig))
|
if (StringUtils.isNotNull(retConfig))
|
||||||
{
|
{
|
||||||
redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
|
CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, configKey, retConfig.getConfigValue());
|
||||||
return retConfig.getConfigValue();
|
return retConfig.getConfigValue();
|
||||||
}
|
}
|
||||||
return StringUtils.EMPTY;
|
return StringUtils.EMPTY;
|
||||||
@ -120,7 +120,7 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
int row = configMapper.insertConfig(config);
|
int row = configMapper.insertConfig(config);
|
||||||
if (row > 0)
|
if (row > 0)
|
||||||
{
|
{
|
||||||
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
|
CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, config.getConfigKey(), config.getConfigValue());
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@ -137,13 +137,13 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
SysConfig temp = configMapper.selectConfigById(config.getConfigId());
|
SysConfig temp = configMapper.selectConfigById(config.getConfigId());
|
||||||
if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
|
if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
|
||||||
{
|
{
|
||||||
redisCache.deleteObject(getCacheKey(temp.getConfigKey()));
|
CacheUtils.removeIfPresent(CacheConstants.SYS_CONFIG_KEY, temp.getConfigKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
int row = configMapper.updateConfig(config);
|
int row = configMapper.updateConfig(config);
|
||||||
if (row > 0)
|
if (row > 0)
|
||||||
{
|
{
|
||||||
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
|
CacheUtils.put(CacheConstants.SYS_CONFIG_KEY, config.getConfigKey(), config.getConfigValue());
|
||||||
}
|
}
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
@ -161,10 +161,10 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
SysConfig config = selectConfigById(configId);
|
SysConfig config = selectConfigById(configId);
|
||||||
if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
|
if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
|
||||||
{
|
{
|
||||||
throw new ServiceException("内置参数【%1$s】不能删除 ".formatted(config.getConfigKey()));
|
throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
|
||||||
}
|
}
|
||||||
configMapper.deleteConfigById(configId);
|
configMapper.deleteConfigById(configId);
|
||||||
redisCache.deleteObject(getCacheKey(config.getConfigKey()));
|
getCache().evict(config.getConfigKey());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,7 +177,7 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
|
List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
|
||||||
for (SysConfig config : configsList)
|
for (SysConfig config : configsList)
|
||||||
{
|
{
|
||||||
redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
|
getCache().put(config.getConfigKey(), config.getConfigValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,8 +187,7 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
@Override
|
@Override
|
||||||
public void clearConfigCache()
|
public void clearConfigCache()
|
||||||
{
|
{
|
||||||
Collection<String> keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*");
|
CacheUtils.getCache(CacheConstants.SYS_CONFIG_KEY).clear();
|
||||||
redisCache.deleteObject(keys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,13 +219,12 @@ public class SysConfigServiceImpl implements ISysConfigService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置cache key
|
* 获取config缓存
|
||||||
*
|
*
|
||||||
* @param configKey 参数键
|
* @return
|
||||||
* @return 缓存键key
|
|
||||||
*/
|
*/
|
||||||
private String getCacheKey(String configKey)
|
private Cache getCache()
|
||||||
{
|
{
|
||||||
return CacheConstants.SYS_CONFIG_KEY + configKey;
|
return CacheUtils.getCache(CacheConstants.SYS_CONFIG_KEY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user