全局日志模块

This commit is contained in:
click33
2022-11-02 18:50:15 +08:00
parent cf8cd29a82
commit 8be77d70b5
21 changed files with 776 additions and 129 deletions

View File

@@ -14,6 +14,9 @@ import cn.dev33.satoken.error.SaErrorCode;
import cn.dev33.satoken.exception.SaTokenException;
import cn.dev33.satoken.json.SaJsonTemplate;
import cn.dev33.satoken.json.SaJsonTemplateDefaultImpl;
import cn.dev33.satoken.log.SaLog;
import cn.dev33.satoken.log.SaLogForConsole;
import cn.dev33.satoken.log.input.SaLogInput;
import cn.dev33.satoken.same.SaSameTemplate;
import cn.dev33.satoken.sign.SaSignTemplate;
import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl;
@@ -37,18 +40,27 @@ public class SaManager {
*/
public volatile static SaTokenConfig config;
public static void setConfig(SaTokenConfig config) {
SaManager.config = config;
setConfigMethod(config);
// 打印 banner
if(config.getIsPrint()) {
SaFoxUtil.printSaToken();
}
// ## 发送日志
SaManager.getLogInput().registerConfig(config);
// 调用一次StpUtil中的方法保证其可以尽早的初始化 StpLogic
StpUtil.getLoginType();
}
private static void setConfigMethod(SaTokenConfig config) {
SaManager.config = config;
}
public static SaTokenConfig getConfig() {
if (config == null) {
synchronized (SaManager.class) {
if (config == null) {
setConfig(SaTokenConfigFactory.createConfig());
setConfigMethod(SaTokenConfigFactory.createConfig());
}
}
}
@@ -60,6 +72,10 @@ public class SaManager {
*/
private volatile static SaTokenDao saTokenDao;
public static void setSaTokenDao(SaTokenDao saTokenDao) {
setSaTokenDaoMethod(saTokenDao);
SaManager.getLogInput().registerComponent("SaTokenDao", saTokenDao);
}
private static void setSaTokenDaoMethod(SaTokenDao saTokenDao) {
if((SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
}
@@ -69,7 +85,7 @@ public class SaManager {
if (saTokenDao == null) {
synchronized (SaManager.class) {
if (saTokenDao == null) {
setSaTokenDao(new SaTokenDaoDefaultImpl());
setSaTokenDaoMethod(new SaTokenDaoDefaultImpl());
}
}
}
@@ -82,12 +98,13 @@ public class SaManager {
private volatile static StpInterface stpInterface;
public static void setStpInterface(StpInterface stpInterface) {
SaManager.stpInterface = stpInterface;
SaManager.getLogInput().registerComponent("StpInterface", stpInterface);
}
public static StpInterface getStpInterface() {
if (stpInterface == null) {
synchronized (SaManager.class) {
if (stpInterface == null) {
setStpInterface(new StpInterfaceDefaultImpl());
SaManager.stpInterface = new StpInterfaceDefaultImpl();
}
}
}
@@ -100,6 +117,7 @@ public class SaManager {
private volatile static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
SaManager.saTokenContext = saTokenContext;
SaManager.getLogInput().registerComponent("SaTokenContext", saTokenContext);
}
public static SaTokenContext getSaTokenContext() {
return saTokenContext;
@@ -109,11 +127,12 @@ public class SaManager {
* 二级Context
*/
private volatile static SaTokenSecondContext saTokenSecondContext;
public static SaTokenSecondContext getSaTokenSecondContext() {
return saTokenSecondContext;
}
public static void setSaTokenSecondContext(SaTokenSecondContext saTokenSecondContext) {
SaManager.saTokenSecondContext = saTokenSecondContext;
SaManager.getLogInput().registerComponent("SaTokenSecondContext", saTokenSecondContext);
}
public static SaTokenSecondContext getSaTokenSecondContext() {
return saTokenSecondContext;
}
/**
@@ -146,12 +165,13 @@ public class SaManager {
private volatile static SaTempInterface saTemp;
public static void setSaTemp(SaTempInterface saTemp) {
SaManager.saTemp = saTemp;
SaManager.getLogInput().registerComponent("SaTempInterface", saTemp);
}
public static SaTempInterface getSaTemp() {
if (saTemp == null) {
synchronized (SaManager.class) {
if (saTemp == null) {
setSaTemp(new SaTempDefaultImpl());
SaManager.saTemp = new SaTempDefaultImpl();
}
}
}
@@ -164,12 +184,13 @@ public class SaManager {
private volatile static SaJsonTemplate saJsonTemplate;
public static void setSaJsonTemplate(SaJsonTemplate saJsonTemplate) {
SaManager.saJsonTemplate = saJsonTemplate;
SaManager.getLogInput().registerComponent("SaJsonTemplate", saJsonTemplate);
}
public static SaJsonTemplate getSaJsonTemplate() {
if (saJsonTemplate == null) {
synchronized (SaManager.class) {
if (saJsonTemplate == null) {
setSaJsonTemplate(new SaJsonTemplateDefaultImpl());
SaManager.saJsonTemplate = new SaJsonTemplateDefaultImpl();
}
}
}
@@ -182,12 +203,13 @@ public class SaManager {
private volatile static SaSignTemplate saSignTemplate;
public static void setSaSignTemplate(SaSignTemplate saSignTemplate) {
SaManager.saSignTemplate = saSignTemplate;
SaManager.getLogInput().registerComponent("SaSignTemplate", saSignTemplate);
}
public static SaSignTemplate getSaSignTemplate() {
if (saSignTemplate == null) {
synchronized (SaManager.class) {
if (saSignTemplate == null) {
setSaSignTemplate(new SaSignTemplateDefaultImpl());
SaManager.saSignTemplate = new SaSignTemplateDefaultImpl();
}
}
}
@@ -200,18 +222,50 @@ public class SaManager {
private volatile static SaSameTemplate saSameTemplate;
public static void setSaSameTemplate(SaSameTemplate saSameTemplate) {
SaManager.saSameTemplate = saSameTemplate;
SaManager.getLogInput().registerComponent("SaSameTemplate", saSameTemplate);
}
public static SaSameTemplate getSaSameTemplate() {
if (saSameTemplate == null) {
synchronized (SaManager.class) {
if (saSameTemplate == null) {
setSaSameTemplate(new SaSameTemplate());
SaManager.saSameTemplate = new SaSameTemplate();
}
}
}
return saSameTemplate;
}
/**
* 日志接收器
*/
private volatile static SaLogInput logInput;
public static void setLogInput(SaLogInput logInput) {
SaManager.logInput = logInput;
SaManager.getLogInput().registerComponent("SaLogInput", logInput);
}
public static SaLogInput getLogInput() {
if (logInput == null) {
synchronized (SaManager.class) {
if (logInput == null) {
SaManager.logInput = new SaLogInput();
}
}
}
return logInput;
}
/**
* 日志输出器
*/
public volatile static SaLog log = new SaLogForConsole();
public static void setLog(SaLog log) {
SaManager.log = log;
SaManager.getLogInput().registerComponent("SaLog", log);
}
public static SaLog getLog() {
return SaManager.log;
}
/**
* StpLogic集合, 记录框架所有成功初始化的StpLogic
*/

View File

@@ -2,6 +2,8 @@ package cn.dev33.satoken.config;
import java.io.Serializable;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 配置类 Model
* <p>
@@ -70,6 +72,13 @@ public class SaTokenConfig implements Serializable {
/** 是否打印操作日志 */
private Boolean isLog = false;
/** 日志等级trace、debug、info、warn、error、fatal */
private String logLevel = "trace";
/** 日志等级 int 值1=trace、2=debug、3=info、4=warn、5=error、6=fatal */
private int logLevelInt = 1;
/**
* jwt秘钥 (只有集成 jwt 模块时此参数才会生效)
*/
@@ -374,6 +383,40 @@ public class SaTokenConfig implements Serializable {
return this;
}
/**
* @return 日志等级trace、debug、info、warn、error、fatal
*/
public String getLogLevel() {
return logLevel;
}
/**
* @param logLevel 日志等级trace、debug、info、warn、error、fatal
* @return 对象自身
*/
public SaTokenConfig setLogLevel(String logLevel) {
this.logLevel = logLevel;
this.logLevelInt = SaFoxUtil.translateLogLevelToInt(logLevel);
return this;
}
/**
* @return 日志等级 int 值1=trace、2=debug、3=info、4=warn、5=error、6=fatal
*/
public int getLogLevelInt() {
return logLevelInt;
}
/**
* @param logLevelInt 日志等级 int 值1=trace、2=debug、3=info、4=warn、5=error、6=fatal
* @return 对象自身
*/
public SaTokenConfig setLogLeveInt(int logLevelInt) {
this.logLevelInt = logLevelInt;
this.logLevel = SaFoxUtil.translateLogLevelToString(logLevelInt);
return this;
}
/**
* @return jwt秘钥 (只有集成 jwt 模块时此参数才会生效)
*/
@@ -490,6 +533,8 @@ public class SaTokenConfig implements Serializable {
+ ", tokenPrefix=" + tokenPrefix
+ ", isPrint=" + isPrint
+ ", isLog=" + isLog
+ ", logLevel=" + logLevel
+ ", logLevelInt=" + logLevelInt
+ ", jwtSecretKey=" + jwtSecretKey
+ ", basic=" + basic
+ ", currDomain=" + currDomain

View File

@@ -21,7 +21,7 @@ public class SaTokenEventCenter {
static {
// 默认添加控制台日志侦听器
listenerList.add(new SaTokenListenerForConsolePrint());
listenerList.add(new SaTokenListenerForLog());
}
/**
@@ -199,6 +199,31 @@ public class SaTokenEventCenter {
}
}
/**
* 每次打开二级认证时触发
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
* @param safeTime 认证时间,单位:秒
*/
public static void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
for (SaTokenListener listener : listenerList) {
listener.doOpenSafe(loginType, tokenValue, service, safeTime);
}
}
/**
* 每次关闭二级认证时触发
* @param loginType 账号类别
* @param service 指定服务
* @param tokenValue token值
*/
public static void doCloseSafe(String loginType, String tokenValue, String service) {
for (SaTokenListener listener : listenerList) {
listener.doCloseSafe(loginType, tokenValue, service);
}
}
/**
* 每次创建Session时触发
* @param id SessionId

View File

@@ -61,6 +61,23 @@ public interface SaTokenListener {
*/
public void doUntieDisable(String loginType, Object loginId, String service);
/**
* 每次打开二级认证时触发
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
* @param safeTime 认证时间,单位:秒
*/
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime);
/**
* 每次关闭二级认证时触发
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
*/
public void doCloseSafe(String loginType, String tokenValue, String service);
/**
* 每次创建Session时触发
* @param id SessionId

View File

@@ -1,107 +0,0 @@
package cn.dev33.satoken.listener;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 侦听器实现:控制台 log 打印
* @author kong
*
*/
public class SaTokenListenerForConsolePrint implements SaTokenListener {
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
println("账号[" + loginId + "]登录成功");
}
/**
* 每次注销时触发
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
println("账号[" + loginId + "]注销成功 (Token=" + tokenValue + ")");
}
/**
* 每次被踢下线时触发
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
println("账号[" + loginId + "]被踢下线 (Token=" + tokenValue + ")");
}
/**
* 每次被顶下线时触发
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
println("账号[" + loginId + "]被顶下线 (Token=" + tokenValue + ")");
}
/**
* 每次被封禁时触发
*/
@Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis() + disableTime * 1000);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
println("账号[" + loginId + "] " + service + " 服务被封禁,封禁等级=" + level + " (解封时间: " + SaFoxUtil.formatDate(zonedDateTime) + ")");
}
/**
* 每次被解封时触发
*/
@Override
public void doUntieDisable(String loginType, Object loginId, String service) {
println("账号[" + loginId + "] " + service + " 服务被解除封禁");
}
/**
* 每次创建Session时触发
*/
@Override
public void doCreateSession(String id) {
println("Session[" + id + "]创建成功");
}
/**
* 每次注销Session时触发
*/
@Override
public void doLogoutSession(String id) {
println("Session[" + id + "]注销成功");
}
/**
* 每次Token续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
println("帐号[" + loginId + "]Token=" + tokenValue + " 续期timeout成功!");
}
/**
* 日志输出的前缀
*/
public static final String LOG_PREFIX = "SaLog -->: ";
/**
* 打印指定字符串
* @param str 字符串
*/
public void println(String str) {
if(SaManager.getConfig().getIsLog()) {
System.out.println(LOG_PREFIX + str);
}
}
}

View File

@@ -0,0 +1,103 @@
package cn.dev33.satoken.listener;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.stp.SaLoginModel;
/**
* Sa-Token 侦听器实现Log 打印
*
* @author kong
* @since 2022-11-2
*/
public class SaTokenListenerForLog implements SaTokenListener {
/**
* 每次登录时触发
*/
@Override
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
SaManager.getLogInput().doLogin(loginType, loginId, tokenValue, loginModel);
}
/**
* 每次注销时触发
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
SaManager.getLogInput().doLogout(loginType, loginId, tokenValue);
}
/**
* 每次被踢下线时触发
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
SaManager.getLogInput().doKickout(loginType, loginId, tokenValue);
}
/**
* 每次被顶下线时触发
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
SaManager.getLogInput().doReplaced(loginType, loginId, tokenValue);
}
/**
* 每次被封禁时触发
*/
@Override
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
SaManager.getLogInput().doDisable(loginType, loginId, service, level, disableTime);
}
/**
* 每次被解封时触发
*/
@Override
public void doUntieDisable(String loginType, Object loginId, String service) {
SaManager.getLogInput().doUntieDisable(loginType, loginId, service);
}
/**
* 每次打开二级认证时触发
*/
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
SaManager.getLogInput().doOpenSafe(loginType, tokenValue, service, safeTime);
}
/**
* 每次关闭二级认证时触发
*/
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
SaManager.getLogInput().doCloseSafe(loginType, tokenValue, service);
}
/**
* 每次创建Session时触发
*/
@Override
public void doCreateSession(String id) {
SaManager.getLogInput().doCreateSession(id);
}
/**
* 每次注销Session时触发
*/
@Override
public void doLogoutSession(String id) {
SaManager.getLogInput().doLogoutSession(id);
}
/**
* 每次Token续期时触发
*/
@Override
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
SaManager.getLogInput().doRenewTimeout(tokenValue, loginId, timeout);
}
}

View File

@@ -42,6 +42,16 @@ public class SaTokenListenerForSimple implements SaTokenListener {
}
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
}
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
}
@Override
public void doCreateSession(String id) {
@@ -57,4 +67,5 @@ public class SaTokenListenerForSimple implements SaTokenListener {
}
}

View File

@@ -0,0 +1,53 @@
package cn.dev33.satoken.log;
/**
* Sa-Token 日志输出接口
*
* @author kong
* @since 2022-11-1
*/
public interface SaLog {
/**
* 输出 trace 日志
* @param str 日志内容
* @param args 参数列表
*/
public void trace(String str, Object ...args);
/**
* 输出 debug 日志
* @param str 日志内容
* @param args 参数列表
*/
public void debug(String str, Object ...args);
/**
* 输出 info 日志
* @param str 日志内容
* @param args 参数列表
*/
public void info(String str, Object ...args);
/**
* 输出 warn 日志
* @param str 日志内容
* @param args 参数列表
*/
public void warn(String str, Object ...args);
/**
* 输出 error 日志
* @param str 日志内容
* @param args 参数列表
*/
public void error(String str, Object ...args);
/**
* 输出 fatal 日志
* @param str 日志内容
* @param args 参数列表
*/
public void fatal(String str, Object ...args);
}

View File

@@ -0,0 +1,73 @@
package cn.dev33.satoken.log;
import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.util.StrFormatter;
/**
* Sa-Token 日志实现类 [控制台打印]
*
* @author kong
* @since 2022-11-1
*/
public class SaLogForConsole implements SaLog {
/**
* 日志输出的前缀
*/
public static String LOG_PREFIX = "SaLog -->: ";
/**
* 日志等级
*/
public static final int trace = 1;
public static final int debug = 2;
public static final int info = 3;
public static final int warn = 4;
public static final int error = 5;
public static final int fatal = 6;
@Override
public void trace(String str, Object... args) {
println(trace, str, args);
}
@Override
public void debug(String str, Object... args) {
println(debug, str, args);
}
@Override
public void info(String str, Object... args) {
println(info, str, args);
}
@Override
public void warn(String str, Object... args) {
println(warn, str, args);
}
@Override
public void error(String str, Object... args) {
println(error, str, args);
}
@Override
public void fatal(String str, Object... args) {
println(fatal, str, args);
}
/**
* 打印日志到控制台
* @param level 日志等级
* @param str 字符串
* @param args 参数列表
*/
public void println(int level, String str, Object... args) {
SaTokenConfig config = SaManager.getConfig();
if(config.getIsLog() && level >= config.getLogLevelInt()) {
System.out.println(LOG_PREFIX + StrFormatter.format(str, args));
}
}
}

View File

@@ -0,0 +1,160 @@
package cn.dev33.satoken.log.input;
import static cn.dev33.satoken.SaManager.log;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpLogic;
import cn.dev33.satoken.util.SaFoxUtil;
/**
* Sa-Token 日志接受器
*
* @author kong
* @since 2022-11-1
*/
public class SaLogInput {
/**
* 账号登录
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue 本次登录产生的 token 值
* @param loginModel 登录参数
*/
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
log.info("账号 {} 登录成功 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
}
/**
* 每次注销时触发
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
*/
public void doLogout(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 注销登录 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
}
/**
* 每次被踢下线时触发
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
*/
public void doKickout(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 被踢下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
}
/**
* 每次被顶下线时触发
* @param loginType 账号类别
* @param loginId 账号id
* @param tokenValue token值
*/
public void doReplaced(String loginType, Object loginId, String tokenValue) {
log.info("账号 {} 被顶下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
}
/**
* 每次被封禁时触发
* @param loginType 账号类别
* @param loginId 账号id
* @param service 指定服务
* @param level 封禁等级
* @param disableTime 封禁时长,单位: 秒
*/
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
log.info("账号 {} [{}服务] 被封禁 (loginType={}), 封禁等级={}, 解封时间为 {}", loginId, loginType, service, level, SaFoxUtil.formatAfterDate(disableTime * 1000));
}
/**
* 每次被解封时触发
* @param loginType 账号类别
* @param loginId 账号id
* @param service 指定服务
*/
public void doUntieDisable(String loginType, Object loginId, String service) {
log.info("账号 {} [{}服务] 解封成功 (loginType={})", loginId, service, loginType);
}
/**
* 每次打开二级认证时触发
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
* @param safeTime 认证时间,单位:秒
*/
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
log.info("Token 二级认证成功, 业务标识={}, 有效期={}秒, Token值={}", service, safeTime, tokenValue);
}
/**
* 每次关闭二级认证时触发
* @param loginType 账号类别
* @param tokenValue token值
* @param service 指定服务
*/
public void doCloseSafe(String loginType, String tokenValue, String service) {
log.info("Token 二级认证关闭, 业务标识={}, Token值={}", service, tokenValue);
}
/**
* 每次创建Session时触发
* @param id SessionId
*/
public void doCreateSession(String id) {
log.info("SaSession [{}] 创建成功", id);
}
/**
* 每次注销Session时触发
* @param id SessionId
*/
public void doLogoutSession(String id) {
log.info("SaSession [{}] 注销成功", id);
}
/**
* 每次Token续期时触发
*
* @param tokenValue token 值
* @param loginId 账号id
* @param timeout 续期时间
*/
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
log.info("Token 续期成功, {} 秒后到期, 帐号={}, Token值={} ", timeout, loginId, tokenValue);
}
/**
* 全局组件载入
* @param comtName 组件名称
* @param comtObj 组件对象
*/
public void registerComponent(String comtName, Object comtObj) {
String canonicalName = comtObj == null ? null : comtObj.getClass().getCanonicalName();
log.info("全局组件 {} 载入成功: {}", comtName, canonicalName);
}
/**
* StpLogic 对象替换
* @param stpLogic /
*/
public void replaceStpLogic(StpLogic stpLogic) {
if(stpLogic != null) {
log.info("会话组件 StpLogic(type={}) 重置成功: {}", stpLogic.getLoginType(), stpLogic.getClass());
}
}
/**
* 载入全局配置
* @param stpLogic /
*/
public void registerConfig(SaTokenConfig config) {
if(config != null) {
log.info("全局配置 {} ", config);
}
}
}

