From 81727ec4cfa7c21cb636071cba6bd29de91ba5f4 Mon Sep 17 00:00:00 2001 From: click33 <2393584716@qq.com> Date: Wed, 5 Mar 2025 18:36:22 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E9=94=81=E7=99=BB=E5=BD=95=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mvn clean.bat | 1 + sa-token-demo/pom.xml | 1 + .../sa-token-demo-device-lock-h5/common.js | 69 ++++++++++++++ .../device-lock-auth.html | 69 ++++++++++++++ .../sa-token-demo-device-lock-h5/index.html | 43 +++++++++ .../sa-token-demo-device-lock-h5/login.html | 47 ++++++++++ .../sa-token-demo-device-lock/pom.xml | 55 ++++++++++++ .../com/pj/SaTokenDeviceLockApplication.java | 21 +++++ .../java/com/pj/current/GlobalException.java | 22 +++++ .../java/com/pj/current/NotFoundHandle.java | 27 ++++++ .../java/com/pj/satoken/SaTokenConfigure.java | 87 ++++++++++++++++++ .../java/com/pj/test/LoginController.java | 90 +++++++++++++++++++ .../main/java/com/pj/test/SysUserMockDao.java | 24 +++++ .../java/com/pj/util/DeviceLockCheckUtil.java | 42 +++++++++ .../main/java/com/pj/util/PhoneCodeUtil.java | 31 +++++++ .../src/main/resources/application.yml | 49 ++++++++++ 16 files changed, 678 insertions(+) create mode 100644 sa-token-demo/sa-token-demo-device-lock-h5/common.js create mode 100644 sa-token-demo/sa-token-demo-device-lock-h5/device-lock-auth.html create mode 100644 sa-token-demo/sa-token-demo-device-lock-h5/index.html create mode 100644 sa-token-demo/sa-token-demo-device-lock-h5/login.html create mode 100644 sa-token-demo/sa-token-demo-device-lock/pom.xml create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/SaTokenDeviceLockApplication.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/GlobalException.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/NotFoundHandle.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/satoken/SaTokenConfigure.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/LoginController.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/SysUserMockDao.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/PhoneCodeUtil.java create mode 100644 sa-token-demo/sa-token-demo-device-lock/src/main/resources/application.yml diff --git a/mvn clean.bat b/mvn clean.bat index 57e7e58e..c15702f3 100644 --- a/mvn clean.bat +++ b/mvn clean.bat @@ -11,6 +11,7 @@ cd sa-token-demo-alone-redis-cluster & call mvn clean & cd .. cd sa-token-demo-beetl & call mvn clean & cd .. cd sa-token-demo-bom-import & call mvn clean & cd .. cd sa-token-demo-case & call mvn clean & cd .. +cd sa-token-demo-device-lock & call mvn clean & cd .. cd sa-token-demo-grpc & call mvn clean & cd .. cd sa-token-demo-hutool-timed-cache & call mvn clean & cd .. cd sa-token-demo-jwt & call mvn clean & cd .. diff --git a/sa-token-demo/pom.xml b/sa-token-demo/pom.xml index fde0caf9..d088deb0 100644 --- a/sa-token-demo/pom.xml +++ b/sa-token-demo/pom.xml @@ -14,6 +14,7 @@ sa-token-demo-beetl sa-token-demo-bom-import sa-token-demo-case + sa-token-demo-device-lock sa-token-demo-dubbo/sa-token-demo-dubbo-provider sa-token-demo-dubbo/sa-token-demo-dubbo-consumer sa-token-demo-dubbo/sa-token-demo-dubbo3-provider diff --git a/sa-token-demo/sa-token-demo-device-lock-h5/common.js b/sa-token-demo/sa-token-demo-device-lock-h5/common.js new file mode 100644 index 00000000..72bbbae4 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock-h5/common.js @@ -0,0 +1,69 @@ +// 服务器接口主机地址 +var baseUrl = "http://localhost:8081"; + +// 封装一下Ajax +function ajax(path, data, successFn) { + console.log(baseUrl + path); + fetch(baseUrl + path, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'satoken': localStorage.getItem('satoken') + }, + body: serializeToQueryString(data), + }) + .then(response => response.json()) + .then(res => { + console.log('返回数据:', res); + successFn(res); + }) + .catch(error => { + console.error('提交失败:', error); + return alert("异常:" + JSON.stringify(error)); + }); +} + +// 获取本地的 设备id +function getLocalDeviceId() { + let localDeviceId = localStorage.getItem('local-device-id'); + if(!localDeviceId) { + localDeviceId = randomString(60); + localStorage.setItem('local-device-id', localDeviceId); + } + return localDeviceId; +} + + + +// ------------ 工具方法 --------------- + +// 从url中查询到指定名称的参数值 +function getParam(name, defaultValue){ + var query = window.location.search.substring(1); + var vars = query.split("&"); + for (var i=0;i value != null) // 过滤 null 和 undefined + .map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`) + .join('&'); +} + +// 随机生成字符串 +function randomString(len) { +  len = len || 32; +  var $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890'; +  var maxPos = $chars.length; +  var str = ''; +  for (i = 0; i < len; i++) { +    str += $chars.charAt(Math.floor(Math.random() * maxPos)); +  } +  return str; +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-device-lock-h5/device-lock-auth.html b/sa-token-demo/sa-token-demo-device-lock-h5/device-lock-auth.html new file mode 100644 index 00000000..e9e559a5 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock-h5/device-lock-auth.html @@ -0,0 +1,69 @@ + + + + + 设备锁测试-认证页 + + + +
+

