修改sa-token为redis缓存
This commit is contained in:
@@ -84,6 +84,13 @@
|
|||||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||||
<version>${sa-token.version}</version>
|
<version>${sa-token.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Sa-Token 整合 Redis (使用jackson序列化方式) -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cn.dev33</groupId>
|
||||||
|
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||||
|
<version>${sa-token-dao-redis-jackson.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
@@ -0,0 +1,29 @@
|
|||||||
|
package com.accompany.admin.config;
|
||||||
|
|
||||||
|
import com.accompany.core.config.JedisConfig;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||||
|
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
|
||||||
|
import redis.clients.jedis.JedisPoolConfig;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author: liaozetao
|
||||||
|
* @date: 2023/12/8 11:53
|
||||||
|
* @description:
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class SaTokenConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public RedisConnectionFactory connectionFactory(@Autowired JedisConfig jedisConfig) {
|
||||||
|
JedisPoolConfig poolConfig = new JedisPoolConfig();
|
||||||
|
poolConfig.setMaxIdle(jedisConfig.getMaxIdle());
|
||||||
|
poolConfig.setMaxTotal(jedisConfig.getMaxTotal());
|
||||||
|
poolConfig.setMaxWait(Duration.ofMillis(jedisConfig.getMaxWait()));
|
||||||
|
return new JedisConnectionFactory(poolConfig);
|
||||||
|
}
|
||||||
|
}
|
@@ -20,15 +20,14 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
|||||||
@Override
|
@Override
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
public void addInterceptors(InterceptorRegistry registry) {
|
||||||
registry.addInterceptor(loginInterceptor()).addPathPatterns("/admin/**")
|
registry.addInterceptor(loginInterceptor()).addPathPatterns("/admin/**")
|
||||||
.excludePathPatterns("/admin/api/**");
|
.excludePathPatterns("/admin/api/**");
|
||||||
//registry.addInterceptor(loginInterceptor()).addPathPatterns("/admin/**");
|
|
||||||
registry.addInterceptor(requestMetricsInterceptor()).addPathPatterns("/admin/**");
|
registry.addInterceptor(requestMetricsInterceptor()).addPathPatterns("/admin/**");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configurePathMatch(PathMatchConfigurer configurer) {
|
public void configurePathMatch(PathMatchConfigurer configure) {
|
||||||
configurer.setUseSuffixPatternMatch(true);
|
configure.setUseSuffixPatternMatch(true);
|
||||||
configurer.setUseTrailingSlashMatch(true);
|
configure.setUseTrailingSlashMatch(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@@ -3,34 +3,36 @@ package com.accompany.admin.controller.system;
|
|||||||
|
|
||||||
import cn.dev33.satoken.exception.NotLoginException;
|
import cn.dev33.satoken.exception.NotLoginException;
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.accompany.core.util.MD5;
|
|
||||||
import com.aliyuncs.exceptions.ClientException;
|
|
||||||
import com.accompany.admin.controller.BaseController;
|
import com.accompany.admin.controller.BaseController;
|
||||||
import com.accompany.admin.model.AdminUser;
|
import com.accompany.admin.model.AdminUser;
|
||||||
import com.accompany.admin.service.system.AdminLogService;
|
import com.accompany.admin.service.system.AdminLogService;
|
||||||
import com.accompany.admin.service.system.AdminUserService;
|
import com.accompany.admin.service.system.AdminUserService;
|
||||||
import com.accompany.admin.util.StringUtil;
|
import com.accompany.admin.util.StringUtil;
|
||||||
import com.accompany.core.exception.ServiceException;
|
|
||||||
import com.accompany.core.service.common.JedisService;
|
|
||||||
import com.accompany.common.utils.IPUtils;
|
|
||||||
import com.accompany.common.redis.RedisKey;
|
import com.accompany.common.redis.RedisKey;
|
||||||
import com.accompany.common.result.BusiResult;
|
import com.accompany.common.result.BusiResult;
|
||||||
import com.accompany.common.status.BusiStatus;
|
import com.accompany.common.status.BusiStatus;
|
||||||
import com.accompany.common.utils.BlankUtil;
|
import com.accompany.common.utils.BlankUtil;
|
||||||
import com.accompany.common.utils.DateTimeUtil;
|
import com.accompany.common.utils.DateTimeUtil;
|
||||||
|
import com.accompany.common.utils.IPUtils;
|
||||||
|
import com.accompany.core.exception.ServiceException;
|
||||||
|
import com.accompany.core.service.common.JedisService;
|
||||||
|
import com.accompany.core.util.MD5;
|
||||||
|
import com.aliyuncs.exceptions.ClientException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
|
||||||
@Controller
|
@RestController
|
||||||
@RequestMapping("/")
|
@RequestMapping("/")
|
||||||
public class LoginController extends BaseController {
|
public class LoginController extends BaseController {
|
||||||
@Autowired
|
@Autowired
|
||||||
@@ -60,49 +62,36 @@ public class LoginController extends BaseController {
|
|||||||
* @param password MD5加密后的密码
|
* @param password MD5加密后的密码
|
||||||
* @param authCode MD5加密后的验证码
|
* @param authCode MD5加密后的验证码
|
||||||
*/
|
*/
|
||||||
@RequestMapping("/login/login")
|
@PostMapping("/login/login")
|
||||||
@ResponseBody
|
public void login(String account, String password, String authCode, HttpServletRequest request) {
|
||||||
public void login(String account, String password, String authCode, HttpServletRequest request) throws UnsupportedEncodingException {
|
String ipAddress = IPUtils.getRealIpAddress(request);
|
||||||
logger.info("admin login account:{},ip:{}",account, IPUtils.getRealIpAddress(request));
|
logger.info("admin login account : {}, ip : {}", account, ipAddress);
|
||||||
BusiResult result = validateData(account, password, authCode);
|
BusiResult<Integer> result = validateData(account, password, authCode);
|
||||||
if (result.getCode() == 200) { //参数验证成功
|
//参数验证成功
|
||||||
AdminUser adminUser = adminUserService.getAdminUser(account, password);
|
if (!result.isSuccess()) {
|
||||||
if (adminUser != null) {
|
writeJson(Boolean.FALSE, String.valueOf(result.getCode()), result.getData());
|
||||||
StpUtil.login(adminUser.getId(), 60 * 60);
|
return;
|
||||||
/*setAttribute(AdminConstants.HAS_LOGIN, "true", Scope.SESSION);
|
|
||||||
setAttribute(AdminConstants.ADMIN_ID, adminUser.getId(), Scope.SESSION);
|
|
||||||
setAttribute(AdminConstants.ADMIN_NAME, adminUser.getUsername(), Scope.SESSION);
|
|
||||||
Cookie cookie1 = new Cookie(AdminConstants.HAS_LOGIN, "true");
|
|
||||||
Cookie cookie2 = new Cookie(AdminConstants.ADMIN_ID, adminUser.getId() + "");
|
|
||||||
Cookie cookie3 = new Cookie(AdminConstants.ADMIN_NAME, URLEncoder.encode(adminUser.getUsername(), "utf-8"));
|
|
||||||
getResponse().addCookie(cookie1);
|
|
||||||
getResponse().addCookie(cookie2);
|
|
||||||
getResponse().addCookie(cookie3);*/
|
|
||||||
adminUserService.updateLastLogin(adminUser.getId());
|
|
||||||
jedisService.hset(RedisKey.httpsession_store.getKey(), adminUser.getId() + "", getRequest().getSession().getId());
|
|
||||||
String smsCode = adminUserService.updateLoginRecord(adminUser);
|
|
||||||
updateCacheAfterLogin(adminUser);
|
|
||||||
adminLogService.insertLog(adminUser.getId(), getClass().getCanonicalName(), "login",
|
|
||||||
"params===>>account:" + account + ", password:" + password + ", authCode: " + smsCode);
|
|
||||||
logger.info("amdin [" + adminUser.getUsername() + "] login system.");
|
|
||||||
writeJson(true, adminUser.getId() + "@" + adminUser.getUsername());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
int surplus = adminUserService.updateLoginErrorCache(account);
|
|
||||||
//result = 404; //不存在
|
|
||||||
writeJson(false, "404", surplus);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
writeJson(false, String.valueOf(result.getCode()), result.getData());
|
|
||||||
}
|
}
|
||||||
|
AdminUser adminUser = adminUserService.getAdminUser(account, password);
|
||||||
|
if (adminUser == null) {
|
||||||
|
int surplus = adminUserService.updateLoginErrorCache(account);
|
||||||
|
writeJson(false, String.valueOf(HttpStatus.NOT_FOUND.value()), surplus);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
StpUtil.login(adminUser.getId(), 7 * 24 * 60 * 60);
|
||||||
|
adminUserService.updateLastLogin(adminUser.getId());
|
||||||
|
jedisService.hset(RedisKey.httpsession_store.getKey(), String.valueOf(adminUser.getId()), getRequest().getSession().getId());
|
||||||
|
String smsCode = adminUserService.updateLoginRecord(adminUser);
|
||||||
|
updateCacheAfterLogin(adminUser);
|
||||||
|
adminLogService.insertLog(adminUser.getId(), getClass().getCanonicalName(), "login", "params===>>account:" + account + ", password:" + password + ", authCode: " + smsCode);
|
||||||
|
logger.info("admin [" + adminUser.getUsername() + "] login system.");
|
||||||
|
writeJson(true, adminUser.getId() + "@" + adminUser.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Async
|
@Async
|
||||||
public void updateCacheAfterLogin(AdminUser adminUser) {
|
public void updateCacheAfterLogin(AdminUser adminUser) {
|
||||||
jedisService.del(RedisKey.admin_sms_code.getKey(adminUser.getUsername()));
|
jedisService.del(RedisKey.admin_sms_code.getKey(adminUser.getUsername()));
|
||||||
jedisService.del(RedisKey.admin_use_old_sms_code.getKey(adminUser.getUsername()));
|
jedisService.del(RedisKey.admin_use_old_sms_code.getKey(adminUser.getUsername()));
|
||||||
|
|
||||||
String todayStr = DateTimeUtil.getTodayStr();
|
String todayStr = DateTimeUtil.getTodayStr();
|
||||||
String smsCodeErrorCountKey = RedisKey.admin_login_error_count.getKey(todayStr);
|
String smsCodeErrorCountKey = RedisKey.admin_login_error_count.getKey(todayStr);
|
||||||
jedisService.hdel(smsCodeErrorCountKey, adminUser.getUsername());
|
jedisService.hdel(smsCodeErrorCountKey, adminUser.getUsername());
|
||||||
@@ -123,7 +112,7 @@ public class LoginController extends BaseController {
|
|||||||
int adminId = getAdminId();
|
int adminId = getAdminId();
|
||||||
logger.info("admin logout, id is:" + adminId);
|
logger.info("admin logout, id is:" + adminId);
|
||||||
StpUtil.logout();
|
StpUtil.logout();
|
||||||
} catch (NotLoginException ignore){
|
} catch (NotLoginException ignore) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,32 +125,31 @@ public class LoginController extends BaseController {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 检验表单数据是否正确
|
* 检验表单数据是否正确
|
||||||
* @param account
|
*
|
||||||
|
* @param account
|
||||||
* @param password
|
* @param password
|
||||||
* @param authCode
|
* @param authCode
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private BusiResult validateData(String account, String password, String authCode) {
|
private BusiResult<Integer> validateData(String account, String password, String authCode) {
|
||||||
account = accountFilter(account);
|
account = accountFilter(account);
|
||||||
password = StringUtil.filterSpecial(password);
|
password = StringUtil.filterSpecial(password);
|
||||||
authCode = StringUtil.filterSpecial(authCode);
|
authCode = StringUtil.filterSpecial(authCode);
|
||||||
if (!BlankUtil.isBlank(account)) {
|
if (!BlankUtil.isBlank(account)) {
|
||||||
if (BlankUtil.isBlank(password)) {
|
if (BlankUtil.isBlank(password)) {
|
||||||
//return 2; //密码不能为空
|
//密码不能为空
|
||||||
return new BusiResult(BusiStatus.ALERT_PARAMETER_ILLEGAL);
|
return BusiResult.fail(BusiStatus.ALERT_PARAMETER_ILLEGAL);
|
||||||
}
|
}
|
||||||
if (!checkAuthCode(account, authCode)) {
|
if (!checkAuthCode(account, authCode)) {
|
||||||
int surplus = adminUserService.updateLoginErrorCache(account);
|
int surplus = adminUserService.updateLoginErrorCache(account);
|
||||||
//return 3; //验证码不正确
|
//验证码不正确
|
||||||
BusiResult busiResult = new BusiResult(BusiStatus.SMSCODEERROR);
|
return new BusiResult<>(BusiStatus.SMSCODEERROR, surplus);
|
||||||
busiResult.setData(surplus);
|
|
||||||
return busiResult;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//return 1; //邮箱不能为空
|
//return 1; //邮箱不能为空
|
||||||
return new BusiResult(BusiStatus.ALERT_PARAMETER_ILLEGAL);
|
return BusiResult.fail(BusiStatus.ALERT_PARAMETER_ILLEGAL);
|
||||||
}
|
}
|
||||||
return new BusiResult(BusiStatus.SUCCESS);
|
return BusiResult.success();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -180,10 +168,7 @@ public class LoginController extends BaseController {
|
|||||||
}
|
}
|
||||||
String smsCode = jedisService.get(RedisKey.admin_sms_code.getKey(account));
|
String smsCode = jedisService.get(RedisKey.admin_sms_code.getKey(account));
|
||||||
logger.info("account : {}, smsCode : {}, authCode : {}", account, smsCode, authCode);
|
logger.info("account : {}, smsCode : {}, authCode : {}", account, smsCode, authCode);
|
||||||
return Optional.ofNullable(smsCode)
|
return Optional.ofNullable(smsCode).map(MD5::getMD5).map(sc -> sc.equals(authCode)).orElse(false);
|
||||||
.map(MD5::getMD5)
|
|
||||||
.map(sc -> sc.equals(authCode))
|
|
||||||
.orElse(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private String accountFilter(String account) {
|
private String accountFilter(String account) {
|
||||||
|
@@ -2,10 +2,9 @@ package com.accompany.admin.interceptor;
|
|||||||
|
|
||||||
import com.accompany.admin.common.AdminConstants;
|
import com.accompany.admin.common.AdminConstants;
|
||||||
import com.accompany.common.utils.IPUtils;
|
import com.accompany.common.utils.IPUtils;
|
||||||
import org.slf4j.Logger;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@@ -13,25 +12,17 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
/**
|
/**
|
||||||
* 日志路径处理拦截器
|
* 日志路径处理拦截器
|
||||||
*/
|
*/
|
||||||
|
@Slf4j
|
||||||
public class LoggerInterceptor implements HandlerInterceptor {
|
public class LoggerInterceptor implements HandlerInterceptor {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(LoggerInterceptor.class);
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
|
public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
|
||||||
Object admin = request.getSession().getAttribute(AdminConstants.ADMIN_ID);
|
Object admin = request.getSession().getAttribute(AdminConstants.ADMIN_ID);
|
||||||
String adminId = admin == null ? null : admin.toString();
|
String adminId = admin == null ? null : admin.toString();
|
||||||
String path = request.getRequestURI() + "?" + request.getQueryString();
|
String path = request.getRequestURI() + "?" + request.getQueryString();
|
||||||
String ip = IPUtils.getRealIpAddress(request);
|
String ip = IPUtils.getRealIpAddress(request);
|
||||||
logger.info("request path is: {}, adminId is: {}, ip is: {}", path, adminId, ip);
|
log.info("request path is: {}, adminId is: {}, ip is: {}", path, adminId, ip);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,19 +2,9 @@ package com.accompany.admin.interceptor;
|
|||||||
|
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import com.accompany.admin.common.AdminConstants;
|
|
||||||
import com.accompany.core.service.common.JedisService;
|
|
||||||
import com.accompany.common.redis.RedisKey;
|
|
||||||
import com.accompany.common.utils.BlankUtil;
|
|
||||||
import com.accompany.common.utils.StringUtils;
|
|
||||||
import com.alibaba.fastjson.JSON;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@@ -23,7 +13,6 @@ import java.io.Writer;
|
|||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class LoginInterceptor implements HandlerInterceptor {
|
public class LoginInterceptor implements HandlerInterceptor {
|
||||||
private static final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class);
|
|
||||||
|
|
||||||
private static final String NEED_LOGOUT = "needLogout";
|
private static final String NEED_LOGOUT = "needLogout";
|
||||||
|
|
||||||
@@ -33,22 +22,8 @@ public class LoginInterceptor implements HandlerInterceptor {
|
|||||||
try {
|
try {
|
||||||
StpUtil.checkLogin();
|
StpUtil.checkLogin();
|
||||||
return true;
|
return true;
|
||||||
/*Object tmp = request.getSession().getAttribute(AdminConstants.HAS_LOGIN);
|
|
||||||
log.info("tmp : {}", JSON.toJSONString(tmp));
|
|
||||||
if (tmp != null) {
|
|
||||||
String isLogin = tmp.toString();
|
|
||||||
if (!BlankUtil.isBlank(isLogin) && Boolean.TRUE.toString().equalsIgnoreCase(isLogin)) {
|
|
||||||
String adminId = request.getSession().getAttribute(AdminConstants.ADMIN_ID).toString();
|
|
||||||
if (!BlankUtil.isBlank(adminId)) {
|
|
||||||
String sessionId = jedisService.hget(RedisKey.httpsession_store.getKey(), adminId);
|
|
||||||
if (StringUtils.isNotEmpty(sessionId) && sessionId.equals(request.getSession().getId())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.warn("getAdminId fail,admin has not login", e);
|
log.error("getAdminId fail, admin has not login, message : {}", e.getMessage());
|
||||||
}
|
}
|
||||||
reDirect(request, response);
|
reDirect(request, response);
|
||||||
return false;
|
return false;
|
||||||
|
@@ -101,6 +101,7 @@
|
|||||||
<zxing.version>3.2.0</zxing.version>
|
<zxing.version>3.2.0</zxing.version>
|
||||||
<bitwalker.version>1.20</bitwalker.version>
|
<bitwalker.version>1.20</bitwalker.version>
|
||||||
<sa-token.version>1.37.0</sa-token.version>
|
<sa-token.version>1.37.0</sa-token.version>
|
||||||
|
<sa-token-dao-redis-jackson.version>1.34.0</sa-token-dao-redis-jackson.version>
|
||||||
<pinyin4j.version>2.5.1</pinyin4j.version>
|
<pinyin4j.version>2.5.1</pinyin4j.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user