View File

@@ -375,7 +375,7 @@ public class StpLogic {
// 写入 [token-last-activity]
setLastActivityToNow(tokenValue);
// $$ 发布事件账号xxx 登录成功
// $$ 发布事件:账号 xxx 登录成功
SaTokenEventCenter.doLogin(loginType, id, tokenValue, loginModel);
// 检查此账号会话数量是否超出最大值
@@ -2018,8 +2018,13 @@ public class StpLogic {
public void openSafe(String service, long safeTime) {
// 开启二级认证前必须处于登录状态
checkLogin();
// 写入key
getSaTokenDao().set(splicingKeySafe(getTokenValueNotNull(), service), SaTokenConsts.SAFE_AUTH_SAVE_VALUE, safeTime);
String tokenValue = getTokenValueNotNull();
getSaTokenDao().set(splicingKeySafe(tokenValue, service), SaTokenConsts.SAFE_AUTH_SAVE_VALUE, safeTime);
// $$ 发布事件
SaTokenEventCenter.doOpenSafe(loginType, tokenValue, service, safeTime);
}
/**
@@ -2118,6 +2123,9 @@ public class StpLogic {
// 删除 key
getSaTokenDao().delete(splicingKeySafe(tokenValue, service));
// $$ 发布事件
SaTokenEventCenter.doCloseSafe(loginType, tokenValue, service);
}

View File

@@ -36,6 +36,7 @@ public class StpUtil {
* 重置 StpLogic 对象
* <br> 1、更改此账户的 StpLogic 对象
* <br> 2、put 到全局 StpLogic 集合中
* <br> 3、发送日志
*
* @param newStpLogic /
*/
@@ -46,6 +47,9 @@ public class StpUtil {
// 添加到全局 StpLogic 集合中
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
SaManager.putStpLogic(newStpLogic);
// ## 发送日志
SaManager.getLogInput().replaceStpLogic(stpLogic);
}
/**

View File

@@ -4,9 +4,12 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
@@ -85,6 +88,15 @@ public class SaFoxUtil {
return isEmpty(str) == false;
}
/**
* 指定数组是否为null或者空数组
* @param array /
* @return /
*/
public static <T> boolean isEmpty(T[] array) {
return array == null || array.length == 0;
}
/**
* 比较两个对象是否相等
* @param a 第一个对象
@@ -122,6 +134,17 @@ public class SaFoxUtil {
return zonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
/**
* 指定毫秒后的时间(格式化 yyyy-MM-dd HH:mm:ss
* @param ms 指定毫秒后
* @return 格式化后的时间
*/
public static String formatAfterDate(long ms) {
Instant instant = Instant.ofEpochMilli(System.currentTimeMillis() + ms);
ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, ZoneId.systemDefault());
return formatDate(zonedDateTime);
}
/**
* 从集合里查询数据
*
@@ -552,7 +575,31 @@ public class SaFoxUtil {
return list;
}
public static List<String> logLevelList = Arrays.asList("", "trace", "debug", "info", "warn", "error", "fatal");
/**
* 将日志等级从 String 格式转化为 int 格式
* @param level /
* @return /
*/
public static int translateLogLevelToInt(String level) {
int levelInt = logLevelList.indexOf(level);
if(levelInt <= 0 || levelInt >= logLevelList.size()) {
levelInt = 1;
}
return levelInt;
}
/**
* 将日志等级从 String 格式转化为 int 格式
* @param level /
* @return /
*/
public static String translateLogLevelToString(int level) {
if(level <= 0 || level >= logLevelList.size()) {
level = 1;
}
return logLevelList.get(level);
}
}