设备锁测试-认证页

+
您正在一台新设备上登录此账号,需要进行身份验证
+
您绑定的手机号为:
+
+ 验证码: + +
+
+
+ + + + + diff --git a/sa-token-demo/sa-token-demo-device-lock-h5/index.html b/sa-token-demo/sa-token-demo-device-lock-h5/index.html new file mode 100644 index 00000000..f9c109e8 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock-h5/index.html @@ -0,0 +1,43 @@ + + + + + 设备锁测试-首页 + + +

设备锁测试-首页

+

当前是否登录:

+

+ 登录   + 注销 + +

+ + + + diff --git a/sa-token-demo/sa-token-demo-device-lock-h5/login.html b/sa-token-demo/sa-token-demo-device-lock-h5/login.html new file mode 100644 index 00000000..35095894 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock-h5/login.html @@ -0,0 +1,47 @@ + + + + + 设备锁测试-登录页 + + + +
+

设备锁测试-登录页

+
用户:
+
密码:
+
+
+ + + + + diff --git a/sa-token-demo/sa-token-demo-device-lock/pom.xml b/sa-token-demo/sa-token-demo-device-lock/pom.xml new file mode 100644 index 00000000..33352b66 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/pom.xml @@ -0,0 +1,55 @@ + + 4.0.0 + cn.dev33 + sa-token-demo-device-lock + 0.0.1-SNAPSHOT + + + + org.springframework.boot + spring-boot-starter-parent + 2.5.14 + + + + + + + + 1.40.0 + com.pj.SaTokenDeviceLockApplication + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + + cn.dev33 + sa-token-spring-boot-starter + ${sa-token.version} + + + + + cn.dev33 + sa-token-redis-template + ${sa-token.version} + + + + + org.apache.commons + commons-pool2 + + + + + \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/SaTokenDeviceLockApplication.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/SaTokenDeviceLockApplication.java new file mode 100644 index 00000000..b2ee68e6 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/SaTokenDeviceLockApplication.java @@ -0,0 +1,21 @@ +package com.pj; + +import cn.dev33.satoken.SaManager; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + + +/** + * Sa-Token 测试 + * @author click33 + * + */ +@SpringBootApplication +public class SaTokenDeviceLockApplication { + + public static void main(String[] args) { + SpringApplication.run(SaTokenDeviceLockApplication.class, args); + System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig()); + } + +} diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/GlobalException.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/GlobalException.java new file mode 100644 index 00000000..ddc2c3e1 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/GlobalException.java @@ -0,0 +1,22 @@ +package com.pj.current; + +import cn.dev33.satoken.util.SaResult; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 全局异常处理 + */ +@RestControllerAdvice +public class GlobalException { + + @ExceptionHandler + public SaResult handlerException(Exception e, HttpServletRequest request, HttpServletResponse response) { + e.printStackTrace(); + return SaResult.error(e.getMessage()); + } + +} diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/NotFoundHandle.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/NotFoundHandle.java new file mode 100644 index 00000000..0c5fa56b --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/current/NotFoundHandle.java @@ -0,0 +1,27 @@ +package com.pj.current; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.boot.web.servlet.error.ErrorController; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import cn.dev33.satoken.util.SaResult; + +/** + * 处理 404 + * @author click33 + */ +@RestController +public class NotFoundHandle implements ErrorController { + + @RequestMapping("/error") + public Object error(HttpServletRequest request, HttpServletResponse response) throws IOException { + response.setStatus(200); + return SaResult.get(404, "not found", null); + } + +} diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/satoken/SaTokenConfigure.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/satoken/SaTokenConfigure.java new file mode 100644 index 00000000..dd0ab680 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/satoken/SaTokenConfigure.java @@ -0,0 +1,87 @@ +package com.pj.satoken; + +import cn.dev33.satoken.context.SaHolder; +import cn.dev33.satoken.filter.SaServletFilter; +import cn.dev33.satoken.interceptor.SaInterceptor; +import cn.dev33.satoken.router.SaHttpMethod; +import cn.dev33.satoken.router.SaRouter; +import cn.dev33.satoken.util.SaResult; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + + +/** + * [Sa-Token 权限认证] 配置类 + * @author click33 + * + */ +@Configuration +public class SaTokenConfigure implements WebMvcConfigurer { + + /** + * 注册 Sa-Token 拦截器打开注解鉴权功能 + */ + @Override + public void addInterceptors(InterceptorRegistry registry) { + // 注册 Sa-Token 拦截器打开注解鉴权功能 + registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**"); + } + + /** + * 注册 [Sa-Token 全局过滤器] + */ + @Bean + public SaServletFilter getSaServletFilter() { + return new SaServletFilter() + + // 指定 [拦截路由] 与 [放行路由] + .addInclude("/**")// .addExclude("/favicon.ico") + + // 认证函数: 每次请求执行 + .setAuth(obj -> { + // 输出 API 请求日志,方便调试代码 +// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue()); + + }) + + // 异常处理函数:每次认证函数发生异常时执行此函数 + .setError(e -> { + System.out.println("---------- sa全局异常 "); + e.printStackTrace(); + return SaResult.error(e.getMessage()); + }) + + // 前置函数:在每次认证函数之前执行 + .setBeforeAuth(obj -> { + // ---------- 设置一些安全响应头 ---------- + SaHolder.getResponse() + // 服务器名称 + .setServer("sa-server") + // 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以 + .setHeader("X-Frame-Options", "SAMEORIGIN") + // 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面 + .setHeader("X-XSS-Protection", "1; mode=block") + // 禁用浏览器内容嗅探 + .setHeader("X-Content-Type-Options", "nosniff") + + // ---------- 设置跨域响应头 ---------- + // 允许指定域访问跨域资源 + .setHeader("Access-Control-Allow-Origin", "*") + // 允许所有请求方式 + .setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE") + // 有效时间 + .setHeader("Access-Control-Max-Age", "3600") + // 允许的header参数 + .setHeader("Access-Control-Allow-Headers", "*"); + + // 如果是预检请求,则立即返回到前端 + SaRouter.match(SaHttpMethod.OPTIONS) + .free(r -> System.out.println("--------OPTIONS预检请求,不做处理")) + .back(); + }) + ; + } + +} diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/LoginController.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/LoginController.java new file mode 100644 index 00000000..db9d53e2 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/LoginController.java @@ -0,0 +1,90 @@ +package com.pj.test; + +import cn.dev33.satoken.stp.SaLoginParameter; +import cn.dev33.satoken.stp.StpUtil; +import cn.dev33.satoken.util.SaResult; +import com.pj.util.DeviceLockCheckUtil; +import com.pj.util.PhoneCodeUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 登录测试 + * + * @author click33 + */ +@RestController +@RequestMapping("/acc/") +public class LoginController { + + @Autowired + SysUserMockDao userMockDao; + + // 账号密码登录 + @RequestMapping("doLogin") + public SaResult doLogin(String name, String pwd, String deviceId) { + // 此处仅作模拟示例,真实项目需要从数据库中查询数据进行比对 + if("zhang".equals(name) && "123456".equals(pwd)) { + long userId = userMockDao.getUserIdByName(name); + + // 登录前,检测设备锁 + if ( ! StpUtil.isTrustDeviceId(userId, deviceId)) { + DeviceLockCheckUtil.setDeviceIdToUserId(deviceId, 10001); + // 与前端约定好,返回421表示此设备需要验证 + return SaResult.get(421, "新设备登录,需要验证设备", deviceId); + } + + // 登录 + return login(userId, deviceId); + } + return SaResult.error("登录失败"); + } + + // 查询登录状态 + @RequestMapping("isLogin") + public SaResult isLogin() { + return SaResult.data(StpUtil.isLogin()); + } + + // 注销登录 + @RequestMapping("logout") + public SaResult logout() { + StpUtil.logout(); + return SaResult.ok(); + } + + // 返回设备id绑定的 userId 的手机号,脱敏形式 + @RequestMapping("getPhone") + public SaResult getPhone(String deviceId) { + long userId = DeviceLockCheckUtil.getUserIdByDeviceId(deviceId); + String phone = userMockDao.getPhoneByUserId(userId); + return SaResult.data(phone.substring(0, 3) + "****" + phone.substring(7)); + } + + // 发送验证码 + @RequestMapping("sendCode") + public SaResult sendCode(String deviceId) { + long userId = DeviceLockCheckUtil.getUserIdByDeviceId(deviceId); + String phone = userMockDao.getPhoneByUserId(userId); + PhoneCodeUtil.sendCode(phone); + return SaResult.ok(); + } + + // 验证验证码 + @RequestMapping("checkCode") + public SaResult checkCode(String deviceId, String code) { + long userId = DeviceLockCheckUtil.getUserIdByDeviceId(deviceId); + String phone = userMockDao.getPhoneByUserId(userId); + PhoneCodeUtil.checkCode(phone, code); + // 校验通过,开始登录 + return login(userId, deviceId); + } + + // 指定账号登录 + private SaResult login(long userId, String deviceId) { + StpUtil.login(userId, new SaLoginParameter().setDeviceId(deviceId)); + return SaResult.ok("登录成功").set("token", StpUtil.getTokenValue()); + } + +} diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/SysUserMockDao.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/SysUserMockDao.java new file mode 100644 index 00000000..7d2cbe8b --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/test/SysUserMockDao.java @@ -0,0 +1,24 @@ +package com.pj.test; + +import org.springframework.stereotype.Service; + +/** + * 模拟数据库操作类 + * + * @author click33 + * @since 2025/3/5 + */ +@Service +public class SysUserMockDao { + + // 返回指定 userId 绑定的手机号 + public String getPhoneByUserId(long userId) { + return "13112341234"; + } + + // 返回指定用户名对应的 userId + public long getUserIdByName(String name) { + return 10001; + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java new file mode 100644 index 00000000..b4f67bd7 --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/DeviceLockCheckUtil.java @@ -0,0 +1,42 @@ +package com.pj.util; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * 设备锁操作工具类 + * @author click33 + * @since 2025/3/5 + */ +public class DeviceLockCheckUtil { + + /** + * 保存设备id与用户id的映射关系 + * @param deviceId / + * @param userId / + */ + public static void setDeviceIdToUserId(String deviceId, long userId) { + if(SaFoxUtil.isEmpty(deviceId) || SaFoxUtil.isEmpty(userId)) { + throw new RuntimeException("设备id或用户id不能为空"); + } + SaManager.getSaTokenDao().set(saveKeyPrefix() + deviceId, String.valueOf(userId), 1200); + } + + /** + * 返回设备id绑定的用户id + * @param deviceId / + */ + public static long getUserIdByDeviceId(String deviceId) { + String userIdStr = SaManager.getSaTokenDao().get(saveKeyPrefix() + deviceId); + if(userIdStr == null) { + throw new RuntimeException("此设备id目前未绑定任何用户"); + } + return Long.parseLong(userIdStr); + } + + // 返回数据保存时使用的前缀 + public static Object saveKeyPrefix() { + return SaManager.getConfig().getTokenName() + ":device-to-userid:"; + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/PhoneCodeUtil.java b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/PhoneCodeUtil.java new file mode 100644 index 00000000..7327b08d --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/java/com/pj/util/PhoneCodeUtil.java @@ -0,0 +1,31 @@ +package com.pj.util;//package com.pj.oauth2.custom; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.util.SaFoxUtil; + +/** + * 手机验证码工具类 (仅做逻辑模拟,不做真实发送) + * + * @author click33 + * @since 2024/8/23 + */ +public class PhoneCodeUtil { + + // 指定手机号发送验证码 + public static void sendCode(String phone) { + String code = SaFoxUtil.getRandomNumber(100000, 999999) + ""; + SaManager.getSaTokenDao().set("phone_code:" + phone, code, 60 * 5); + System.out.println("手机号:" + phone + ",验证码:" + code + ",已发送成功"); + } + + // 校验验证码是否正确,不正确则抛出异常 + public static void checkCode(String phone, String code) { + String oldCode = SaManager.getSaTokenDao().get("phone_code:" + phone); + if( ! code.equals(oldCode) ) { + throw new RuntimeException("验证码错误"); + } + // 验证通过后,立即删除验证码 + SaManager.getSaTokenDao().delete("phone_code:" + phone); + } + +} \ No newline at end of file diff --git a/sa-token-demo/sa-token-demo-device-lock/src/main/resources/application.yml b/sa-token-demo/sa-token-demo-device-lock/src/main/resources/application.yml new file mode 100644 index 00000000..84e4a4fa --- /dev/null +++ b/sa-token-demo/sa-token-demo-device-lock/src/main/resources/application.yml @@ -0,0 +1,49 @@ +# 端口 +server: + port: 8081 + +############## Sa-Token 配置 (文档: https://sa-token.cc) ############## +sa-token: + # token 名称 (同时也是 cookie 名称) + token-name: satoken + # token 有效期(单位:秒) 默认30天,-1 代表永久有效 + timeout: 2592000 + # token 最低活跃频率(单位:秒),如果 token 超过此时间没有访问系统就会被冻结,默认-1 代表不限制,永不冻结 + active-timeout: -1 + # 是否允许同一账号多地同时登录 (为 true 时允许一起登录, 为 false 时新登录挤掉旧登录) + is-concurrent: true + # 在多人登录同一账号时,是否共用一个 token (为 true 时所有登录共用一个 token, 为 false 时每次登录新建一个 token) + is-share: false + # token 风格(默认可取值:uuid、simple-uuid、random-32、random-64、random-128、tik) + token-style: uuid + # 是否输出操作日志 + is-log: true + +spring: + # redis配置 + redis: + # Redis数据库索引(默认为0) + database: 0 + # Redis服务器地址 + host: 127.0.0.1 + # Redis服务器连接端口 + port: 6379 + # Redis服务器连接密码(默认为空) + password: + # 连接超时时间 + timeout: 10s + lettuce: + pool: + # 连接池最大连接数 + max-active: 200 + # 连接池最大阻塞等待时间(使用负值表示没有限制) + max-wait: -1ms + # 连接池中的最大空闲连接 + max-idle: 10 + # 连接池中的最小空闲连接 + min-idle: 0 + + + + + \ No newline at end of file