配置更改
This commit is contained in:
parent
6683780144
commit
6830350411
|
|
@ -0,0 +1,131 @@
|
|||
# 项目相关配置
|
||||
bonus:
|
||||
# 名称
|
||||
name: bonus
|
||||
# 版本
|
||||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/bonus/uploadPath,Linux配置 /home/bonus/uploadPath)
|
||||
profile: D:/bonus/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
sql:
|
||||
filePath: E:/bonus/filePath
|
||||
schemaName: smart_archives_dev
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /smartArchives
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.bonus: info
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.bonus.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# 项目相关配置
|
||||
bonus:
|
||||
# 名称
|
||||
name: bonus
|
||||
# 版本
|
||||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/bonus/uploadPath,Linux配置 /home/bonus/uploadPath)
|
||||
profile: D:/bonus/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
sql:
|
||||
filePath: E:/bonus/filePath
|
||||
schemaName: smart_archives_dev
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /smartArchives
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.bonus: info
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.bonus.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
# 项目相关配置
|
||||
bonus:
|
||||
# 名称
|
||||
name: bonus
|
||||
# 版本
|
||||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/bonus/uploadPath,Linux配置 /home/bonus/uploadPath)
|
||||
profile: /home/bonus/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
sql:
|
||||
filePath: /home/bonus/filePath
|
||||
schemaName: smart_archives_dev
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 39080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /smartArchives
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.bonus: info
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: 192.168.0.14
|
||||
# 端口,默认为6379
|
||||
port: 2004
|
||||
# 数据库索引
|
||||
database: 6
|
||||
# 密码
|
||||
password: Plzbns@Redis123!
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.bonus.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
|
@ -1,133 +1,3 @@
|
|||
# 项目相关配置
|
||||
bonus:
|
||||
# 名称
|
||||
name: bonus
|
||||
# 版本
|
||||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/bonus/uploadPath,Linux配置 /home/bonus/uploadPath)
|
||||
profile: E:/bonus/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
sql:
|
||||
filePath: E:/bonus/filePath
|
||||
schemaName: smart_archives_dev
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /smartArchives
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.bonus: debug
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: druid
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.bonus.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
active: @profiles.active@,druid
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
# 项目相关配置
|
||||
bonus:
|
||||
# 名称
|
||||
name: bonus
|
||||
# 版本
|
||||
version: 3.9.0
|
||||
# 版权年份
|
||||
copyrightYear: 2025
|
||||
# 文件路径 示例( Windows配置D:/bonus/uploadPath,Linux配置 /home/bonus/uploadPath)
|
||||
profile: D:/bonus/uploadPath
|
||||
# 获取ip地址开关
|
||||
addressEnabled: false
|
||||
# 验证码类型 math 数字计算 char 字符验证
|
||||
captchaType: math
|
||||
|
||||
sql:
|
||||
filePath: E:/bonus/filePath
|
||||
schemaName: smart_archives_dev
|
||||
|
||||
# 开发环境配置
|
||||
server:
|
||||
# 服务器的HTTP端口,默认为8080
|
||||
port: 8080
|
||||
servlet:
|
||||
# 应用的访问路径
|
||||
context-path: /smartArchives
|
||||
tomcat:
|
||||
# tomcat的URI编码
|
||||
uri-encoding: UTF-8
|
||||
# 连接数满后的排队数,默认为100
|
||||
accept-count: 1000
|
||||
threads:
|
||||
# tomcat最大线程数,默认为200
|
||||
max: 800
|
||||
# Tomcat启动初始化的线程数,默认值10
|
||||
min-spare: 100
|
||||
|
||||
# 日志配置
|
||||
logging:
|
||||
level:
|
||||
com.bonus: info
|
||||
org.springframework: warn
|
||||
|
||||
# 用户配置
|
||||
user:
|
||||
password:
|
||||
# 密码最大错误次数
|
||||
maxRetryCount: 5
|
||||
# 密码锁定时间(默认10分钟)
|
||||
lockTime: 10
|
||||
|
||||
# Spring配置
|
||||
spring:
|
||||
# 资源信息
|
||||
messages:
|
||||
# 国际化资源文件路径
|
||||
basename: i18n/messages
|
||||
profiles:
|
||||
active: druid
|
||||
# 文件上传
|
||||
servlet:
|
||||
multipart:
|
||||
# 单个文件大小
|
||||
max-file-size: 10MB
|
||||
# 设置总上传的文件大小
|
||||
max-request-size: 20MB
|
||||
# 服务模块
|
||||
devtools:
|
||||
restart:
|
||||
# 热部署开关
|
||||
enabled: true
|
||||
# redis 配置
|
||||
redis:
|
||||
# 地址
|
||||
host: localhost
|
||||
# 端口,默认为6379
|
||||
port: 6379
|
||||
# 数据库索引
|
||||
database: 0
|
||||
# 密码
|
||||
password:
|
||||
# 连接超时时间
|
||||
timeout: 10s
|
||||
lettuce:
|
||||
pool:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
# 连接池中的最大空闲连接
|
||||
max-idle: 8
|
||||
# 连接池的最大数据库连接数
|
||||
max-active: 8
|
||||
# #连接池最大阻塞等待时间(使用负值表示没有限制)
|
||||
max-wait: -1ms
|
||||
|
||||
# token配置
|
||||
token:
|
||||
# 令牌自定义标识
|
||||
header: Authorization
|
||||
# 令牌密钥
|
||||
secret: abcdefghijklmnopqrstuvwxyz
|
||||
# 令牌有效期(默认30分钟)
|
||||
expireTime: 30
|
||||
|
||||
# MyBatis配置
|
||||
mybatis:
|
||||
# 搜索指定包别名
|
||||
typeAliasesPackage: com.bonus.**.domain
|
||||
# 配置mapper的扫描,找到所有的mapper.xml映射文件
|
||||
mapperLocations: classpath*:mapper/**/*Mapper.xml
|
||||
# 加载全局的配置文件
|
||||
configLocation: classpath:mybatis/mybatis-config.xml
|
||||
|
||||
# PageHelper分页插件
|
||||
pagehelper:
|
||||
helperDialect: mysql
|
||||
supportMethodsArguments: true
|
||||
params: count=countSql
|
||||
|
||||
# Swagger配置
|
||||
swagger:
|
||||
# 是否开启swagger
|
||||
enabled: true
|
||||
# 请求前缀
|
||||
pathMapping: /dev-api
|
||||
|
||||
# 防止XSS攻击
|
||||
xss:
|
||||
# 过滤开关
|
||||
enabled: true
|
||||
# 排除链接(多个用逗号分隔)
|
||||
excludes: /system/notice
|
||||
# 匹配链接
|
||||
urlPatterns: /system/*,/monitor/*,/tool/*
|
||||
|
|
@ -12,6 +12,12 @@ public class CacheConstants
|
|||
*/
|
||||
public static final String LOGIN_TOKEN_KEY = "login_tokens:";
|
||||
|
||||
/**
|
||||
* 用户与token绑定关系 redis key(限制单端在线)
|
||||
* 格式:user_tokens:{username} -> {token-uuid}
|
||||
*/
|
||||
public static final String USER_TOKEN_KEY = "user_tokens:";
|
||||
|
||||
/**
|
||||
* 验证码 redis key
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,6 +21,11 @@ public class LoginUser implements UserDetails
|
|||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 是否被其他设备强制下线
|
||||
*/
|
||||
private boolean forceLogoutByOtherDevice = false;
|
||||
|
||||
/**
|
||||
* 部门ID
|
||||
*/
|
||||
|
|
@ -258,6 +263,14 @@ public class LoginUser implements UserDetails
|
|||
this.user = user;
|
||||
}
|
||||
|
||||
public boolean isForceLogoutByOtherDevice() {
|
||||
return forceLogoutByOtherDevice;
|
||||
}
|
||||
|
||||
public void setForceLogoutByOtherDevice(boolean forceLogoutByOtherDevice) {
|
||||
this.forceLogoutByOtherDevice = forceLogoutByOtherDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ import javax.servlet.FilterChain;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.bonus.common.constant.HttpStatus;
|
||||
import com.bonus.common.core.domain.AjaxResult;
|
||||
import com.bonus.common.utils.ServletUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
|
|
@ -34,6 +38,25 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
|
|||
throws ServletException, IOException
|
||||
{
|
||||
LoginUser loginUser = tokenService.getLoginUser(request);
|
||||
// 若检测到被其他设备挤下线,直接返回特定提示
|
||||
Object forced = request.getAttribute("forceLogoutByOtherDevice");
|
||||
if (Boolean.TRUE.equals(forced))
|
||||
{
|
||||
String msg = "检测到您的账号已在其他设备登录";
|
||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.UNAUTHORIZED, msg)));
|
||||
return;
|
||||
}
|
||||
if (StringUtils.isNotNull(loginUser))
|
||||
{
|
||||
// 如果是被其他设备挤下线的标记对象,则不注入认证,交由未认证处理器返回前端提示
|
||||
try {
|
||||
if (loginUser.isForceLogoutByOtherDevice())
|
||||
{
|
||||
chain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
} catch (Exception ignore) { }
|
||||
}
|
||||
if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
|
||||
{
|
||||
tokenService.verifyToken(loginUser);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import java.io.IOException;
|
|||
import java.io.Serializable;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
|
@ -23,12 +24,23 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S
|
|||
{
|
||||
private static final long serialVersionUID = -8970718410437077606L;
|
||||
|
||||
// 通过 request attribute 判断是否是多设备登录挤下线
|
||||
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
|
||||
throws IOException
|
||||
{
|
||||
int code = HttpStatus.UNAUTHORIZED;
|
||||
String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
|
||||
String msg;
|
||||
Object forced = request.getAttribute("forceLogoutByOtherDevice");
|
||||
if (Boolean.TRUE.equals(forced))
|
||||
{
|
||||
msg = "检测到您的账号已在其他设备登录,当前会话已下线。如非本人操作,请立即修改密码。";
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
|
||||
}
|
||||
ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -72,8 +72,28 @@ public class TokenService
|
|||
Claims claims = parseToken(token);
|
||||
// 解析对应的权限以及用户信息
|
||||
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
||||
String usernameFromJwt = (String) claims.get(Constants.JWT_USERNAME);
|
||||
String userKey = getTokenKey(uuid);
|
||||
LoginUser user = redisCache.getCacheObject(userKey);
|
||||
if (StringUtils.isNull(user))
|
||||
{
|
||||
// login_tokens:{uuid} 已不存在:视为会话被挤下线或已失效
|
||||
// 为确保前端能提示“其他设备登录”,在能解析出用户名时一律标记
|
||||
if (StringUtils.isNotEmpty(usernameFromJwt))
|
||||
{
|
||||
request.setAttribute("forceLogoutByOtherDevice", Boolean.TRUE);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// 单端在线校验:username -> uuid 映射需要与当前token匹配
|
||||
String username = user.getUsername();
|
||||
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(username));
|
||||
if (StringUtils.isEmpty(mappedUuid) || !uuid.equals(mappedUuid))
|
||||
{
|
||||
// 当前token已被挤下线或无效,标记前端可识别的提示
|
||||
request.setAttribute("forceLogoutByOtherDevice", Boolean.TRUE);
|
||||
return null;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -103,7 +123,20 @@ public class TokenService
|
|||
if (StringUtils.isNotEmpty(token))
|
||||
{
|
||||
String userKey = getTokenKey(token);
|
||||
LoginUser loginUser = redisCache.getCacheObject(userKey);
|
||||
// 删除loginUser缓存
|
||||
redisCache.deleteObject(userKey);
|
||||
// 同步删除用户名->token映射(仅当映射值等于当前token时)
|
||||
if (StringUtils.isNotNull(loginUser))
|
||||
{
|
||||
String username = loginUser.getUsername();
|
||||
String userTokenKey = getUserTokenKey(username);
|
||||
String mappedUuid = redisCache.getCacheObject(userTokenKey);
|
||||
if (token.equals(mappedUuid))
|
||||
{
|
||||
redisCache.deleteObject(userTokenKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -118,7 +151,10 @@ public class TokenService
|
|||
String token = IdUtils.fastUUID();
|
||||
loginUser.setToken(token);
|
||||
setUserAgent(loginUser);
|
||||
// 刷新并写入 login_tokens:{uuid} -> LoginUser
|
||||
refreshToken(loginUser);
|
||||
// 绑定用户名与当前uuid,挤下线旧会话
|
||||
bindUserToken(loginUser.getUsername(), token);
|
||||
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put(Constants.LOGIN_USER_KEY, token);
|
||||
|
|
@ -154,6 +190,14 @@ public class TokenService
|
|||
// 根据uuid将loginUser缓存
|
||||
String userKey = getTokenKey(loginUser.getToken());
|
||||
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
|
||||
// 同步刷新用户名->token映射的过期时间,避免映射过期时间短导致误下线
|
||||
String username = loginUser.getUsername();
|
||||
String userTokenKey = getUserTokenKey(username);
|
||||
String mappedUuid = redisCache.getCacheObject(userTokenKey);
|
||||
if (StringUtils.isNotEmpty(mappedUuid) && mappedUuid.equals(loginUser.getToken()))
|
||||
{
|
||||
redisCache.expire(userTokenKey, expireTime, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -237,6 +281,14 @@ public class TokenService
|
|||
return CacheConstants.LOGIN_TOKEN_KEY + uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 用户名->token 映射的key
|
||||
*/
|
||||
private String getUserTokenKey(String username)
|
||||
{
|
||||
return CacheConstants.USER_TOKEN_KEY + username;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取请求token
|
||||
*/
|
||||
|
|
@ -252,8 +304,28 @@ public class TokenService
|
|||
Claims claims = parseToken(token);
|
||||
// 解析对应的权限以及用户信息
|
||||
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
|
||||
String usernameFromJwt = (String) claims.get(Constants.JWT_USERNAME);
|
||||
String userKey = getTokenKey(uuid);
|
||||
LoginUser user = redisCache.getCacheObject(userKey);
|
||||
if (StringUtils.isNull(user))
|
||||
{
|
||||
// 若login_tokens无此uuid,检查用户名映射,若映射存在且指向其他uuid,则视为被其他设备挤下线
|
||||
if (StringUtils.isNotEmpty(usernameFromJwt))
|
||||
{
|
||||
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(usernameFromJwt));
|
||||
if (StringUtils.isNotEmpty(mappedUuid) && !uuid.equals(mappedUuid))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
String username = user.getUsername();
|
||||
String mappedUuid = redisCache.getCacheObject(getUserTokenKey(username));
|
||||
if (StringUtils.isEmpty(mappedUuid) || !uuid.equals(mappedUuid))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return user;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
@ -263,4 +335,20 @@ public class TokenService
|
|||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定用户与token(uuid),并挤下线旧会话
|
||||
*/
|
||||
private void bindUserToken(String username, String uuid)
|
||||
{
|
||||
String userTokenKey = getUserTokenKey(username);
|
||||
String oldUuid = redisCache.getCacheObject(userTokenKey);
|
||||
if (StringUtils.isNotEmpty(oldUuid) && !uuid.equals(oldUuid))
|
||||
{
|
||||
// 删除旧的 login_tokens:{oldUuid}
|
||||
String oldLoginKey = getTokenKey(oldUuid);
|
||||
redisCache.deleteObject(oldLoginKey);
|
||||
}
|
||||
redisCache.setCacheObject(userTokenKey, uuid, expireTime, TimeUnit.MINUTES);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
54
pom.xml
54
pom.xml
|
|
@ -35,6 +35,7 @@
|
|||
<logback.version>1.2.13</logback.version>
|
||||
<spring-security.version>5.7.12</spring-security.version>
|
||||
<spring-framework.version>5.3.39</spring-framework.version>
|
||||
<profiles.active>test</profiles.active> <!-- 默认值 -->
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
|
|
@ -246,6 +247,25 @@
|
|||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering> <!-- 启用过滤 -->
|
||||
<includes>
|
||||
<include>**/application.yml</include>
|
||||
<include>**/application.yaml</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<!-- 不过滤其他文件 -->
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
<excludes>
|
||||
<exclude>**/application.yml</exclude>
|
||||
<exclude>**/application.yaml</exclude>
|
||||
</excludes>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
|
|
@ -273,4 +293,38 @@
|
|||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
|
||||
|
||||
|
||||
<profiles>
|
||||
<!-- 开发环境 -->
|
||||
<profile>
|
||||
<id>dev</id>
|
||||
<properties>
|
||||
<profiles.active>dev</profiles.active>
|
||||
</properties>
|
||||
<!--<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>-->
|
||||
</profile>
|
||||
|
||||
<!-- 测试环境 -->
|
||||
<profile>
|
||||
<id>test</id>
|
||||
<properties>
|
||||
<profiles.active>test</profiles.active>
|
||||
</properties>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
</profile>
|
||||
|
||||
<!-- 生产环境 -->
|
||||
<profile>
|
||||
<id>prod</id>
|
||||
<properties>
|
||||
<profiles.active>prod</profiles.active>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
Loading…
Reference in New Issue