View File

@@ -0,0 +1,103 @@
package cn.dev33.satoken.util;
/**
* 字符串格式化工具
* <p>
* 本工具类 copy 自 Hutool
* https://github.com/dromara/hutool/blob/v5-master/hutool-core/src/main/java/cn/hutool/core/text/StrFormatter.java
* </p>
*
* @author Looly
*/
public class StrFormatter {
/**
* 占位符
*/
public static String EMPTY_JSON = "{}";
public static char C_BACKSLASH = '\\';
/**
* 格式化字符串<br>
* 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
* 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用format("this is {} for {}", "a", "b") =》 this is a for b<br>
* 转义{} format("this is \\{} for {}", "a", "b") =》 this is \{} for a<br>
* 转义\ format("this is \\\\{} for {}", "a", "b") =》 this is \a for b<br>
*
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
*/
public static String format(String strPattern, Object... argArray) {
return formatWith(strPattern, EMPTY_JSON, argArray);
}
/**
* 格式化字符串<br>
* 此方法只是简单将指定占位符 按照顺序替换为参数<br>
* 如果想输出占位符使用 \\转义即可,如果想输出占位符之前的 \ 使用双转义符 \\\\ 即可<br>
* 例:<br>
* 通常使用format("this is {} for {}", "{}", "a", "b") =》 this is a for b<br>
* 转义{} format("this is \\{} for {}", "{}", "a", "b") =》 this is {} for a<br>
* 转义\ format("this is \\\\{} for {}", "{}", "a", "b") =》 this is \a for b<br>
*
* @param strPattern 字符串模板
* @param placeHolder 占位符,例如{}
* @param argArray 参数列表
* @return 结果
* @since 5.7.14
*/
public static String formatWith(String strPattern, String placeHolder, Object... argArray) {
if (SaFoxUtil.isEmpty(strPattern) || SaFoxUtil.isEmpty(placeHolder) || SaFoxUtil.isEmpty(argArray)) {
return strPattern;
}
final int strPatternLength = strPattern.length();
final int placeHolderLength = placeHolder.length();
// 初始化定义好的长度以获得更好的性能
final StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
int handledPosition = 0;// 记录已经处理到的位置
int delimIndex;// 占位符所在位置
for (int argIndex = 0; argIndex < argArray.length; argIndex++) {
delimIndex = strPattern.indexOf(placeHolder, handledPosition);
if (delimIndex == -1) {// 剩余部分无占位符
if (handledPosition == 0) { // 不带占位符的模板直接返回
return strPattern;
}
// 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
// 转义符
if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) {// 转义符
if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) {// 双转义符
// 转义符之前还有一个转义符,占位符依旧有效
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(String.valueOf(argArray[argIndex]));
handledPosition = delimIndex + placeHolderLength;
} else {
// 占位符被转义
argIndex--;
sbuf.append(strPattern, handledPosition, delimIndex - 1);
sbuf.append(placeHolder.charAt(0));
handledPosition = delimIndex + 1;
}
} else {// 正常占位符
sbuf.append(strPattern, handledPosition, delimIndex);
sbuf.append(String.valueOf(argArray[argIndex]));
handledPosition = delimIndex + placeHolderLength;
}
}
// 加入最后一个占位符后所有的字符
sbuf.append(strPattern, handledPosition, strPatternLength);
return sbuf.toString();
}
}

View File

@@ -22,6 +22,8 @@ public class DisableController {
2、注销登录 ---- http://localhost:8081/disable/logout
3、禁用账号 ---- http://localhost:8081/disable/disable?userId=10001
4、再次访问登录接口登录失败 ---- http://localhost:8081/disable/login?userId=10001
5、解封账号 ---- http://localhost:8081/disable/untieDisable?userId=10001
6、再次访问登录接口登录成功 ---- http://localhost:8081/disable/login?userId=10001
*/
// 会话登录接口 ---- http://localhost:8081/disable/login?userId=10001
@@ -41,7 +43,7 @@ public class DisableController {
return SaResult.ok("账号退出成功");
}
// 封禁指定账号 ---- http://localhost:8081/disable/disable
// 封禁指定账号 ---- http://localhost:8081/disable/disable?userId=10001
@RequestMapping("disable")
public SaResult disable(long userId) {
/*
@@ -53,4 +55,11 @@ public class DisableController {
return SaResult.ok("账号 " + userId + " 封禁成功");
}
// 解封指定账号 ---- http://localhost:8081/disable/untieDisable?userId=10001
@RequestMapping("untieDisable")
public SaResult untieDisable(long userId) {
StpUtil.untieDisable(userId);
return SaResult.ok("账号 " + userId + " 解封成功");
}
}

View File

@@ -61,6 +61,13 @@ public class SafeAuthController {
return SaResult.error("二级认证失败");
}
// 手动关闭二级认证 ---- http://localhost:8081/safe/closeSafe
@RequestMapping("closeSafe")
public SaResult closeSafe() {
StpUtil.closeSafe();
return SaResult.ok();
}
// ------------------ 指定业务类型进行二级认证

View File

@@ -48,6 +48,18 @@ public class MySaTokenListener implements SaTokenListener {
System.out.println("---------- 自定义侦听器实现 doUntieDisable");
}
/** 每次打开二级认证时触发 */
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
System.out.println("---------- 自定义侦听器实现 doOpenSafe");
}
/** 每次关闭二级认证时触发 */
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
System.out.println("---------- 自定义侦听器实现 doCloseSafe");
}
/** 每次创建Session时触发 */
@Override
public void doCreateSession(String id) {
@@ -66,4 +78,5 @@ public class MySaTokenListener implements SaTokenListener {
System.out.println("---------- 自定义侦听器实现 doRenewTimeout");
}
}

View File

@@ -31,6 +31,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
// 注册 Sa-Token 拦截器打开注解鉴权功能
registry.addInterceptor(new SaInterceptor(handle -> {
// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
// 指定一条 match 规则
SaRouter
@@ -75,6 +76,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
// 认证函数: 每次请求执行
.setAuth(obj -> {
// System.out.println("---------- sa全局认证 " + SaHolder.getRequest().getRequestPath());
// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
// 权限校验 -- 不同模块认证不同权限
// 这里你可以写和拦截器鉴权同样的代码,不同点在于:

View File

@@ -42,6 +42,7 @@ public class StpUserUtil {
* 重置 StpLogic 对象
* <br> 1、更改此账户的 StpLogic 对象
* <br> 2、put 到全局 StpLogic 集合中
* <br> 3、发送日志
*
* @param newStpLogic /
*/
@@ -52,6 +53,9 @@ public class StpUserUtil {
// 添加到全局 StpLogic 集合中
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
SaManager.putStpLogic(newStpLogic);
// ## 发送日志
SaManager.getLogInput().replaceStpLogic(stpLogic);
}
/**

View File

@@ -42,6 +42,7 @@ public class StpUserUtil {
* 重置 StpLogic 对象
* <br> 1、更改此账户的 StpLogic 对象
* <br> 2、put 到全局 StpLogic 集合中
* <br> 3、发送日志
*
* @param newStpLogic /
*/
@@ -52,6 +53,9 @@ public class StpUserUtil {
// 添加到全局 StpLogic 集合中
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
SaManager.putStpLogic(newStpLogic);
// ## 发送日志
SaManager.getLogInput().replaceStpLogic(stpLogic);
}
/**

View File

@@ -67,6 +67,18 @@ public class MySaTokenListener implements SaTokenListener {
System.out.println("---------- 自定义侦听器实现 doUntieDisable");
}
/** 每次二级认证时触发 */
@Override
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
System.out.println("---------- 自定义侦听器实现 doOpenSafe");
}
/** 每次退出二级认证时触发 */
@Override
public void doCloseSafe(String loginType, String tokenValue, String service) {
System.out.println("---------- 自定义侦听器实现 doCloseSafe");
}
/** 每次创建Session时触发 */
@Override
public void doCreateSession(String id) {