mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-02-27 16:50:24 +08:00
Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ddfe6e50d | ||
|
|
bd509ed75f | ||
|
|
b8de417d16 | ||
|
|
6a65b63f7e | ||
|
|
5155743fb0 | ||
|
|
d2568577ba | ||
|
|
1f99a2efba | ||
|
|
bdcaecd5bc | ||
|
|
59eaed193b | ||
|
|
c2ad8bf347 | ||
|
|
637781415a | ||
|
|
234b9d4089 | ||
|
|
4a418d048b | ||
|
|
1e2abfaa15 | ||
|
|
1da64da031 | ||
|
|
f79564220e | ||
|
|
674aa8fdce | ||
|
|
062af081f7 | ||
|
|
5de3060efd | ||
|
|
f0431e3a54 | ||
|
|
6b2060e447 | ||
|
|
699670627e | ||
|
|
27dbb4842e | ||
|
|
b5691141ce | ||
|
|
0869d322db | ||
|
|
1c86312ed7 | ||
|
|
d2f0167e28 | ||
|
|
8f01bacd6f | ||
|
|
6dc9be8cd7 | ||
|
|
ac2351fd96 | ||
|
|
2abd152218 | ||
|
|
8be77d70b5 | ||
|
|
e22233576a | ||
|
|
cf8cd29a82 | ||
|
|
d2665036a2 | ||
|
|
f21b6d8b07 | ||
|
|
838f64b06b | ||
|
|
e5dc9165d1 | ||
|
|
944e7af8f3 |
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.32.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.33.0</h1>
|
||||
<h4 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h4>
|
||||
<p align="center">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
|
||||
@@ -184,7 +184,7 @@ Sa-OAuth2 模块分为四种授权模式,解决不同场景下的授权需求
|
||||
|
||||
|
||||
## 交流群
|
||||
QQ交流群:614714762 [点击加入](https://jq.qq.com/?_wv=1027&k=F96A2mrl)
|
||||
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
|
||||
|
||||
微信交流群:
|
||||
|
||||
|
||||
2
pom.xml
2
pom.xml
@@ -38,7 +38,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<revision>1.32.0</revision>
|
||||
<revision>1.33.0</revision>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
|
||||
|
||||
@@ -10,9 +10,13 @@ import cn.dev33.satoken.context.SaTokenContextDefaultImpl;
|
||||
import cn.dev33.satoken.context.second.SaTokenSecondContext;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
|
||||
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.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
import cn.dev33.satoken.log.SaLogForConsole;
|
||||
import cn.dev33.satoken.same.SaSameTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignTemplate;
|
||||
import cn.dev33.satoken.sign.SaSignTemplateDefaultImpl;
|
||||
@@ -36,18 +40,27 @@ public class SaManager {
|
||||
*/
|
||||
public volatile static SaTokenConfig config;
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaManager.config = config;
|
||||
if(config.getIsPrint()) {
|
||||
setConfigMethod(config);
|
||||
|
||||
// 打印 banner
|
||||
if(config !=null && config.getIsPrint()) {
|
||||
SaFoxUtil.printSaToken();
|
||||
}
|
||||
|
||||
// $$ 全局事件
|
||||
SaTokenEventCenter.doSetConfig(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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,6 +72,10 @@ public class SaManager {
|
||||
*/
|
||||
private volatile static SaTokenDao saTokenDao;
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
setSaTokenDaoMethod(saTokenDao);
|
||||
SaTokenEventCenter.doRegisterComponent("SaTokenDao", saTokenDao);
|
||||
}
|
||||
private static void setSaTokenDaoMethod(SaTokenDao saTokenDao) {
|
||||
if((SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
|
||||
}
|
||||
@@ -68,7 +85,7 @@ public class SaManager {
|
||||
if (saTokenDao == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
setSaTokenDaoMethod(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,12 +98,13 @@ public class SaManager {
|
||||
private volatile static StpInterface stpInterface;
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaManager.stpInterface = stpInterface;
|
||||
SaTokenEventCenter.doRegisterComponent("StpInterface", stpInterface);
|
||||
}
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
SaManager.stpInterface = new StpInterfaceDefaultImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,6 +117,7 @@ public class SaManager {
|
||||
private volatile static SaTokenContext saTokenContext;
|
||||
public static void setSaTokenContext(SaTokenContext saTokenContext) {
|
||||
SaManager.saTokenContext = saTokenContext;
|
||||
SaTokenEventCenter.doRegisterComponent("SaTokenContext", saTokenContext);
|
||||
}
|
||||
public static SaTokenContext getSaTokenContext() {
|
||||
return saTokenContext;
|
||||
@@ -108,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;
|
||||
SaTokenEventCenter.doRegisterComponent("SaTokenSecondContext", saTokenSecondContext);
|
||||
}
|
||||
public static SaTokenSecondContext getSaTokenSecondContext() {
|
||||
return saTokenSecondContext;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,12 +165,13 @@ public class SaManager {
|
||||
private volatile static SaTempInterface saTemp;
|
||||
public static void setSaTemp(SaTempInterface saTemp) {
|
||||
SaManager.saTemp = saTemp;
|
||||
SaTokenEventCenter.doRegisterComponent("SaTempInterface", saTemp);
|
||||
}
|
||||
public static SaTempInterface getSaTemp() {
|
||||
if (saTemp == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTemp == null) {
|
||||
setSaTemp(new SaTempDefaultImpl());
|
||||
SaManager.saTemp = new SaTempDefaultImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,12 +184,13 @@ public class SaManager {
|
||||
private volatile static SaJsonTemplate saJsonTemplate;
|
||||
public static void setSaJsonTemplate(SaJsonTemplate saJsonTemplate) {
|
||||
SaManager.saJsonTemplate = saJsonTemplate;
|
||||
SaTokenEventCenter.doRegisterComponent("SaJsonTemplate", saJsonTemplate);
|
||||
}
|
||||
public static SaJsonTemplate getSaJsonTemplate() {
|
||||
if (saJsonTemplate == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saJsonTemplate == null) {
|
||||
setSaJsonTemplate(new SaJsonTemplateDefaultImpl());
|
||||
SaManager.saJsonTemplate = new SaJsonTemplateDefaultImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,12 +203,13 @@ public class SaManager {
|
||||
private volatile static SaSignTemplate saSignTemplate;
|
||||
public static void setSaSignTemplate(SaSignTemplate saSignTemplate) {
|
||||
SaManager.saSignTemplate = saSignTemplate;
|
||||
SaTokenEventCenter.doRegisterComponent("SaSignTemplate", saSignTemplate);
|
||||
}
|
||||
public static SaSignTemplate getSaSignTemplate() {
|
||||
if (saSignTemplate == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saSignTemplate == null) {
|
||||
setSaSignTemplate(new SaSignTemplateDefaultImpl());
|
||||
SaManager.saSignTemplate = new SaSignTemplateDefaultImpl();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -199,17 +222,30 @@ public class SaManager {
|
||||
private volatile static SaSameTemplate saSameTemplate;
|
||||
public static void setSaSameTemplate(SaSameTemplate saSameTemplate) {
|
||||
SaManager.saSameTemplate = saSameTemplate;
|
||||
SaTokenEventCenter.doRegisterComponent("SaSameTemplate", saSameTemplate);
|
||||
}
|
||||
public static SaSameTemplate getSaSameTemplate() {
|
||||
if (saSameTemplate == null) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saSameTemplate == null) {
|
||||
setSaSameTemplate(new SaSameTemplate());
|
||||
SaManager.saSameTemplate = new SaSameTemplate();
|
||||
}
|
||||
}
|
||||
}
|
||||
return saSameTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志输出器
|
||||
*/
|
||||
public volatile static SaLog log = new SaLogForConsole();
|
||||
public static void setLog(SaLog log) {
|
||||
SaManager.log = log;
|
||||
SaTokenEventCenter.doRegisterComponent("SaLog", log);
|
||||
}
|
||||
public static SaLog getLog() {
|
||||
return SaManager.log;
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic集合, 记录框架所有成功初始化的StpLogic
|
||||
@@ -269,7 +305,7 @@ public class SaManager {
|
||||
* (1) 从main方法里调用一次
|
||||
* (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
|
||||
*/
|
||||
throw new SaTokenException("未能获取对应StpLogic,type="+ loginType);
|
||||
throw new SaTokenException("未能获取对应StpLogic,type="+ loginType).setCode(SaErrorCode.CODE_10002);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.dev33.satoken.basic;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.NotBasicAuthException;
|
||||
import cn.dev33.satoken.secure.SaBase64Util;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
@@ -24,7 +25,7 @@ public class SaBasicTemplate {
|
||||
*/
|
||||
public void throwNotBasicAuthException(String realm) {
|
||||
SaHolder.getResponse().setStatus(401).setHeader("WWW-Authenticate", "Basic Realm=" + realm);
|
||||
throw new NotBasicAuthException();
|
||||
throw new NotBasicAuthException().setCode(SaErrorCode.CODE_10311);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
@@ -15,7 +17,7 @@ import cn.dev33.satoken.util.SaFoxUtil;
|
||||
* 用于手动读取配置文件初始化 SaTokenConfig 对象,只有在非IOC环境下你才会用到此类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
* @since 2022-10-30
|
||||
*/
|
||||
public class SaTokenConfigFactory {
|
||||
|
||||
@@ -69,7 +71,7 @@ public class SaTokenConfigFactory {
|
||||
map.put(key, prop.getProperty(key));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("配置文件(" + propertiesPath + ")加载失败", e);
|
||||
throw new SaTokenException("配置文件(" + propertiesPath + ")加载失败", e).setCode(SaErrorCode.CODE_10021);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -110,7 +112,7 @@ public class SaTokenConfigFactory {
|
||||
field.setAccessible(true);
|
||||
field.set(obj, valueConvert);
|
||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
||||
throw new RuntimeException("属性赋值出错:" + field.getName(), e);
|
||||
throw new SaTokenException("属性赋值出错:" + field.getName(), e).setCode(SaErrorCode.CODE_10022);
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.InvalidContextException;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [默认实现类]
|
||||
@@ -26,14 +27,14 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
|
||||
/**
|
||||
* 默认的错误提示语
|
||||
*/
|
||||
public static final String ERROR_MESSAGE = "未初始化任何有效上下文处理器";
|
||||
public static final String ERROR_MESSAGE = "未能获取有效的上下文处理器";
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Request] 对象
|
||||
*/
|
||||
@Override
|
||||
public SaRequest getRequest() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +42,7 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
|
||||
*/
|
||||
@Override
|
||||
public SaResponse getResponse() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -49,7 +50,7 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
|
||||
*/
|
||||
@Override
|
||||
public SaStorage getStorage() {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,8 +58,7 @@ public class SaTokenContextDefaultImpl implements SaTokenContext {
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
throw new SaTokenException(ERROR_MESSAGE);
|
||||
throw new InvalidContextException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10001);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ package cn.dev33.satoken.context;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.InvalidContextException;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文处理器 [ThreadLocal版本] ---- 对象存储器
|
||||
@@ -51,7 +52,7 @@ public class SaTokenContextForThreadLocalStorage {
|
||||
public static Box getBoxNotNull() {
|
||||
Box box = boxThreadLocal.get();
|
||||
if(box == null) {
|
||||
throw new SaTokenException("未成功初始化上下文");
|
||||
throw new InvalidContextException("未能获取有效的上下文").setCode(SaErrorCode.CODE_10002);
|
||||
}
|
||||
return box;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@ import java.time.OffsetDateTime;
|
||||
import java.time.ZoneOffset;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@@ -233,10 +234,10 @@ public class SaCookie {
|
||||
this.builde();
|
||||
|
||||
if(SaFoxUtil.isEmpty(name)) {
|
||||
throw new SaTokenException("name不能为空");
|
||||
throw new SaTokenException("name不能为空").setCode(SaErrorCode.CODE_12002);
|
||||
}
|
||||
if(value != null && value.indexOf(";") > -1) {
|
||||
throw new SaTokenException("无效Value:" + value);
|
||||
throw new SaTokenException("无效Value:" + value).setCode(SaErrorCode.CODE_12003);
|
||||
}
|
||||
|
||||
// Set-Cookie: name=value; Max-Age=100000; Expires=Tue, 05-Oct-2021 20:28:17 GMT; Domain=localhost; Path=/; Secure; HttpOnly; SameSite=Lax
|
||||
@@ -254,10 +255,10 @@ public class SaCookie {
|
||||
}
|
||||
sb.append("; Expires=" + expires);
|
||||
}
|
||||
if(SaFoxUtil.isEmpty(domain) == false) {
|
||||
if(!SaFoxUtil.isEmpty(domain)) {
|
||||
sb.append("; Domain=" + domain);
|
||||
}
|
||||
if(SaFoxUtil.isEmpty(path) == false) {
|
||||
if(!SaFoxUtil.isEmpty(path)) {
|
||||
sb.append("; Path=" + path);
|
||||
}
|
||||
if(secure) {
|
||||
@@ -266,8 +267,8 @@ public class SaCookie {
|
||||
if(httpOnly) {
|
||||
sb.append("; HttpOnly");
|
||||
}
|
||||
if(SaFoxUtil.isEmpty(sameSite) == false) {
|
||||
sb.append("; sameSite=" + sameSite);
|
||||
if(!SaFoxUtil.isEmpty(sameSite)) {
|
||||
sb.append("; SameSite=" + sameSite);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.dev33.satoken.context.model;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@@ -65,7 +66,7 @@ public interface SaRequest {
|
||||
public default String getParamNotNull(String name) {
|
||||
String paramValue = getParam(name);
|
||||
if(SaFoxUtil.isEmpty(paramValue)) {
|
||||
throw new SaTokenException("缺少参数:" + name);
|
||||
throw new SaTokenException("缺少参数:" + name).setCode(SaErrorCode.CODE_12001);
|
||||
}
|
||||
return paramValue;
|
||||
}
|
||||
@@ -139,8 +140,6 @@ public interface SaRequest {
|
||||
* @param path 转发地址
|
||||
* @return 任意值
|
||||
*/
|
||||
public default Object forward(String path) {
|
||||
throw new SaTokenException("No implementation");
|
||||
}
|
||||
public Object forward(String path);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
package cn.dev33.satoken.error;
|
||||
|
||||
/**
|
||||
* 定义所有异常细分状态码
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-10-30
|
||||
*/
|
||||
public interface SaErrorCode {
|
||||
|
||||
/** 代表这个异常在抛出时未指定异常细分状态码 */
|
||||
public static final int CODE_UNDEFINED = -1;
|
||||
|
||||
// ------------
|
||||
|
||||
/** 未能获取有效的上下文处理器 */
|
||||
public static final int CODE_10001 = 10001;
|
||||
|
||||
/** 未能获取有效的上下文 */
|
||||
public static final int CODE_10002 = 10002;
|
||||
|
||||
/** JSON 转换器未实现 */
|
||||
public static final int CODE_10003 = 10003;
|
||||
|
||||
/** 未能从全局 StpLogic 集合中找到对应 type 的 StpLogic */
|
||||
public static final int CODE_10011 = 10011;
|
||||
|
||||
/** 指定的配置文件加载失败 */
|
||||
public static final int CODE_10021 = 10021;
|
||||
|
||||
/** 配置文件属性无法正常读取 */
|
||||
public static final int CODE_10022 = 10022;
|
||||
|
||||
/** 重置的侦听器集合不可以为空 */
|
||||
public static final int CODE_10031 = 10031;
|
||||
|
||||
/** 注册的侦听器不可以为空 */
|
||||
public static final int CODE_10032 = 10032;
|
||||
|
||||
// 1030x core模块
|
||||
|
||||
/** 提供的 Same-Token 是无效的 */
|
||||
public static final int CODE_10301 = 10301;
|
||||
|
||||
/** 表示未能通过 Http Basic 认证校验 */
|
||||
public static final int CODE_10311 = 10311;
|
||||
|
||||
/** 提供的 HttpMethod 是无效的 */
|
||||
public static final int CODE_10321 = 10321;
|
||||
|
||||
// 1100x StpLogic
|
||||
|
||||
/** 未能读取到有效Token */
|
||||
public static final int CODE_11001 = 11001;
|
||||
|
||||
/** 登录时的账号id值为空 */
|
||||
public static final int CODE_11002 = 11002;
|
||||
|
||||
/** 更改 Token 指向的 账号Id 时,账号Id值为空 */
|
||||
public static final int CODE_11003 = 11003;
|
||||
|
||||
/** 未能读取到有效Token */
|
||||
public static final int CODE_11011 = 11011;
|
||||
|
||||
/** Token无效 */
|
||||
public static final int CODE_11012 = 11012;
|
||||
|
||||
/** Token已过期 */
|
||||
public static final int CODE_11013 = 11013;
|
||||
|
||||
/** Token已被顶下线 */
|
||||
public static final int CODE_11014 = 11014;
|
||||
|
||||
/** Token已被踢下线 */
|
||||
public static final int CODE_11015 = 11015;
|
||||
|
||||
/** Token已临时过期 */
|
||||
public static final int CODE_11016 = 11016;
|
||||
|
||||
/** 在未集成 sa-token-jwt 插件时调用 getExtra() 抛出异常 */
|
||||
public static final int CODE_11031 = 11031;
|
||||
|
||||
/** 缺少指定的角色 */
|
||||
public static final int CODE_11041 = 11041;
|
||||
|
||||
/** 缺少指定的权限 */
|
||||
public static final int CODE_11051 = 11051;
|
||||
|
||||
/** 当前账号未通过服务封禁校验 */
|
||||
public static final int CODE_11061 = 11061;
|
||||
|
||||
/** 提供要解禁的账号无效 */
|
||||
public static final int CODE_11062 = 11062;
|
||||
|
||||
/** 提供要解禁的服务无效 */
|
||||
public static final int CODE_11063 = 11063;
|
||||
|
||||
/** 提供要解禁的等级无效 */
|
||||
public static final int CODE_11064 = 11064;
|
||||
|
||||
/** 二级认证校验未通过 */
|
||||
public static final int CODE_11071 = 11071;
|
||||
|
||||
|
||||
|
||||
// ------------
|
||||
|
||||
/** 请求中缺少指定的参数 */
|
||||
public static final int CODE_12001 = 12001;
|
||||
|
||||
/** 构建 Cookie 时缺少 name 参数 */
|
||||
public static final int CODE_12002 = 12002;
|
||||
|
||||
/** 构建 Cookie 时缺少 value 参数 */
|
||||
public static final int CODE_12003 = 12003;
|
||||
|
||||
// ------------
|
||||
|
||||
/** Base64 编码异常 */
|
||||
public static final int CODE_12101 = 12101;
|
||||
|
||||
/** Base64 解码异常 */
|
||||
public static final int CODE_12102 = 12102;
|
||||
|
||||
/** URL 编码异常 */
|
||||
public static final int CODE_12103 = 12103;
|
||||
|
||||
/** URL 解码异常 */
|
||||
public static final int CODE_12104 = 12104;
|
||||
|
||||
/** md5 加密异常 */
|
||||
public static final int CODE_12111 = 12111;
|
||||
|
||||
/** sha1 加密异常 */
|
||||
public static final int CODE_12112 = 12112;
|
||||
|
||||
/** sha256 加密异常 */
|
||||
public static final int CODE_12113 = 12113;
|
||||
|
||||
/** AES 加密异常 */
|
||||
public static final int CODE_12114 = 12114;
|
||||
|
||||
/** AES 解密异常 */
|
||||
public static final int CODE_12115 = 12115;
|
||||
|
||||
/** RSA 公钥加密异常 */
|
||||
public static final int CODE_12116 = 12116;
|
||||
|
||||
/** RSA 私钥加密异常 */
|
||||
public static final int CODE_12117 = 12117;
|
||||
|
||||
/** RSA 公钥解密异常 */
|
||||
public static final int CODE_12118 = 12118;
|
||||
|
||||
/** RSA 私钥解密异常 */
|
||||
public static final int CODE_12119 = 12119;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表未能获取有效的上下文
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-29
|
||||
*/
|
||||
public class InvalidContextException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130144L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表未能获取有效的上下文
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public InvalidContextException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表组件或方法未被提供有效的实现
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-30
|
||||
*/
|
||||
public class NotImplException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130144L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表组件或方法未被提供有效的实现
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public NotImplException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 一个异常:代表不是 Web 上下文
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-29
|
||||
*/
|
||||
public class NotWebContextException extends SaTokenException {
|
||||
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130144L;
|
||||
|
||||
/**
|
||||
* 一个异常:代表不是 Web 上下文
|
||||
* @param message 异常描述
|
||||
*/
|
||||
public NotWebContextException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
/**
|
||||
* 定义所有异常细分状态码
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-4-25
|
||||
*/
|
||||
public class SaExceptionCode {
|
||||
|
||||
/** 代表这个异常在抛出时未指定异常细分状态码 */
|
||||
public static final int CODE_UNDEFINED = -1;
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.dev33.satoken.exception;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
@@ -19,7 +20,7 @@ public class SaTokenException extends RuntimeException {
|
||||
/**
|
||||
* 异常细分状态码
|
||||
*/
|
||||
private int code = SaExceptionCode.CODE_UNDEFINED;
|
||||
private int code = SaErrorCode.CODE_UNDEFINED;
|
||||
|
||||
/**
|
||||
* 构建一个异常
|
||||
@@ -93,8 +94,9 @@ public class SaTokenException extends RuntimeException {
|
||||
* 如果flag==true,则抛出message异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分状态码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message) {
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaTokenException(message);
|
||||
}
|
||||
@@ -104,10 +106,11 @@ public class SaTokenException extends RuntimeException {
|
||||
* 如果value==null或者isEmpty,则抛出message异常
|
||||
* @param value 值
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分状态码
|
||||
*/
|
||||
public static void throwByNull(Object value, String message) {
|
||||
public static void throwByNull(Object value, String message, int code) {
|
||||
if(SaFoxUtil.isEmpty(value)) {
|
||||
throw new SaTokenException(message);
|
||||
throw new SaTokenException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ package cn.dev33.satoken.json;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.exception.ApiDisabledException;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.NotImplException;
|
||||
|
||||
/**
|
||||
* JSON 相关操作接口
|
||||
@@ -19,7 +20,7 @@ public class SaJsonTemplateDefaultImpl implements SaJsonTemplate {
|
||||
*/
|
||||
@Override
|
||||
public String toJsonString(Object obj) {
|
||||
throw new ApiDisabledException(ERROR_MESSAGE);
|
||||
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10003);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -27,7 +28,7 @@ public class SaJsonTemplateDefaultImpl implements SaJsonTemplate {
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> parseJsonToMap(String jsonStr) {
|
||||
throw new ApiDisabledException(ERROR_MESSAGE);
|
||||
throw new NotImplException(ERROR_MESSAGE).setCode(SaErrorCode.CODE_10003);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -3,8 +3,11 @@ package cn.dev33.satoken.listener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
/**
|
||||
* Sa-Token 事件中心 事件发布器
|
||||
@@ -20,7 +23,7 @@ public class SaTokenEventCenter {
|
||||
|
||||
static {
|
||||
// 默认添加控制台日志侦听器
|
||||
listenerList.add(new SaTokenListenerForConsolePrint());
|
||||
listenerList.add(new SaTokenListenerForLog());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -37,7 +40,7 @@ public class SaTokenEventCenter {
|
||||
*/
|
||||
public static void setListenerList(List<SaTokenListener> listenerList) {
|
||||
if(listenerList == null) {
|
||||
throw new SaTokenException("重置的侦听器集合不可以为空");
|
||||
throw new SaTokenException("重置的侦听器集合不可以为空").setCode(SaErrorCode.CODE_10031);
|
||||
}
|
||||
SaTokenEventCenter.listenerList = listenerList;
|
||||
}
|
||||
@@ -48,7 +51,7 @@ public class SaTokenEventCenter {
|
||||
*/
|
||||
public static void registerListener(SaTokenListener listener) {
|
||||
if(listener == null) {
|
||||
throw new SaTokenException("注册的侦听器不可以为空");
|
||||
throw new SaTokenException("注册的侦听器不可以为空").setCode(SaErrorCode.CODE_10032);
|
||||
}
|
||||
listenerList.add(listener);
|
||||
}
|
||||
@@ -59,11 +62,11 @@ public class SaTokenEventCenter {
|
||||
*/
|
||||
public static void registerListenerList(List<SaTokenListener> listenerList) {
|
||||
if(listenerList == null) {
|
||||
throw new SaTokenException("注册的侦听器不可以为空");
|
||||
throw new SaTokenException("注册的侦听器集合不可以为空").setCode(SaErrorCode.CODE_10031);
|
||||
}
|
||||
for (SaTokenListener listener : listenerList) {
|
||||
if(listener == null) {
|
||||
throw new SaTokenException("注册的侦听器不可以为空");
|
||||
throw new SaTokenException("注册的侦听器不可以为空").setCode(SaErrorCode.CODE_10032);
|
||||
}
|
||||
}
|
||||
SaTokenEventCenter.listenerList.addAll(listenerList);
|
||||
@@ -197,7 +200,32 @@ public class SaTokenEventCenter {
|
||||
listener.doUntieDisable(loginType, loginId, service);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 每次打开二级认证时触发
|
||||
* @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
|
||||
@@ -231,4 +259,36 @@ public class SaTokenEventCenter {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 全局组件载入
|
||||
* @param comtName 组件名称
|
||||
* @param comtObj 组件对象
|
||||
*/
|
||||
public static void doRegisterComponent(String comtName, Object comtObj) {
|
||||
for (SaTokenListener listener : listenerList) {
|
||||
listener.doRegisterComponent(comtName, comtObj);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic 对象替换
|
||||
* @param stpLogic /
|
||||
*/
|
||||
public static void doSetStpLogic(StpLogic stpLogic) {
|
||||
for (SaTokenListener listener : listenerList) {
|
||||
listener.doSetStpLogic(stpLogic);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 载入全局配置
|
||||
* @param config /
|
||||
*/
|
||||
public static void doSetConfig(SaTokenConfig config) {
|
||||
for (SaTokenListener listener : listenerList) {
|
||||
listener.doSetConfig(config);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
|
||||
/**
|
||||
* Sa-Token 侦听器
|
||||
@@ -60,7 +62,24 @@ public interface SaTokenListener {
|
||||
* @param service 指定服务
|
||||
*/
|
||||
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
|
||||
@@ -81,5 +100,24 @@ public interface SaTokenListener {
|
||||
* @param timeout 续期时间
|
||||
*/
|
||||
public void doRenewTimeout(String tokenValue, Object loginId, long timeout);
|
||||
|
||||
|
||||
/**
|
||||
* 全局组件载入
|
||||
* @param comtName 组件名称
|
||||
* @param comtObj 组件对象
|
||||
*/
|
||||
public default void doRegisterComponent(String comtName, Object comtObj) {}
|
||||
|
||||
/**
|
||||
* StpLogic 对象替换
|
||||
* @param stpLogic /
|
||||
*/
|
||||
public default void doSetStpLogic(StpLogic stpLogic) {}
|
||||
|
||||
/**
|
||||
* 载入全局配置
|
||||
* @param config /
|
||||
*/
|
||||
public default void doSetConfig(SaTokenConfig config) {}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package cn.dev33.satoken.listener;
|
||||
|
||||
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 侦听器实现:Log 打印
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-11-2
|
||||
*/
|
||||
public class SaTokenListenerForLog implements SaTokenListener {
|
||||
|
||||
/**
|
||||
* 每次登录时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
|
||||
log.info("账号 {} 登录成功 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次注销时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogout(String loginType, Object loginId, String tokenValue) {
|
||||
log.info("账号 {} 注销登录 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被踢下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doKickout(String loginType, Object loginId, String tokenValue) {
|
||||
log.info("账号 {} 被踢下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被顶下线时触发
|
||||
*/
|
||||
@Override
|
||||
public void doReplaced(String loginType, Object loginId, String tokenValue) {
|
||||
log.info("账号 {} 被顶下线 (loginType={}), 会话凭证Token={}", loginId, loginType, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被封禁时触发
|
||||
*/
|
||||
@Override
|
||||
public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {
|
||||
log.info("账号 {} [{}服务] 被封禁 (loginType={}), 封禁等级={}, 解封时间为 {}", loginId, loginType, service, level, SaFoxUtil.formatAfterDate(disableTime * 1000));
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次被解封时触发
|
||||
*/
|
||||
@Override
|
||||
public void doUntieDisable(String loginType, Object loginId, String service) {
|
||||
log.info("账号 {} [{}服务] 解封成功 (loginType={})", loginId, service, loginType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次打开二级认证时触发
|
||||
*/
|
||||
@Override
|
||||
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
|
||||
log.info("Token 二级认证成功, 业务标识={}, 有效期={}秒, Token值={}", service, safeTime, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次关闭二级认证时触发
|
||||
*/
|
||||
@Override
|
||||
public void doCloseSafe(String loginType, String tokenValue, String service) {
|
||||
log.info("Token 二级认证关闭, 业务标识={}, Token值={}", service, tokenValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次创建Session时触发
|
||||
*/
|
||||
@Override
|
||||
public void doCreateSession(String id) {
|
||||
log.info("SaSession [{}] 创建成功", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次注销Session时触发
|
||||
*/
|
||||
@Override
|
||||
public void doLogoutSession(String id) {
|
||||
log.info("SaSession [{}] 注销成功", id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次Token续期时触发
|
||||
*/
|
||||
@Override
|
||||
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
|
||||
log.info("Token 续期成功, {} 秒后到期, 帐号={}, Token值={} ", timeout, loginId, tokenValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 全局组件载入
|
||||
* @param comtName 组件名称
|
||||
* @param comtObj 组件对象
|
||||
*/
|
||||
@Override
|
||||
public void doRegisterComponent(String comtName, Object comtObj) {
|
||||
String canonicalName = comtObj == null ? null : comtObj.getClass().getCanonicalName();
|
||||
log.info("全局组件 {} 载入成功: {}", comtName, canonicalName);
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic 对象替换
|
||||
* @param stpLogic /
|
||||
*/
|
||||
@Override
|
||||
public void doSetStpLogic(StpLogic stpLogic) {
|
||||
if(stpLogic != null) {
|
||||
log.info("会话组件 StpLogic(type={}) 重置成功: {}", stpLogic.getLoginType(), stpLogic.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 载入全局配置
|
||||
* @param config /
|
||||
*/
|
||||
@Override
|
||||
public void doSetConfig(SaTokenConfig config) {
|
||||
if(config != null) {
|
||||
log.info("全局配置 {} ", config);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -40,6 +40,16 @@ public class SaTokenListenerForSimple implements SaTokenListener {
|
||||
@Override
|
||||
public void doUntieDisable(String loginType, Object loginId, String service) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doOpenSafe(String loginType, String tokenValue, String service, long safeTime) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doCloseSafe(String loginType, String tokenValue, String service) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,4 +67,5 @@ public class SaTokenListenerForSimple implements SaTokenListener {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
53
sa-token-core/src/main/java/cn/dev33/satoken/log/SaLog.java
Normal file
53
sa-token-core/src/main/java/cn/dev33/satoken/log/SaLog.java
Normal 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);
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package cn.dev33.satoken.router;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
@@ -37,11 +38,11 @@ public enum SaHttpMethod {
|
||||
*/
|
||||
public static SaHttpMethod toEnum(String method) {
|
||||
if(method == null) {
|
||||
throw new SaTokenException("无效Method:" + method);
|
||||
throw new SaTokenException("无效Method:" + method).setCode(SaErrorCode.CODE_10321);
|
||||
}
|
||||
SaHttpMethod reqMethod = map.get(method.toUpperCase());
|
||||
if(reqMethod == null) {
|
||||
throw new SaTokenException("无效Method:" + method);
|
||||
throw new SaTokenException("无效Method:" + method).setCode(SaErrorCode.CODE_10321);
|
||||
}
|
||||
return reqMethod;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package cn.dev33.satoken.same;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SameTokenInvalidException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
@@ -57,7 +58,7 @@ public class SaSameTemplate {
|
||||
public void checkToken(String token) {
|
||||
if(isValid(token) == false) {
|
||||
token = (token == null ? "" : token);
|
||||
throw new SameTokenInvalidException("无效Same-Token:" + token);
|
||||
throw new SameTokenInvalidException("无效Same-Token:" + token).setCode(SaErrorCode.CODE_10301);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ package cn.dev33.satoken.secure;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Base64;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
* Sa-Token Base64工具类
|
||||
* @author kong
|
||||
@@ -40,7 +43,7 @@ public class SaBase64Util {
|
||||
try {
|
||||
return encoder.encodeToString(text.getBytes("UTF-8"));
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12101);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +56,7 @@ public class SaBase64Util {
|
||||
try {
|
||||
return new String(decoder.decode(base64Text), "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new RuntimeException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12101);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cn.dev33.satoken.secure;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
@@ -23,6 +22,7 @@ import javax.crypto.KeyGenerator;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return new String(strA);
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12111);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return new String(chs);
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12112);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ public class SaSecureUtil {
|
||||
|
||||
return builder.toString();
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12113);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +164,7 @@ public class SaSecureUtil {
|
||||
byte[] result = cipher.doFinal(byteContent);
|
||||
return encoder.encodeToString(result);
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12114);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ public class SaSecureUtil {
|
||||
byte[] result = cipher.doFinal(decoder.decode(text));
|
||||
return new String(result, "utf-8");
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12115);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,15 +220,9 @@ public class SaSecureUtil {
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
|
||||
KeyPair keyPair;
|
||||
|
||||
try {
|
||||
keyPairGenerator.initialize(KEY_SIZE,
|
||||
new SecureRandom(UUID.randomUUID().toString().replaceAll("-", "").getBytes()));
|
||||
keyPair = keyPairGenerator.generateKeyPair();
|
||||
} catch (InvalidParameterException e) {
|
||||
throw e;
|
||||
} catch (NullPointerException e) {
|
||||
throw e;
|
||||
}
|
||||
keyPairGenerator.initialize(KEY_SIZE,
|
||||
new SecureRandom(UUID.randomUUID().toString().replaceAll("-", "").getBytes()));
|
||||
keyPair = keyPairGenerator.generateKeyPair();
|
||||
|
||||
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
|
||||
@@ -261,7 +255,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12116);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +280,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12117);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +307,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12118);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +333,7 @@ public class SaSecureUtil {
|
||||
}
|
||||
return stringBuffer.toString();
|
||||
} catch (Exception e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12119);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.ApiDisabledException;
|
||||
import cn.dev33.satoken.exception.DisableServiceException;
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
@@ -255,7 +256,7 @@ public class StpLogic {
|
||||
public String getTokenValueNotNull(){
|
||||
String tokenValue = getTokenValue();
|
||||
if(SaFoxUtil.isEmpty(tokenValue)) {
|
||||
throw new SaTokenException("未能读取到有效Token");
|
||||
throw new SaTokenException("未能读取到有效Token").setCode(SaErrorCode.CODE_11001);
|
||||
}
|
||||
return tokenValue;
|
||||
}
|
||||
@@ -351,7 +352,7 @@ public class StpLogic {
|
||||
public String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
|
||||
// ------ 前置检查
|
||||
SaTokenException.throwByNull(id, "账号id不能为空");
|
||||
SaTokenException.throwByNull(id, "账号id不能为空", SaErrorCode.CODE_11002);
|
||||
|
||||
// ------ 1、初始化 loginModel
|
||||
SaTokenConfig config = getConfig();
|
||||
@@ -374,7 +375,7 @@ public class StpLogic {
|
||||
// 写入 [token-last-activity]
|
||||
setLastActivityToNow(tokenValue);
|
||||
|
||||
// $$ 发布事件:账号xxx 登录成功
|
||||
// $$ 发布事件:账号 xxx 登录成功
|
||||
SaTokenEventCenter.doLogin(loginType, id, tokenValue, loginModel);
|
||||
|
||||
// 检查此账号会话数量是否超出最大值
|
||||
@@ -550,7 +551,7 @@ public class StpLogic {
|
||||
|
||||
// $$ 发布事件:某某Token注销下线了
|
||||
SaTokenEventCenter.doLogout(loginType, loginId, tokenValue);
|
||||
|
||||
|
||||
// 4. 清理User-Session上的token签名 & 尝试注销User-Session
|
||||
SaSession session = getSessionByLoginId(loginId, false);
|
||||
if(session != null) {
|
||||
@@ -677,24 +678,24 @@ public class StpLogic {
|
||||
// 如果获取不到token,则抛出: 无token
|
||||
String tokenValue = getTokenValue();
|
||||
if(tokenValue == null) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.NOT_TOKEN);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.NOT_TOKEN).setCode(SaErrorCode.CODE_11011);
|
||||
}
|
||||
// 查找此token对应loginId, 如果找不到则抛出:无效token
|
||||
String loginId = getLoginIdNotHandle(tokenValue);
|
||||
if(loginId == null) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.INVALID_TOKEN, tokenValue);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.INVALID_TOKEN, tokenValue).setCode(SaErrorCode.CODE_11012);
|
||||
}
|
||||
// 如果是已经过期,则抛出:已经过期
|
||||
if(loginId.equals(NotLoginException.TOKEN_TIMEOUT)) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.TOKEN_TIMEOUT, tokenValue);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.TOKEN_TIMEOUT, tokenValue).setCode(SaErrorCode.CODE_11013);
|
||||
}
|
||||
// 如果是已经被顶替下去了, 则抛出:已被顶下线
|
||||
if(loginId.equals(NotLoginException.BE_REPLACED)) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.BE_REPLACED, tokenValue);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.BE_REPLACED, tokenValue).setCode(SaErrorCode.CODE_11014);
|
||||
}
|
||||
// 如果是已经被踢下线了, 则抛出:已被踢下线
|
||||
if(loginId.equals(NotLoginException.KICK_OUT)) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.KICK_OUT, tokenValue);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.KICK_OUT, tokenValue).setCode(SaErrorCode.CODE_11015);
|
||||
}
|
||||
// 检查是否已经 [临时过期]
|
||||
checkActivityTimeout(tokenValue);
|
||||
@@ -817,7 +818,7 @@ public class StpLogic {
|
||||
* @return 对应的扩展数据
|
||||
*/
|
||||
public Object getExtra(String key) {
|
||||
throw new ApiDisabledException();
|
||||
throw new ApiDisabledException().setCode(SaErrorCode.CODE_11031);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -827,7 +828,7 @@ public class StpLogic {
|
||||
* @return 对应的扩展数据
|
||||
*/
|
||||
public Object getExtra(String tokenValue, String key) {
|
||||
throw new ApiDisabledException();
|
||||
throw new ApiDisabledException().setCode(SaErrorCode.CODE_11031);
|
||||
}
|
||||
|
||||
|
||||
@@ -853,7 +854,7 @@ public class StpLogic {
|
||||
* @param loginId 新的账号Id值
|
||||
*/
|
||||
public void updateTokenToIdMapping(String tokenValue, Object loginId) {
|
||||
SaTokenException.throwBy(SaFoxUtil.isEmpty(loginId), "LoginId 不能为空");
|
||||
SaTokenException.throwBy(SaFoxUtil.isEmpty(loginId), "LoginId 不能为空", SaErrorCode.CODE_11003);
|
||||
getSaTokenDao().update(splicingKeyTokenValue(tokenValue), loginId.toString());
|
||||
}
|
||||
/**
|
||||
@@ -1096,7 +1097,7 @@ public class StpLogic {
|
||||
}
|
||||
// -2 代表已过期,抛出异常
|
||||
if(timeout == SaTokenDao.NOT_VALUE_EXPIRE) {
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.TOKEN_TIMEOUT, tokenValue);
|
||||
throw NotLoginException.newInstance(loginType, NotLoginException.TOKEN_TIMEOUT, tokenValue).setCode(SaErrorCode.CODE_11016);
|
||||
}
|
||||
// --- 至此,验证已通过
|
||||
|
||||
@@ -1353,7 +1354,7 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkRole(String role) {
|
||||
if(hasRole(role) == false) {
|
||||
throw new NotRoleException(role, this.loginType);
|
||||
throw new NotRoleException(role, this.loginType).setCode(SaErrorCode.CODE_11041);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1366,7 +1367,7 @@ public class StpLogic {
|
||||
List<String> roleList = getRoleList(loginId);
|
||||
for (String role : roleArray) {
|
||||
if(!hasElement(roleList, role)) {
|
||||
throw new NotRoleException(role, this.loginType);
|
||||
throw new NotRoleException(role, this.loginType).setCode(SaErrorCode.CODE_11041);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1385,7 +1386,7 @@ public class StpLogic {
|
||||
}
|
||||
}
|
||||
if(roleArray.length > 0) {
|
||||
throw new NotRoleException(roleArray[0], this.loginType);
|
||||
throw new NotRoleException(roleArray[0], this.loginType).setCode(SaErrorCode.CODE_11041);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1466,7 +1467,7 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkPermission(String permission) {
|
||||
if(hasPermission(permission) == false) {
|
||||
throw new NotPermissionException(permission, this.loginType);
|
||||
throw new NotPermissionException(permission, this.loginType).setCode(SaErrorCode.CODE_11051);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1479,7 +1480,7 @@ public class StpLogic {
|
||||
List<String> permissionList = getPermissionList(loginId);
|
||||
for (String permission : permissionArray) {
|
||||
if(!hasElement(permissionList, permission)) {
|
||||
throw new NotPermissionException(permission, this.loginType);
|
||||
throw new NotPermissionException(permission, this.loginType).setCode(SaErrorCode.CODE_11051);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1498,7 +1499,7 @@ public class StpLogic {
|
||||
}
|
||||
}
|
||||
if(permissionArray.length > 0) {
|
||||
throw new NotPermissionException(permissionArray[0], this.loginType);
|
||||
throw new NotPermissionException(permissionArray[0], this.loginType).setCode(SaErrorCode.CODE_11051);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1808,10 +1809,10 @@ public class StpLogic {
|
||||
public void untieDisable(Object loginId, String... services) {
|
||||
// 空值检查
|
||||
if(SaFoxUtil.isEmpty(loginId)) {
|
||||
throw new SaTokenException("请提供要解禁的账号");
|
||||
throw new SaTokenException("请提供要解禁的账号").setCode(SaErrorCode.CODE_11062);
|
||||
}
|
||||
if(services == null || services.length == 0) {
|
||||
throw new SaTokenException("请提供要解禁的服务");
|
||||
throw new SaTokenException("请提供要解禁的服务").setCode(SaErrorCode.CODE_11063);
|
||||
}
|
||||
|
||||
for (String service : services) {
|
||||
@@ -1846,13 +1847,13 @@ public class StpLogic {
|
||||
public void disableLevel(Object loginId, String service, int level, long time) {
|
||||
// 空值检查
|
||||
if(SaFoxUtil.isEmpty(loginId)) {
|
||||
throw new SaTokenException("请提供要封禁的账号");
|
||||
throw new SaTokenException("请提供要封禁的账号").setCode(SaErrorCode.CODE_11062);
|
||||
}
|
||||
if(SaFoxUtil.isEmpty(service)) {
|
||||
throw new SaTokenException("请提供要封禁的服务");
|
||||
throw new SaTokenException("请提供要封禁的服务").setCode(SaErrorCode.CODE_11063);
|
||||
}
|
||||
if(level < SaTokenConsts.MIN_DISABLE_LEVEL) {
|
||||
throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL);
|
||||
throw new SaTokenException("封禁等级不可以小于最小值:" + SaTokenConsts.MIN_DISABLE_LEVEL).setCode(SaErrorCode.CODE_11064);
|
||||
}
|
||||
|
||||
// 标注为已被封禁
|
||||
@@ -1917,7 +1918,7 @@ public class StpLogic {
|
||||
// s2. 检测被封禁的等级是否达到指定级别
|
||||
Integer disableLevel = SaFoxUtil.getValueByType(value, int.class);
|
||||
if(disableLevel >= level) {
|
||||
throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service));
|
||||
throw new DisableServiceException(loginType, loginId, service, disableLevel, level, getDisableTime(loginId, service)).setCode(SaErrorCode.CODE_11061);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2017,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2069,7 +2075,7 @@ public class StpLogic {
|
||||
public void checkSafe(String service) {
|
||||
String tokenValue = getTokenValue();
|
||||
if (isSafe(tokenValue, service) == false) {
|
||||
throw new NotSafeException(loginType, tokenValue, service);
|
||||
throw new NotSafeException(loginType, tokenValue, service).setCode(SaErrorCode.CODE_11071);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2117,6 +2123,9 @@ public class StpLogic {
|
||||
|
||||
// 删除 key
|
||||
getSaTokenDao().delete(splicingKeySafe(tokenValue, service));
|
||||
|
||||
// $$ 发布事件
|
||||
SaTokenEventCenter.doCloseSafe(loginType, tokenValue, service);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
@@ -36,6 +37,7 @@ public class StpUtil {
|
||||
* 重置 StpLogic 对象
|
||||
* <br> 1、更改此账户的 StpLogic 对象
|
||||
* <br> 2、put 到全局 StpLogic 集合中
|
||||
* <br> 3、发送日志
|
||||
*
|
||||
* @param newStpLogic /
|
||||
*/
|
||||
@@ -46,6 +48,9 @@ public class StpUtil {
|
||||
// 添加到全局 StpLogic 集合中
|
||||
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
|
||||
SaManager.putStpLogic(newStpLogic);
|
||||
|
||||
// $$ 全局事件
|
||||
SaTokenEventCenter.doSetStpLogic(stpLogic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
@@ -15,6 +18,7 @@ import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import cn.dev33.satoken.error.SaErrorCode;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
|
||||
/**
|
||||
@@ -24,10 +28,6 @@ import cn.dev33.satoken.exception.SaTokenException;
|
||||
*
|
||||
*/
|
||||
public class SaFoxUtil {
|
||||
/**
|
||||
* 可以减少线程争用的随机对象
|
||||
*/
|
||||
private static final ThreadLocalRandom RANDOM = ThreadLocalRandom.current();
|
||||
|
||||
private SaFoxUtil() {
|
||||
}
|
||||
@@ -60,7 +60,7 @@ public class SaFoxUtil {
|
||||
String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int number = RANDOM.nextInt(62);
|
||||
int number = ThreadLocalRandom.current().nextInt(62);
|
||||
sb.append(str.charAt(number));
|
||||
}
|
||||
return sb.toString();
|
||||
@@ -83,7 +83,17 @@ public class SaFoxUtil {
|
||||
public static boolean isNotEmpty(Object str) {
|
||||
return isEmpty(str) == false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 指定数组是否为null或者空数组
|
||||
* @param <T> /
|
||||
* @param array /
|
||||
* @return /
|
||||
*/
|
||||
public static <T> boolean isEmpty(T[] array) {
|
||||
return array == null || array.length == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个对象是否相等
|
||||
* @param a 第一个对象
|
||||
@@ -100,7 +110,7 @@ public class SaFoxUtil {
|
||||
* @return 随机字符串
|
||||
*/
|
||||
public static String getMarking28() {
|
||||
return System.currentTimeMillis() + "" + RANDOM.nextInt(Integer.MAX_VALUE);
|
||||
return System.currentTimeMillis() + "" + ThreadLocalRandom.current().nextInt(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +130,18 @@ public class SaFoxUtil {
|
||||
public static String formatDate(ZonedDateTime zonedDateTime) {
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从集合里查询数据
|
||||
*
|
||||
@@ -451,7 +472,7 @@ public class SaFoxUtil {
|
||||
try {
|
||||
return URLEncoder.encode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12103);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,7 +485,7 @@ public class SaFoxUtil {
|
||||
try {
|
||||
return URLDecoder.decode(url, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new SaTokenException(e);
|
||||
throw new SaTokenException(e).setCode(SaErrorCode.CODE_12104);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -518,7 +539,7 @@ public class SaFoxUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* Array 转 String,按照逗号切割
|
||||
* Array 转 String,按照逗号连接
|
||||
* @param arr 数组
|
||||
* @return 字符串
|
||||
*/
|
||||
@@ -551,7 +572,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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class SaTokenConsts {
|
||||
/**
|
||||
* Sa-Token 当前版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.32.0";
|
||||
public static final String VERSION_NO = "v1.33.0";
|
||||
|
||||
/**
|
||||
* Sa-Token 开源地址 Gitee
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.pj;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Sa-Token 示例
|
||||
* @author kong
|
||||
@@ -13,6 +15,7 @@ public class SaTokenCaseApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenCaseApplication.class, args);
|
||||
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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 + " 解封成功");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
// ------------------ 指定业务类型进行二级认证
|
||||
|
||||
|
||||
@@ -47,7 +47,19 @@ public class MySaTokenListener implements SaTokenListener {
|
||||
public void doUntieDisable(String loginType, Object loginId, String service) {
|
||||
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) {
|
||||
@@ -65,5 +77,6 @@ public class MySaTokenListener implements SaTokenListener {
|
||||
public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {
|
||||
System.out.println("---------- 自定义侦听器实现 doRenewTimeout");
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
|
||||
/**
|
||||
* 将 Sa-Token log 信息转接到 Slf4j
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-11-2
|
||||
*/
|
||||
//@Component
|
||||
public class SaLogForSlf4j implements SaLog {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(SaLogForSlf4j.class);
|
||||
|
||||
@Override
|
||||
public void trace(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String str, Object... args) {
|
||||
log.debug(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String str, Object... args) {
|
||||
log.info(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
// 权限校验 -- 不同模块认证不同权限
|
||||
// 这里你可以写和拦截器鉴权同样的代码,不同点在于:
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
@@ -42,6 +43,7 @@ public class StpUserUtil {
|
||||
* 重置 StpLogic 对象
|
||||
* <br> 1、更改此账户的 StpLogic 对象
|
||||
* <br> 2、put 到全局 StpLogic 集合中
|
||||
* <br> 3、发送日志
|
||||
*
|
||||
* @param newStpLogic /
|
||||
*/
|
||||
@@ -52,6 +54,9 @@ public class StpUserUtil {
|
||||
// 添加到全局 StpLogic 集合中
|
||||
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
|
||||
SaManager.putStpLogic(newStpLogic);
|
||||
|
||||
// $$ 全局事件
|
||||
SaTokenEventCenter.doSetStpLogic(stpLogic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<lombok.version>1.18.10</lombok.version>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<java.version>1.8</java.version>
|
||||
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<solon.version>1.10.9</solon.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
<solon.version>1.10.13</solon.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -21,6 +21,12 @@
|
||||
<artifactId>solon-web</artifactId>
|
||||
<version>${solon.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon.logging</artifactId>
|
||||
<version>${solon.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证, 在线文档:https://sa-token.cc/ -->
|
||||
<dependency>
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
package com.pj;
|
||||
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import org.noear.solon.Solon;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* sa-token整合 solon 示例
|
||||
* @author noear
|
||||
*
|
||||
*/
|
||||
public class SaTokenDemoApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
Solon.start(SaTokenDemoApp.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
System.out.println("\n启动成功:Sa-Token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
import cn.dev33.satoken.log.SaLogForConsole;
|
||||
import cn.dev33.satoken.util.StrFormatter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 将 Sa-Token log 信息转接到 slf4j 接口
|
||||
*
|
||||
* @author noear 2022/11/14 created
|
||||
*/
|
||||
//@Component
|
||||
public class SaLogForSlf4j extends SaLogForConsole implements SaLog {
|
||||
static final Logger log = LoggerFactory.getLogger(SaLogForSlf4j.class);
|
||||
|
||||
/**
|
||||
* 打印日志到控制台
|
||||
*
|
||||
* @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()) {
|
||||
switch (level) {
|
||||
case trace:
|
||||
log.trace(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case debug:
|
||||
log.debug(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case info:
|
||||
log.info(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case warn:
|
||||
log.warn(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case error:
|
||||
case fatal:
|
||||
log.error(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.noear.solon.core.util.LogUtil;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
import cn.dev33.satoken.log.SaLogForConsole;
|
||||
import cn.dev33.satoken.util.StrFormatter;
|
||||
|
||||
/**
|
||||
* 将 Sa-Token log 信息转接到 Solon
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-11-2
|
||||
*/
|
||||
//@Component
|
||||
public class SaLogForSolon extends SaLogForConsole implements SaLog {
|
||||
|
||||
/**
|
||||
* 打印日志到控制台
|
||||
*
|
||||
* @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()) {
|
||||
switch (level) {
|
||||
case trace:
|
||||
LogUtil.global().trace(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case debug:
|
||||
LogUtil.global().debug(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case info:
|
||||
LogUtil.global().info(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case warn:
|
||||
LogUtil.global().warn(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
case error:
|
||||
case fatal:
|
||||
LogUtil.global().error(LOG_PREFIX + StrFormatter.format(str, args));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,13 @@
|
||||
package com.pj.test;
|
||||
|
||||
import cn.dev33.satoken.exception.*;
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
import cn.dev33.satoken.exception.*;
|
||||
|
||||
import org.noear.solon.annotation.Component;
|
||||
import org.noear.solon.core.event.EventListener;
|
||||
import org.noear.solon.core.handle.Context;
|
||||
import org.noear.solon.core.handle.Filter;
|
||||
import org.noear.solon.core.handle.FilterChain;
|
||||
|
||||
|
||||
/**
|
||||
@@ -14,13 +16,12 @@ import org.noear.solon.core.handle.Context;
|
||||
* @author noear
|
||||
*/
|
||||
@Component
|
||||
public class GlobalException implements EventListener<Throwable> {
|
||||
|
||||
public class GlobalExceptionFilter implements Filter {
|
||||
@Override
|
||||
public void onEvent(Throwable e) {
|
||||
Context c = Context.current();
|
||||
|
||||
if (c != null) {
|
||||
public void doFilter(Context ctx, FilterChain chain) throws Throwable {
|
||||
try {
|
||||
chain.doFilter(ctx);
|
||||
} catch (SaTokenException e) {
|
||||
// 不同异常返回不同状态码
|
||||
AjaxJson aj = null;
|
||||
if (e instanceof NotLoginException) { // 如果是未登录异常
|
||||
@@ -39,7 +40,7 @@ public class GlobalException implements EventListener<Throwable> {
|
||||
aj = AjaxJson.getError(e.getMessage());
|
||||
}
|
||||
|
||||
c.result = aj;
|
||||
ctx.render(aj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ sa-token:
|
||||
# token风格
|
||||
token-style: uuid
|
||||
# 是否输出操作日志
|
||||
is-log: false
|
||||
is-log: true
|
||||
|
||||
solon:
|
||||
# redis配置
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -40,7 +40,7 @@ public class SsoRequestUtil {
|
||||
/**
|
||||
* 单点注销地址
|
||||
*/
|
||||
public static String sloUrl = "http://sa-sso-server.com:9000/sso/logout";
|
||||
public static String sloUrl = "http://sa-sso-server.com:9000/sso/signout";
|
||||
|
||||
/**
|
||||
* 接口调用秘钥
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import cn.dev33.satoken.log.SaLog;
|
||||
|
||||
/**
|
||||
* 将 Sa-Token log 信息转接到 Slf4j
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-11-2
|
||||
*/
|
||||
//@Component
|
||||
public class SaLogForSlf4j implements SaLog {
|
||||
|
||||
Logger log = LoggerFactory.getLogger(SaLogForSlf4j.class);
|
||||
|
||||
@Override
|
||||
public void trace(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String str, Object... args) {
|
||||
log.debug(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String str, Object... args) {
|
||||
log.info(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fatal(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -42,8 +42,9 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
// 认证函数: 每次请求执行
|
||||
.setAuth(obj -> {
|
||||
// System.out.println("---------- sa全局认证 " + SaHolder.getRequest().getRequestPath());
|
||||
|
||||
// 输出 API 请求日志,方便调试代码
|
||||
// SaManager.getLog().debug("----- 请求path={} 提交token={}", SaHolder.getRequest().getRequestPath(), StpUtil.getTokenValue());
|
||||
|
||||
})
|
||||
|
||||
// 异常处理函数:每次认证函数发生异常时执行此函数
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
@@ -42,6 +43,7 @@ public class StpUserUtil {
|
||||
* 重置 StpLogic 对象
|
||||
* <br> 1、更改此账户的 StpLogic 对象
|
||||
* <br> 2、put 到全局 StpLogic 集合中
|
||||
* <br> 3、发送日志
|
||||
*
|
||||
* @param newStpLogic /
|
||||
*/
|
||||
@@ -52,6 +54,9 @@ public class StpUserUtil {
|
||||
// 添加到全局 StpLogic 集合中
|
||||
// 以便可以通过 SaManager.getStpLogic(type) 的方式来全局获取到这个 StpLogic
|
||||
SaManager.putStpLogic(newStpLogic);
|
||||
|
||||
// $$ 全局事件
|
||||
SaTokenEventCenter.doSetStpLogic(stpLogic);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
<!-- 定义 Sa-Token 版本号 -->
|
||||
<properties>
|
||||
<sa-token.version>1.32.0</sa-token.version>
|
||||
<sa-token.version>1.33.0</sa-token.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<description>Sa-Token Dependencies</description>
|
||||
|
||||
<properties>
|
||||
<revision>1.32.0</revision>
|
||||
<revision>1.33.0</revision>
|
||||
|
||||
<!-- 统一定义依赖版本号 -->
|
||||
<springboot.version>2.5.12</springboot.version>
|
||||
@@ -21,9 +21,8 @@
|
||||
<jackson-datatype-jsr310.version>2.11.2</jackson-datatype-jsr310.version>
|
||||
<servlet-api.version>3.1.0</servlet-api.version>
|
||||
<thymeleaf.version>3.0.9.RELEASE</thymeleaf.version>
|
||||
<solon.version>1.10.9</solon.version>
|
||||
<solon-test.version>1.9.1</solon-test.version>
|
||||
<noear-redisx.version>1.4.3</noear-redisx.version>
|
||||
<solon.version>1.10.13</solon.version>
|
||||
<noear-redisx.version>1.4.4</noear-redisx.version>
|
||||
<jfinal.version>4.9.17</jfinal.version>
|
||||
<jboot.version>3.14.4</jboot.version>
|
||||
<commons-pool2.version>2.5.0</commons-pool2.version>
|
||||
@@ -154,7 +153,7 @@
|
||||
<dependency>
|
||||
<groupId>org.noear</groupId>
|
||||
<artifactId>solon-test</artifactId>
|
||||
<version>${solon-test.version}</version>
|
||||
<version>${solon.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- redis pool -->
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://sa-token.cc/logo.png" width="150" height="150">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.32.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">Sa-Token v1.33.0</h1>
|
||||
<h5 align="center">一个轻量级 Java 权限认证框架,让鉴权变得简单、优雅!</h5>
|
||||
<p align="center" class="badge-box">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg?theme=gvp"></a>
|
||||
@@ -136,7 +136,7 @@ Sa-Token 目前主要五大功能模块:登录认证、权限认证、单点
|
||||
|
||||
|
||||
## 交流群
|
||||
QQ交流群:614714762 [点击加入](https://jq.qq.com/?_wv=1027&k=F96A2mrl)
|
||||
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
|
||||
|
||||
微信交流群:
|
||||
|
||||
|
||||
@@ -88,11 +88,13 @@
|
||||
- [推荐公众号](/more/tj-gzh)
|
||||
- [加入讨论群](/more/join-group)
|
||||
- [赞助 Sa-Token](/more/sa-token-donate)
|
||||
- [需求提交](/more/demand-commit)
|
||||
|
||||
- **附录**
|
||||
- [常见问题排查](/more/common-questions)
|
||||
- [框架名词解释](/more/noun-intro)
|
||||
- [Sa-Token功能结构图](/fun/auth-flow)
|
||||
- [全局 Log 输出](/fun/log)
|
||||
- [未登录场景值详解](/fun/not-login-scene)
|
||||
- [Token有效期详解](/fun/token-timeout)
|
||||
- [Session模型详解](/fun/session-model)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<div class="logo-box">
|
||||
<img src="logo.png" title="logo" />
|
||||
<h1 class="logo-text">Sa-Token</h1>
|
||||
<sub>v1.32.0</sub>
|
||||
<sub>v1.33.0</sub>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
@@ -26,37 +26,9 @@
|
||||
<div class="sear-box p-none" tabindex="-1" >
|
||||
<!-- 加载中…… -->
|
||||
</div>
|
||||
<div class="zk-box">
|
||||
<a class="wzi" href="javascript:;">
|
||||
<!-- <span>背景 </span> -->
|
||||
<img class="theme-btn" src="static/icon/theme.svg">
|
||||
<!-- <span class="zk-icon"></span> -->
|
||||
</a>
|
||||
<div class="zk-context theme-box">
|
||||
<div>
|
||||
<div style="height: 5px;"></div>
|
||||
<span style="background-color: #FFFFFF;"></span>
|
||||
<span style="background-color: #f5f5f5;"></span>
|
||||
<span style="background-color: #F1FAFA;"></span>
|
||||
<span style="background-color: #f5f5d5;"></span>
|
||||
<span style="background-color: #d5f5f5;"></span>
|
||||
|
||||
<span style="background-color: #f5e5f5;"></span>
|
||||
<span style="background-color: #E8E8FF;"></span>
|
||||
<span style="background-color: #f0f9eb;"></span>
|
||||
<span style="background-color: #ebe5dd;"></span>
|
||||
<span style="background-color: #e8f4ff;"></span>
|
||||
|
||||
<!-- <span style="background-color: #F0DAD2;"></span> -->
|
||||
<!-- <span style="background-color: #f5d5d5;"></span> -->
|
||||
<!-- <span style="background-color: #FFFFE0;"></span> -->
|
||||
<!-- <span style="background-color: #eeeeee;"></span> -->
|
||||
<!-- <span style="background-color: #f5fafe;"></span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<select class="select-version p-none" onchange="location.href=this.value">
|
||||
<option value="doc.html">最新版</option>
|
||||
<option value="v/v1.32.0/doc.html">v1.32.0</option>
|
||||
<option value="v/v1.31.0/doc.html">v1.31.0</option>
|
||||
<option value="v/v1.30.0/doc/index.html">v1.30.0</option>
|
||||
<option value="v/v1.29.0/doc/index.html">v1.29.0</option>
|
||||
@@ -92,10 +64,40 @@
|
||||
<option value="v/v1.0.0/doc/index.html">v1.0.0</option>
|
||||
<option value="/">首页</option>
|
||||
</select>
|
||||
<div class="zk-box p-none">
|
||||
<a class="wzi" href="javascript:;">
|
||||
<!-- <span>背景 </span> -->
|
||||
<img class="theme-btn" src="static/icon/theme.svg">
|
||||
<!-- <span class="zk-icon"></span> -->
|
||||
</a>
|
||||
<div class="zk-context theme-box">
|
||||
<div>
|
||||
<div style="height: 5px;"></div>
|
||||
<span style="background-color: #FFFFFF;"></span>
|
||||
<span style="background-color: #f5f5f5;"></span>
|
||||
<span style="background-color: #F1FAFA;"></span>
|
||||
<span style="background-color: #f5f5d5;"></span>
|
||||
<span style="background-color: #d5f5f5;"></span>
|
||||
|
||||
<span style="background-color: #f5e5f5;"></span>
|
||||
<span style="background-color: #E8E8FF;"></span>
|
||||
<span style="background-color: #f0f9eb;"></span>
|
||||
<span style="background-color: #ebe5dd;"></span>
|
||||
<span style="background-color: #e8f4ff;"></span>
|
||||
|
||||
<!-- <span style="background-color: #F0DAD2;"></span> -->
|
||||
<!-- <span style="background-color: #f5d5d5;"></span> -->
|
||||
<!-- <span style="background-color: #FFFFE0;"></span> -->
|
||||
<!-- <span style="background-color: #eeeeee;"></span> -->
|
||||
<!-- <span style="background-color: #f5fafe;"></span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="wzi" href="index.html">首页</a>
|
||||
<a class="wzi" href="doc.html">文档</a>
|
||||
<a class="p-none wzi" href="#/more/link">案例</a>
|
||||
<a class="p-none wzi" href="#/more/blog">博客</a>
|
||||
<a class="p-none wzi" href="#/more/demand-commit">需求提交</a>
|
||||
<!-- <a class="p-none wzi" href="#/more/blog">博客</a> -->
|
||||
<a class="p-none wzi" href="#/more/sa-token-donate">赞助</a>
|
||||
<a class="p-none wzi" href="#/sso/sso-pro">🔥 SSO商业版</a>
|
||||
<div class="zk-box">
|
||||
@@ -109,11 +111,12 @@
|
||||
<a href="#/more/update-log">更新日志</a>
|
||||
<a href="#/more/common-questions">常见报错</a>
|
||||
<a href="#/more/tj-gzh">推荐公众号</a>
|
||||
<a href="#/more/blog">相关博客</a>
|
||||
<div class="zk-fengexian"></div>
|
||||
<!-- <a href="http://sa-app.dev33.cn/wall.html?name=sa-token" target="_blank">需求墙</a> -->
|
||||
<a href="#/fun/sa-token-test">在线考试</a>
|
||||
<a href="#/fun/issue-template">在线提问</a>
|
||||
<a href="https://wj.qq.com/s2/10852322/0d8b/" target="_blank">需求提交</a>
|
||||
<!-- <a href="https://wj.qq.com/s2/10852322/0d8b/" target="_blank">需求提交</a> -->
|
||||
<a href="https://wj.qq.com/s2/8475114/2f6a/" target="_blank">问卷调查</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -147,7 +150,7 @@
|
||||
<!-- -->
|
||||
<script src="./static/docsify-plugin.js"></script>
|
||||
<script>
|
||||
var saTokenTopVersion = '1.32.0'; // Sa-Token最新版本
|
||||
var saTokenTopVersion = '1.33.0'; // Sa-Token最新版本
|
||||
var name = '<img style="width: 60px; height: 60px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
|
||||
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v' + saTokenTopVersion + '</sub>';
|
||||
window.$docsify = {
|
||||
|
||||
@@ -53,39 +53,176 @@ SaToken 中的所有异常都是继承于 `SaTokenException` 的,也就是说
|
||||
|
||||
### 异常细分状态码-参照表
|
||||
|
||||
!> 目前仅对 sso 插件和 jwt 插件做了异常状态码细分,后续版本升级会支持更多模块
|
||||
!> 部分插件因异常抛出点较少,暂未做状态码细分处理
|
||||
|
||||
**sa-token-code 核心包:**
|
||||
#### sa-token-code 核心包
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| -1 | 代表这个异常在抛出时未指定异常细分状态码 |
|
||||
| 10001 | 未能获取有效的上下文处理器 |
|
||||
| 10002 | 未能获取有效的上下文 |
|
||||
| 10003 | JSON 转换器未实现 |
|
||||
| 10011 | 未能从全局 StpLogic 集合中找到对应 type 的 StpLogic |
|
||||
| 10021 | 指定的配置文件加载失败 |
|
||||
| 10022 | 配置文件属性无法正常读取 |
|
||||
| 10031 | 重置的侦听器集合不可以为空 |
|
||||
| 10032 | 注册的侦听器不可以为空 |
|
||||
| 10301 | 提供的 Same-Token 是无效的 |
|
||||
| 10311 | 表示未能通过 Http Basic 认证校验 |
|
||||
| 10321 | 提供的 HttpMethod 是无效的 |
|
||||
| 11001 | 未能读取到有效Token |
|
||||
| 11002 | 登录时的账号id值为空 |
|
||||
| 11003 | 更改 Token 指向的 账号Id 时,账号Id值为空 |
|
||||
| 11011 | 未能读取到有效Token |
|
||||
| 11012 | Token无效 |
|
||||
| 11013 | Token已过期 |
|
||||
| 11014 | Token已被顶下线 |
|
||||
| 11015 | Token已被踢下线 |
|
||||
| 11016 | Token已临时过期 |
|
||||
| 11031 | 在未集成 sa-token-jwt 插件时调用 getExtra() 抛出异常 |
|
||||
| 11041 | 缺少指定的角色 |
|
||||
| 11051 | 缺少指定的权限 |
|
||||
| 11061 | 当前账号未通过服务封禁校验 |
|
||||
| 11062 | 提供要解禁的账号无效 |
|
||||
| 11063 | 提供要解禁的服务无效 |
|
||||
| 11064 | 提供要解禁的等级无效 |
|
||||
| 11071 | 二级认证校验未通过 |
|
||||
| 12001 | 请求中缺少指定的参数 |
|
||||
| 12002 | 构建 Cookie 时缺少 name 参数 |
|
||||
| 12003 | 构建 Cookie 时缺少 value 参数 |
|
||||
| 12101 | Base64 编码异常 |
|
||||
| 12102 | Base64 解码异常 |
|
||||
| 12103 | URL 编码异常 |
|
||||
| 12104 | URL 解码异常 |
|
||||
| 12111 | md5 加密异常 |
|
||||
| 12112 | sha1 加密异常 |
|
||||
| 12113 | sha256 加密异常 |
|
||||
| 12114 | AES 加密异常 |
|
||||
| 12115 | AES 解密异常 |
|
||||
| 12116 | RSA 公钥加密异常 |
|
||||
| 12117 | RSA 私钥加密异常 |
|
||||
| 12118 | RSA 公钥解密异常 |
|
||||
| 12119 | RSA 私钥解密异常 |
|
||||
|
||||
|
||||
**sa-token-sso 单点登录相关:**
|
||||
#### sa-token-servlet
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 20001 | `redirect` 重定向 url 是一个无效地址 |
|
||||
| 20002 | `redirect` 重定向 url 不在 allowUrl 允许的范围内 |
|
||||
| 20003 | 接口调用方提供的 `secretkey` 秘钥无效 |
|
||||
| 20004 | 提供的 `ticket` 是无效的 |
|
||||
| 20005 | 在模式三下,sso-client 调用 sso-server 端 校验ticket接口 时,得到的响应是校验失败 |
|
||||
| 20006 | 在模式三下,sso-client 调用 sso-server 端 单点注销接口 时,得到的响应是注销失败 |
|
||||
| 20007 | http 请求调用 提供的 `timestamp` 与当前时间的差距超出允许的范围 |
|
||||
| 20008 | http 请求调用 提供的 `sign` 无效 |
|
||||
| 20009 | 本地系统没有配置 `secretkey` 字段 |
|
||||
| 20001 | 转发失败 |
|
||||
| 20002 | 重定向失败 |
|
||||
|
||||
|
||||
|
||||
**sa-token-jwt 插件相关:**
|
||||
#### sa-token-spring-boot-starter
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 40101 | 对 jwt 字符串解析失败 |
|
||||
| 40102 | 此 jwt 的签名无效 |
|
||||
| 40103 | 此 jwt 的 `loginType` 字段不符合预期 |
|
||||
| 40104 | 此 jwt 已超时 |
|
||||
| 20101 | 企图在非 Web 上下文获取 Request、Response 等对象 |
|
||||
| 20103 | 对象转 JSON 字符串失败 |
|
||||
| 20104 | JSON 字符串转 Map 失败 |
|
||||
| 20105 | 默认的 Filter 异常处理函数 |
|
||||
|
||||
|
||||
#### sa-token-reactor-spring-boot-starter
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 20203 | 对象转 JSON 字符串失败 |
|
||||
| 20204 | JSON 字符串转 Map 失败 |
|
||||
| 20205 | 默认的 Filter 异常处理函数 |
|
||||
|
||||
|
||||
#### sa-token-solon-plugin
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 20301 | 默认的拦截器异常处理函数 |
|
||||
| 20302 | 默认的 Filter 异常处理函数 |
|
||||
|
||||
|
||||
#### sa-token-sso 单点登录相关:
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 30001 | `redirect` 重定向 url 是一个无效地址 |
|
||||
| 30002 | `redirect` 重定向 url 不在 allowUrl 允许的范围内 |
|
||||
| 30003 | 接口调用方提供的 `secretkey` 秘钥无效 |
|
||||
| 30004 | 提供的 `ticket` 是无效的 |
|
||||
| 30005 | 在模式三下,sso-client 调用 sso-server 端 校验ticket接口 时,得到的响应是校验失败 |
|
||||
| 30006 | 在模式三下,sso-client 调用 sso-server 端 单点注销接口 时,得到的响应是注销失败 |
|
||||
| 30007 | http 请求调用 提供的 `timestamp` 与当前时间的差距超出允许的范围 |
|
||||
| 30008 | http 请求调用 提供的 `sign` 无效 |
|
||||
| 30009 | 本地系统没有配置 `secretkey` 字段 |
|
||||
| 30010 | 本地系统没有配置 http 请求处理器 |
|
||||
|
||||
|
||||
#### sa-token-oauth2 相关:
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 30101 | client_id 不可为空 |
|
||||
| 30102 | scope 不可为空 |
|
||||
| 30103 | redirect_uri 不可为空 |
|
||||
| 30104 | LoginId 不可为空 |
|
||||
| 30105 | 无效client_id |
|
||||
| 30106 | 无效access_token |
|
||||
| 30107 | 无效 client_token |
|
||||
| 30108 | Access-Token 不具备指定的 Scope |
|
||||
| 30109 | Client-Token 不具备指定的 Scope |
|
||||
| 30110 | 无效 code 码 |
|
||||
| 30111 | 无效 Refresh-Token |
|
||||
| 30112 | 请求的Scope暂未签约 |
|
||||
| 30113 | 无效redirect_url |
|
||||
| 30114 | 非法redirect_url |
|
||||
| 30115 | 无效client_secret |
|
||||
| 30116 | 请求的Scope暂未签约 |
|
||||
| 30117 | 无效code |
|
||||
| 30118 | 无效client_id |
|
||||
| 30119 | 无效client_secret |
|
||||
| 30120 | 无效redirect_uri |
|
||||
| 30121 | 无效refresh_token |
|
||||
| 30122 | 无效client_id |
|
||||
| 30123 | 无效client_secret |
|
||||
| 30124 | 无效client_id |
|
||||
| 30125 | 无效response_type |
|
||||
| 30131 | 暂未开放授权码模式 |
|
||||
| 30132 | 暂未开放隐藏式模式 |
|
||||
| 30133 | 暂未开放密码式模式 |
|
||||
| 30134 | 暂未开放凭证式模式 |
|
||||
|
||||
|
||||
#### sa-token-jwt 插件相关:
|
||||
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 30201 | 对 jwt 字符串解析失败 |
|
||||
| 30202 | 此 jwt 的签名无效 |
|
||||
| 30203 | 此 jwt 的 `loginType` 字段不符合预期 |
|
||||
| 30204 | 此 jwt 已超时 |
|
||||
| 30205 | 没有配置jwt秘钥 |
|
||||
| 30206 | 登录时提供的账号id为空 |
|
||||
|
||||
|
||||
#### sa-token-temp-jwt 插件相关:
|
||||
| code码值 | 含义 |
|
||||
| :-------- | :-------- |
|
||||
| 30301 | jwt 模式没有提供秘钥 |
|
||||
| 30302 | jwt 模式不可以删除 Token |
|
||||
| 30303 | Token已超时 |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
+ 得出以下结果:
|
||||
|
||||
+ 和文档上描述的不一致:
|
||||
+ 其中第 xx 行的代码输出表现 和文档上描述的不一致:
|
||||
|
||||
+ 我的理解是:
|
||||
|
||||
|
||||
89
sa-token-doc/fun/log.md
Normal file
89
sa-token-doc/fun/log.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# 参考:全局 Log 输出
|
||||
|
||||
---
|
||||
|
||||
### 打开全局日志输出
|
||||
|
||||
以下配置可以打开全局日志输出:
|
||||
|
||||
<!---------------------------- tabs:start ---------------------------->
|
||||
|
||||
<!------------- tab:yaml 风格 ------------->
|
||||
``` yaml
|
||||
sa-token:
|
||||
# 是否输出操作日志
|
||||
is-log: true
|
||||
```
|
||||
|
||||
<!------------- tab:properties 风格 ------------->
|
||||
``` properties
|
||||
# 是否输出操作日志
|
||||
sa-token.is-log=true
|
||||
```
|
||||
<!---------------------------- tabs:end ---------------------------->
|
||||
|
||||
|
||||
此配置项打开之后,框架将会在账号登录、注销、二级认证 等关键性步骤打印日志,以方便项目开发调试。
|
||||
|
||||
框架默认将日志信息打印到控制台,如果需要将日志输出到其它地方,你可以重写 SaLog 对象,例如以下代码将会把日志转接到 Slf4j 下:
|
||||
|
||||
``` java
|
||||
/**
|
||||
* 将 Sa-Token log 信息转接到 Slf4j
|
||||
*/
|
||||
@Component
|
||||
public class SaLogForSlf4j implements SaLog {
|
||||
Logger log = LoggerFactory.getLogger(SaLogForSlf4j.class);
|
||||
|
||||
@Override
|
||||
public void trace(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
@Override
|
||||
public void debug(String str, Object... args) {
|
||||
log.debug(str, args);
|
||||
}
|
||||
@Override
|
||||
public void info(String str, Object... args) {
|
||||
log.info(str, args);
|
||||
}
|
||||
@Override
|
||||
public void warn(String str, Object... args) {
|
||||
log.trace(str, args);
|
||||
}
|
||||
@Override
|
||||
public void error(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
@Override
|
||||
public void fatal(String str, Object... args) {
|
||||
log.error(str, args);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
重新启动项目,观察日志打印变化。
|
||||
|
||||
### 增加API访问日志
|
||||
|
||||
手动增加 API 请求日志信息,这将非常有助于你调试代码,例如:
|
||||
|
||||
``` java
|
||||
@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全局异常 ");
|
||||
return SaResult.error(e.getMessage());
|
||||
})
|
||||
;
|
||||
}
|
||||
```
|
||||
@@ -27,10 +27,40 @@
|
||||
</a>
|
||||
</div>
|
||||
<nav class="nav-right">
|
||||
<div class="zk-box p-none">
|
||||
<a class="wzi" href="javascript:;">
|
||||
<!-- <span>背景 </span> -->
|
||||
<img class="theme-btn" src="static/icon/theme.svg">
|
||||
<!-- <span class="zk-icon"></span> -->
|
||||
</a>
|
||||
<div class="zk-context theme-box">
|
||||
<div>
|
||||
<div style="height: 5px;"></div>
|
||||
<span style="background-color: #FFFFFF;"></span>
|
||||
<span style="background-color: #f5f5f5;"></span>
|
||||
<span style="background-color: #F1FAFA;"></span>
|
||||
<span style="background-color: #f5f5d5;"></span>
|
||||
<span style="background-color: #d5f5f5;"></span>
|
||||
|
||||
<span style="background-color: #f5e5f5;"></span>
|
||||
<span style="background-color: #E8E8FF;"></span>
|
||||
<span style="background-color: #f0f9eb;"></span>
|
||||
<span style="background-color: #ebe5dd;"></span>
|
||||
<span style="background-color: #e8f4ff;"></span>
|
||||
|
||||
<!-- <span style="background-color: #F0DAD2;"></span> -->
|
||||
<!-- <span style="background-color: #f5d5d5;"></span> -->
|
||||
<!-- <span style="background-color: #FFFFE0;"></span> -->
|
||||
<!-- <span style="background-color: #eeeeee;"></span> -->
|
||||
<!-- <span style="background-color: #f5fafe;"></span> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="wzi" href="index.html">首页</a>
|
||||
<a class="wzi" href="doc.html">文档</a>
|
||||
<a class="p-none wzi" href="doc.html#/more/link">案例</a>
|
||||
<a class="p-none wzi" href="doc.html#/more/blog">博客</a>
|
||||
<a class="p-none wzi" href="doc.html#/more/demand-commit">需求提交</a>
|
||||
<!-- <a class="p-none wzi" href="doc.html#/more/blog">博客</a> -->
|
||||
<a class="p-none wzi" href="doc.html#/more/sa-token-donate">赞助</a>
|
||||
<a class="p-none wzi" href="doc.html#/sso/sso-pro">🔥 SSO商业版</a>
|
||||
<div class="zk-box">
|
||||
@@ -44,11 +74,12 @@
|
||||
<a href="doc.html#/more/update-log">更新日志</a>
|
||||
<a href="doc.html#/more/common-questions">常见报错</a>
|
||||
<a href="doc.html#/more/tj-gzh">推荐公众号</a>
|
||||
<a href="doc.html#/more/blog">相关博客</a>
|
||||
<div class="zk-fengexian"></div>
|
||||
<!-- <a href="http://sa-app.dev33.cn/wall.html?name=sa-token" target="_blank">需求墙</a> -->
|
||||
<a href="doc.html#/fun/sa-token-test">在线考试</a>
|
||||
<a href="doc.html#/fun/issue-template">在线提问</a>
|
||||
<a href="https://wj.qq.com/s2/10852322/0d8b/" target="_blank">需求提交</a>
|
||||
<!-- <a href="https://wj.qq.com/s2/10852322/0d8b/" target="_blank">需求提交</a> -->
|
||||
<a href="https://wj.qq.com/s2/8475114/2f6a/" target="_blank">问卷调查</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,7 +102,7 @@
|
||||
<div class="main-box">
|
||||
<div class="content-box">
|
||||
<!-- <div class="fenge"></div> -->
|
||||
<h1>Sa-Token<small>v1.32.0</small></h1>
|
||||
<h1>Sa-Token<small>v1.33.0</small></h1>
|
||||
<div class="sub-title">一个轻量级 java 权限认证框架,让鉴权变得简单、优雅!</div>
|
||||
<div class="btn-box">
|
||||
<a class="abtn" href="https://github.com/dromara/sa-token" target="_blank">GitHub</a>
|
||||
@@ -148,7 +179,7 @@
|
||||
<div class="s-fenge"></div>
|
||||
<h2 class="s-title">优秀开源集成案例</h2>
|
||||
<div class="feature-box s-case-box">
|
||||
<!-- SpringBoot_v2 4.8k -->
|
||||
<!-- SpringBoot_v2 5.1k -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/bdj/SpringBoot_v2" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--springboot_v2.png">
|
||||
@@ -157,7 +188,7 @@
|
||||
<span class="s-author">开源oschina</span>
|
||||
<p class="s-case-intro">努力打造 springboot 框架的极致细腻的脚手架,原生纯净。</p>
|
||||
</div>
|
||||
<!-- Snowy 3.7k -->
|
||||
<!-- Snowy 4.2k -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/xiaonuobase/snowy" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--snowy.png">
|
||||
@@ -166,7 +197,7 @@
|
||||
<span class="s-author"> 小诺开源技术 </span>
|
||||
<p class="s-case-intro">国内首个国密前后分离快速开发平台,基于Vue3、Antdv、SaToken</p>
|
||||
</div>
|
||||
<!-- RuoYi-Vue-Plus 2.4k -->
|
||||
<!-- RuoYi-Vue-Plus 3.3k -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/JavaLionLi/RuoYi-Vue-Plus" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--ruoyi-vue-plus.png">
|
||||
@@ -175,25 +206,7 @@
|
||||
<span class="s-author"> 疯狂的狮子Li </span>
|
||||
<p class="s-case-intro">重写 RuoYi-Vue 所有功能,集成 Sa-Token、Mybatis-Plus、Hutool 定期同步</p>
|
||||
</div>
|
||||
<!-- Sa-Plus 875 -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/click33/sa-plus" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--sa-plus.png">
|
||||
</a>
|
||||
<h3 class="s-case-title">Sa-Plus</h3>
|
||||
<span class="s-author"> 孔明 </span>
|
||||
<p class="s-case-intro">一个基于 SpringBoot 的快速开发框架,内置代码生成器</p>
|
||||
</div>
|
||||
<!-- EasyAdmin 628 -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/lakernote/easy-admin" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--easy-admin.png">
|
||||
</a>
|
||||
<h3 class="s-case-title">EasyAdmin</h3>
|
||||
<span class="s-author"> laker </span>
|
||||
<p class="s-case-intro">轻量级的后台管理系统脚手架,内置代码生成器、权限管理、工作流引擎等</p>
|
||||
</div>
|
||||
<!-- RuoYi-Cloud-Plus 475 -->
|
||||
<!-- RuoYi-Cloud-Plus 990 -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/JavaLionLi/RuoYi-Cloud-Plus" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--ruoyi-cloud-plus.png">
|
||||
@@ -202,7 +215,25 @@
|
||||
<span class="s-author"> 疯狂的狮子Li </span>
|
||||
<p class="s-case-intro">重写 RuoYi-Cloud 所有功能 整合 SpringCloudAlibaba、Dubbo3.0、Sa-Token</p>
|
||||
</div>
|
||||
<!-- dcy-fast 315 -->
|
||||
<!-- Sa-Plus 960 -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/click33/sa-plus" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--sa-plus.png">
|
||||
</a>
|
||||
<h3 class="s-case-title">Sa-Plus</h3>
|
||||
<span class="s-author"> 孔明 </span>
|
||||
<p class="s-case-intro">一个基于 SpringBoot 的快速开发框架,内置代码生成器</p>
|
||||
</div>
|
||||
<!-- EasyAdmin 785 -->
|
||||
<div class="s-case">
|
||||
<a href="https://gitee.com/lakernote/easy-admin" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--easy-admin.png">
|
||||
</a>
|
||||
<h3 class="s-case-title">EasyAdmin</h3>
|
||||
<span class="s-author"> laker </span>
|
||||
<p class="s-case-intro">轻量级的后台管理系统脚手架,内置代码生成器、权限管理、工作流引擎等</p>
|
||||
</div>
|
||||
<!-- dcy-fast 343 -->
|
||||
<!-- <div class="s-case">
|
||||
<a href="https://gitee.com/dcy421/dcy-fast" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--dcy-fast.png">
|
||||
@@ -211,7 +242,7 @@
|
||||
<span class="s-author"> 青年 </span>
|
||||
<p class="s-case-intro">一个基于 SpringBoot + Sa-Token + Mybatis-Plus 的后台管理系统</p>
|
||||
</div> -->
|
||||
<!-- fhs 543 -->
|
||||
<!-- fhs 585 -->
|
||||
<!-- <div class="s-case">
|
||||
<a href="https://gitee.com/fhs-opensource/fhs-framework" target="_blank" class="s-case-link">
|
||||
<img src="https://oss.dev33.cn/sa-token/case/case--fhs.png">
|
||||
@@ -420,7 +451,7 @@
|
||||
<a href="https://www.herodotus.cn/" target="_blank">
|
||||
<img src="https://oss.dev33.cn/sa-token/link/dante-cloud2.png" msg="Dante-Cloud 是一款企业级微服务架构和服务能力开发平台。">
|
||||
</a>
|
||||
<a href="http://www.mtruning.club:81/" target="_blank">
|
||||
<a href="http://www.mtruning.club" target="_blank">
|
||||
<img src="https://oss.dev33.cn/sa-token/link/go-view.png" msg="低代码数据可视化开发平台">
|
||||
</a>
|
||||
<a href="https://dromara.org/zh/projects/" target="_blank">
|
||||
@@ -533,7 +564,7 @@
|
||||
</style>
|
||||
<div class="foot-box" id="foot">
|
||||
<div class="s-width" style="text-align: center;">
|
||||
Copyright ©2022 Sa-Token java权限认证 | sa-token.cc | <a href="https://beian.miit.gov.cn/" target="_blank">鲁ICP备18046274号-2</a>
|
||||
Copyright ©2022 Sa-Token java权限认证 | sa-token.cc | <a href="https://beian.miit.gov.cn/" target="_blank">鲁ICP备18046274号-4</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -612,45 +643,66 @@
|
||||
});
|
||||
})
|
||||
|
||||
// set 一下 img 的宽度
|
||||
function setImgWidth(img) {
|
||||
// 如果已经有了宽度参数,则不追加
|
||||
if(img.src.indexOf('?') > -1) {
|
||||
return;
|
||||
}
|
||||
// console.log(img.getAttribute('nf'));
|
||||
if(img.getAttribute('nf') != null) {
|
||||
return;
|
||||
}
|
||||
// 如果不是oss上的图片
|
||||
if(img.src.indexOf('https://oss.dev33.cn') == -1 || img.src.endsWith('.svg')) {
|
||||
return;
|
||||
}
|
||||
img.src = img.src + "?x-oss-process=image/resize,m_lfit,w_" + (img.width) + ",limit_0/auto-orient,0";
|
||||
</script>
|
||||
|
||||
<!-- 修改背景颜色 -->
|
||||
<script>
|
||||
|
||||
// 绑定修改背景色的按钮事件
|
||||
$('.theme-box span').click(function() {
|
||||
let bgColor = this.style.backgroundColor;
|
||||
setBg(bgColor);
|
||||
localStorage.setItem('bg-color-value', bgColor)
|
||||
})
|
||||
// 读取上次记录
|
||||
let bgColor = localStorage.getItem('bg-color-value');
|
||||
if(bgColor) {
|
||||
setBg(bgColor);
|
||||
}
|
||||
|
||||
// set 一遍 img 的尺寸,防止失真
|
||||
function f5ImgSize() {
|
||||
$('.com-box-f .com-box a img').each(function() {
|
||||
// console.log(this.src, this.width);
|
||||
// 未加载完毕时,则等待其load之后再设置
|
||||
if(this.complete == false) {
|
||||
this.onload = function() {
|
||||
setImgWidth(this);
|
||||
}
|
||||
return;
|
||||
// 设置背景颜色
|
||||
function setBg(bgColor) {
|
||||
console.log('---- 背景颜色设定为:', bgColor);
|
||||
|
||||
// -------- 设置 body 背景
|
||||
document.body.style.backgroundColor = bgColor;
|
||||
|
||||
// -------- 设置 header 头背景
|
||||
// 如果是 16 进制,转 rgba
|
||||
if(bgColor.indexOf('#') == 0) {
|
||||
bgColor = hexToRgba(bgColor, 0.97);
|
||||
}
|
||||
// 如果是 rgb,转 rgba
|
||||
else if(bgColor.match(/\,/g).length == 2) {
|
||||
bgColor = bgColor.replace(')', ' ,0.97)');
|
||||
}
|
||||
|
||||
document.querySelector('.doc-header').style.backgroundColor = bgColor;
|
||||
}
|
||||
|
||||
// 16进制 转 rgba
|
||||
function hexToRgba(str, a){
|
||||
a = a || 1;
|
||||
|
||||
var reg = /^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/
|
||||
if(!reg.test(str)){return;}
|
||||
let newStr = (str.toLowerCase()).replace(/\#/g,'')
|
||||
let len = newStr.length;
|
||||
if(len == 3){
|
||||
let t = ''
|
||||
for(var i=0;i<len;i++){
|
||||
t += newStr.slice(i,i+1).concat(newStr.slice(i,i+1))
|
||||
}
|
||||
// 追加宽度参数
|
||||
setImgWidth(this);
|
||||
})
|
||||
}
|
||||
if(window.innerWidth > 1800) {
|
||||
if(navigator.userAgent.indexOf('WebKit') > -1) {
|
||||
// f5ImgSize();
|
||||
newStr = t
|
||||
}
|
||||
let arr = []; //将字符串分隔,两个两个的分隔
|
||||
for(var i =0;i<6;i=i+2){
|
||||
let s = newStr.slice(i,i+2)
|
||||
arr.push(parseInt("0x" + s))
|
||||
}
|
||||
return 'rgb(' + arr.join(",") + ', ' + a + ')';
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
@@ -74,15 +74,6 @@
|
||||
- 可能1:这个账号被 `StpUtil.kickout(loginId)` 方法强制踢下线了。
|
||||
|
||||
|
||||
### Q:集成 Redis 后,明明 Redis 中有值,却还是提示无效Token?
|
||||
根据以往的处理经验,发生这种情况 90% 的概率是因为你找错了Redis,即:代码连接的Redis和你用管理工具看到的Redis并不是同一个。
|
||||
|
||||
你可能会问:我看配置文件明明是同一个啊?
|
||||
|
||||
我的回答是:别光看配置文件,不一定准确,在启动时直接执行 `SaManager.getSaTokenDao().set("name", "value", 100000);`,
|
||||
随便写入一个值,看看能不能根据你的预期写进这个Redis,如果能的话才能证明`代码连接的Reids` 和`你用管理工具看到的Redis` 是同一个,再进行下一步排查。
|
||||
|
||||
|
||||
### Q:加了注解进行鉴权认证,不生效?
|
||||
1. 注解鉴权功能默认关闭,两种方式任选其一进行打开:注册注解拦截器、集成AOP模块,参考:[注解式鉴权](/use/at-check)
|
||||
2. 在Spring环境中, 如果同时配置了`WebMvcConfigurer`和`WebMvcConfigurationSupport`时, 也会导致拦截器失效.
|
||||
@@ -91,6 +82,7 @@
|
||||
3. 如果以上步骤处理后仍然没有效果,加群说明一下复现步骤
|
||||
|
||||
|
||||
|
||||
### Q:我加了拦截器鉴权,但是好像没有什么效果,请求没有被拦截住?
|
||||
- 可能1:这个拦截器可能没有注册成功。
|
||||
- 可能2:你访问的请求没有进入这个拦截器。
|
||||
@@ -105,7 +97,7 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
System.out.println("--------- flag 1");
|
||||
registry.addInterceptor(new SaInterceptor(handle -> {
|
||||
System.out.println("--------- flag 2");
|
||||
System.out.println("--------- flag 2,请求进入了拦截器,访问的 path 是:" + SaHolder.getRequest().getRequestPath());
|
||||
StpUtil.checkLogin(); // 登录校验,只有会话登录后才能通过这句代码
|
||||
}))
|
||||
.addPathPatterns("/user/**")
|
||||
@@ -117,15 +109,18 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
在启动时 `flag 1` 被打印出来,才证明拦截器注册成功了,在访问请求时 `flag 2` 被打印出来,才证明请求进入了拦截器。
|
||||
|
||||
如果拦截器没有注册成功,则:
|
||||
- 可能1:SpringBoot 版本较高(`>= 2.6.0`),请尝试在启动类加上 `@EnableWebMvc` 注解再重新启动。
|
||||
- 可能2:`SaTokenConfigure` 配置类不在启动类的同包或者子包下,导致没有被 SpringBoot 扫描到。
|
||||
- 可能3:`SaTokenConfigure` 配置类在启动类的同包或者子包下,但启动类上加了 `@ComponentScan("com.xxx")` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。
|
||||
- 可能4:项目属于 Maven 多模块项目,`SaTokenConfigure` 和启动类没有在一个模块,且启动类模块没有引入配置类的模块,导致加载不到。
|
||||
<!-- - 可能1:SpringBoot 版本较高(`>= 2.6.0`),请尝试在启动类加上 `@EnableWebMvc` 注解再重新启动。 -->
|
||||
- 可能1:`SaTokenConfigure` 配置类不在启动类的同包或者子包下,导致没有被 SpringBoot 扫描到。
|
||||
- 可能2:你的项目启动类上加了 `@ComponentScan("com.xxx")` 注解,导致包扫描范围不正确,请将此注解删除或移动到其它配置类上。
|
||||
- 可能3:项目属于 Maven 多模块项目,`SaTokenConfigure` 和启动类没有在一个模块,且启动类模块没有引入配置类的模块,导致加载不到。
|
||||
|
||||
如果拦截器已经注册成功,但请求没有进入拦截器:
|
||||
- 可能1:你访问的 path,没有被 `.addPathPatterns("/user/**")` 拦截住。
|
||||
- 可能2:你访问的 path,被 `.excludePathPatterns("/xxx/xx")` 排除掉了。
|
||||
- 可能3:你访问的是另一个项目,请把当前项目停掉,看看你的请求还能不能访问成功。
|
||||
- 可能1:你访问的 path,没有被 `.addPathPatterns("/user/**")` 拦截住,或者被 `.excludePathPatterns("/xxx/xx")` 排除掉了。
|
||||
- 可能2:你访问的是另一个项目,请把当前项目停掉,看看你的请求还能不能访问成功。
|
||||
|
||||
如果请求进入拦截器也成功了,那可能是:
|
||||
- 可能1:前端访问时提交了会话 Token,且这个 Token 是有效的,通过了拦截器的代码校验。
|
||||
- 可能2:你访问的 path,和你预期不符,仔细观察一下打印出来的 path 信息,和你的预期相符吗。
|
||||
|
||||
注:以上的排查步骤,对过滤器不生效的情形一样适用。
|
||||
|
||||
@@ -133,17 +128,60 @@ public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
### Q:我使用拦截器鉴权时,明明排除了某个路径却仍然被拦截了?
|
||||
- 可能1:你的项目可能是跨域了,先把跨域问题解决掉,参考:[解决跨域问题](/fun/cors-filter)
|
||||
- 可能2:你访问的接口可能是404了,SpringBoot环境下如果访问接口404后,会被转发到`/error`,然后被再次拦截。请确保你访问的 path 有对应的 Controller 承接!
|
||||
- 可能3:可能这里并没有拦截,但是又被其他地方拦截了。请先把这个拦截器给注释掉,看看还会不会拦截,如果依然拦截,那说明不是这个拦截器的锅,请仔细查看一下控制台抛出的堆栈信息,定位一下到底是哪行代码拦截住这个请求的。
|
||||
- 可能4:后端拦截的 path 未必是你前端访问的这个path,建议先打印一下 path 信息,看看和你预想的是否一致,再做分析。
|
||||
- 可能5:你写了多个匹配规则,请求只越过了第一个规则,被其它规则拦下了,例如以下代码:
|
||||
- 可能3:可能拦截器这里并没有拦截,但是又被其他地方拦截了。请先把这个拦截器给注释掉,看看还会不会拦截,如果依然拦截,那说明不是这个拦截器的锅,请仔细查看一下控制台抛出的堆栈信息,定位一下到底是哪行代码拦截住这个请求的。
|
||||
- 可能4:后端拦截的 path 未必是你前端访问的这个path(特别是经过网关转发后的path可能会有变化),建议先打印一下 path 信息,看看和你预想的是否一致,再做分析。
|
||||
``` java
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new SaInterceptor(handle -> {
|
||||
try {
|
||||
System.out.println("-------- 前端访问path:" + SaHolder.getRequest().getRequestPath());
|
||||
StpUtil.checkLogin();
|
||||
System.out.println("-------- 此 path 校验成功:" + SaHolder.getRequest().getRequestPath());
|
||||
} catch (Exception e) {
|
||||
System.out.println("-------- 此 path 校验失败:" + SaHolder.getRequest().getRequestPath());
|
||||
throw e;
|
||||
}
|
||||
})).addPathPatterns("/**");
|
||||
}
|
||||
```
|
||||
- 可能5:可能你只提交了一个请求,但是浏览器自动帮你提交了其它请求,举个例子:首次访问网站时,浏览器一般会自动提交 `/favicon.ico`,所以**你需要找出是哪个path被拦截了**,怎么找呢?用【可能4】的代码来测试找。
|
||||
- 可能6:你的项目配置了 `context-path` 上下文地址,比如 `server.servlet.context-path=/shop`,注意这个地址是不需要加在拦截器上的:
|
||||
``` java
|
||||
// 这是错误示例,不需要把 context-path 上下文参数写在下面的 excludePathPatterns 地址上。
|
||||
registry.addInterceptor(new SaInterceptor(hadnle -> StpUtil.checkLogin()))
|
||||
.addPathPatterns("/**").excludePathPatterns("/shop/user/login");
|
||||
// 这是正确示例,无论你的 context-path 上下文配置了什么样的值,下面的 excludePathPatterns 地址都不需要写上它
|
||||
registry.addInterceptor(new SaInterceptor(hadnle -> StpUtil.checkLogin()))
|
||||
.addPathPatterns("/**").excludePathPatterns("/user/login");
|
||||
```
|
||||
- 可能7:你写了多个匹配规则,请求越过了第一个规则,但又被其它规则拦下来了,例如以下代码:
|
||||
``` java
|
||||
// 以下代码,当你未登录访问 `/user/doLogin` 时,会被第1条规则越过,然后被第2条拦下,校验登录,然后抛出异常:`NotLoginException:xxx`
|
||||
registry.addInterceptor(new SaInterceptor(handler -> {
|
||||
SaRouter.match("/**").notMatch("/user/doLogin").check(r -> StpUtil.checkLogin()); // 第1个规则
|
||||
SaRouter.match("/**").notMatch("/article/getList").check(r -> StpUtil.checkLogin()); // 第2个规则
|
||||
SaRouter.match("/**").notMatch("/goods/getList").check(r -> StpUtil.checkLogin()); // 第3个规则
|
||||
})).addPathPatterns("/**");
|
||||
```
|
||||
以上代码,当你未登录访问 `/user/doLogin` 时,会被第1条规则越过,然后被第2条拦下,校验登录,然后抛出异常:`NotLoginException:xxx`
|
||||
- 可能8:你自定义的封装方法,并没有按照你的预想情况执行:
|
||||
``` java
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(new SaInterceptor(handle -> {
|
||||
// 调用自定义的 excludePaths() 方法获取数据排除鉴权
|
||||
SaRouter.match("/**").notMatch(excludePaths()).check(r -> StpUtil.checkLogin());
|
||||
})).addPathPatterns("/**");
|
||||
}
|
||||
// 自定义查询排查鉴权的地址方法
|
||||
public static List<String> excludePaths() {
|
||||
List<String> list = ... // 从数据源查询...;
|
||||
return list;
|
||||
}
|
||||
```
|
||||
如上方法, `excludePaths()` 可能并不会像你预想的一样正确执行返回相应的值,请在 `.notMatch()` 处 `一律先硬编码写固定死值来测试`,这时就有两种情况:
|
||||
- 情况1:写固定死值时,代码能正常执行了,那说明你自定义的 `excludePaths()` 方法有问题,执行结果不正确。
|
||||
- 情况2:写固定也不行,那说明不是 `excludePaths()` 的问题,那再从其它地方开始排查。
|
||||
|
||||
|
||||
|
||||
### Q:我在配置文件中加了一些关于 Sa-Token 的配置,但是没有生效。
|
||||
@@ -196,6 +234,48 @@ public class SaTokenApplication {
|
||||
2、情况2是,这个组件注入成功了,但是还没到执行时机,比如 `StpInterface` 组件,只有在鉴权时才会触发,如果你的代码仅仅是登录校验,就不会执行到这个组件。
|
||||
|
||||
|
||||
### Q:集成 Redis 后,明明 Redis 中有值,却还是提示无效Token?
|
||||
|
||||
根据以往的处理经验,发生这种情况 90% 的概率是因为你找错了Redis,即:代码连接的Redis和你用管理工具看到的Redis并不是同一个。
|
||||
|
||||
你可能会问:我看配置文件明明是同一个啊?
|
||||
|
||||
我的回答是:别光看配置文件,不一定准确,在启动时直接执行 `SaManager.getSaTokenDao().set("name", "value", 100000);`,
|
||||
随便写入一个值,看看能不能根据你的预期写进这个Redis,如果能的话才能证明`代码连接的Reids` 和`你用管理工具看到的Redis` 是同一个,再进行下一步排查。
|
||||
|
||||
|
||||
### Q:报错:无效Same-Token:xxxxxxxxxxx
|
||||
与之类似的的报错还有:
|
||||
- SSO模式二时,报错:无效ticket:xxxxxxxxxx
|
||||
- OAuth2模块跨多个项目搭建Server时:报错无效 Access-Token:xxxxxx
|
||||
- 微服务做分布式 Session 认证时,报错:无效 Token:xxxxxxxxx
|
||||
- 等等等等....
|
||||
|
||||
这些功能有个统一的特点,就是需要多个项目连接同一个 Redis 才能搭建成功,如果连接的不是同一个 Redis,就会导致 Token / ticket 无法互相认证。
|
||||
|
||||
你可能会问:我看配置文件明明就是连接的同一个 Redis 啊?
|
||||
|
||||
别急,和上一个问题一样,**不要凭借肉眼检查下定论**,在你的两个服务之间,分别使用以下代码测试一下:
|
||||
|
||||
``` java
|
||||
@SpringBootApplication
|
||||
public class SspServerApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SspServerApplication.class, args);
|
||||
// 写值测试:注意一定要用下列方法测试,不要用自己封装的 RedisUtil 之类的测试
|
||||
SaManager.getSaTokenDao().set("name", "value", 100000);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
如果都能根据你的预期写进同一个 Redis,那才能证明两个服务确实连接的是同一个 Redis。
|
||||
|
||||
实际上,在交流群中提问这些问题的同学,90%的经过以上测试以后,都会发现两者连接的不是同一个 Reids,原因大多是:Redis配置没有生效、使用了 Alone-Redis 之类的……
|
||||
|
||||
如果你是剩下的 10%,那么继续排查:两边的 sa-token 配置是否完全一致,比如 token-name 配置不一致,也会导致数据无法相互认证。最好是把所有 sa-token 相关的配置都复制过去,试验一下看看。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### Q:有时候我不加 Token 也可以通过鉴权,请问是怎么回事?
|
||||
@@ -276,6 +356,38 @@ springboot 集成 satoken redis 后, 一旦 springboot 切换版本就有可能
|
||||
|
||||
|
||||
|
||||
### Q:我实现了 StpInterface 接口,但是在登录时没有进入我的实现类代码?
|
||||
不进入是正常现象, StpInterface 是鉴权接口,在执行鉴权代码时才会进入 StpInterface 实现类,登录认证时不会进入。
|
||||
|
||||
|
||||
### Q:启动时报错,找不到 xx 类 xx 方法:
|
||||
``` java
|
||||
Caused by: java.lang.ClassNotFoundException: cn.dev33.satoken.same.SaSameTemplate
|
||||
```
|
||||
|
||||
一般找不到类,或者找不到方法,都是版本冲突了,使用 Sa-Token 时一定要注意**版本对齐**,意思是所有和 Sa-Token 相关的依赖都需要版本一致。
|
||||
|
||||
比如说你如果一个依赖是 1.32.0,一个是 1.31.0,就会造成无法启动:
|
||||
|
||||
``` xml
|
||||
<!-- 如下样例:一个是 `1.32.0`,一个是 `1.31.0`, 版本没对齐,就会造成项目无法启动 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.32.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
<version>1.31.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
请仔细排查你的 pom.xml 文件,是否有 Sa-Token 依赖没对齐,**请不要肉眼检查,用全局搜索 "sa-token" 关键词来找**,如果是多模块或者微服务项目,就整个项目搜索。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- ---------------------------- 常见疑问 ----------------------------- -->
|
||||
|
||||
14
sa-token-doc/more/demand-commit.md
Normal file
14
sa-token-doc/more/demand-commit.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# 需求提交
|
||||
|
||||
文档不清晰?功能不完善?脑袋里有好 idea?提!都可以提!
|
||||
|
||||
我们深知一个优秀的项目不能闭门造车,它需要海纳百川:[点我在线提交需求](https://wj.qq.com/s2/10852322/0d8b/)
|
||||
|
||||
<!-- 我们深知一个优秀的项目需要海纳百川,请把你的不满、吐槽、创意纷纷砸过来:[点我在线提交需求](https://wj.qq.com/s2/10852322/0d8b/) -->
|
||||
|
||||
我们将慎重对待每一位粉丝的珍贵意见 ❤️ ❤️ ❤️:
|
||||
|
||||
- 对框架新增特性功能且比较简单,会在第一时间进行开发。
|
||||
- 对框架新增特性功能但比较复杂,会延后几个版本制定相应的计划后进行开发。
|
||||
- 与框架设计理念不太相符,或超出权限认证范畴,将会视需求人数决定是否开发。
|
||||
|
||||
@@ -6,10 +6,9 @@
|
||||
|
||||
### 1、加入QQ交流群
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
QQ交流群:614714762 [点击加入](https://jq.qq.com/?_wv=1027&k=F96A2mrl)
|
||||
QQ交流群:707350988 [点击加入](https://jq.qq.com/?_wv=1027&k=tqbzHT2D)
|
||||
|
||||
### 2、加入微信交流群:
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ Sa-Token 采用 Apache-2.0 开源协议,**承诺框架本身与官网文档永
|
||||
|
||||
| 赞助人 | 赞助金额 | 留言 | 时间 |
|
||||
| :-------- | :-------- | :-------- | :-------- |
|
||||
| [laruui](https://gitee.com/laruui) | ¥ 10.0 | 感谢您的开源项目!加油 | 2022-10-28 |
|
||||
| [就眠儀式](https://gitee.com/Jmysy) | ¥ 50.0 | 感谢您的开源项目! | 2022-10-26 |
|
||||
| [王文博](https://gitee.com/rl520) | ¥ 20.0 | 感谢您的开源项目! | 2022-10-24 |
|
||||
| [feyong](https://gitee.com/feyong) | ¥ 10.0 | 感谢您的开源项目! | 2022-10-18 |
|
||||
| [xueshize](https://gitee.com/xueshize) | ¥ 20.0 | 感谢您的开源项目! | 2022-10-12 |
|
||||
| [西东](https://gitee.com/noear_admin) | ¥ 99.0 | 感谢您的开源项目! | 2022-10-05 |
|
||||
| [BlueRose](https://gitee.com/Bluerose_2) | ¥ 20.0 | 感谢您的付出,项目非常棒! | 2022-09-22 |
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
# 更新日志
|
||||
|
||||
|
||||
### 2022-11-16 @v1.33.0
|
||||
- 重构:重构异常状态码机制。 **[重要]**
|
||||
- 重构:重构 sa-token-sso 模块异常码改为 300 开头,sa-token-jwt 异常码改为 302 开头。 **[不向下兼容]**
|
||||
- 新增:新增全局 Log 模块。 **[重要]**
|
||||
- 重构:`SaTokenListenerForConsolePrint` 改名 `SaTokenListenerForLog`。 **[不向下兼容]**
|
||||
- 修复:修复多线程下 `SaFoxUtil.getRandomString()` 随机数重复问题。
|
||||
- 修复:修复 sa-token-demo-sso3-client-nosdk 项目中单点注销 url 配置错误的问题
|
||||
- 文档:文档优化。
|
||||
|
||||
|
||||
|
||||
### 2022-10-28 @v1.32.0
|
||||
- 修复:修复 sa-token-dao-redis-fastjson 插件多余序列化 `timeout` 字段的问题。
|
||||
- 修复:修复 sa-token-dao-redis-fastjson 插件 `session.getModel` 无法反序列化实体类的问题。
|
||||
|
||||
@@ -42,7 +42,7 @@ public class HomeController {
|
||||
@RequestMapping("/home")
|
||||
public Object index() {
|
||||
// 如果未登录,则先去登录
|
||||
if(StpUtil.isLogin()) {
|
||||
if(!StpUtil.isLogin()) {
|
||||
return SaHolder.getResponse().redirect("/sso/auth");
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,15 @@ SSO 集成常见问题整理
|
||||
可以:加个过滤器检测到未登录 自动跳转就行了,详细可以参照章节:[[何时引导用户去登录]](/sso/sso-custom-login) 给出的建议进行设计
|
||||
|
||||
|
||||
### 问:我参照文档的SSO模式二搭建,一直提示:Ticket无效,请问怎么回事?
|
||||
根据群友的反馈,出现此异常概率最大的原因是因为 `Client` 与 `Server` 没有连接同一个Redis,SSO模式二中两者必须连接同一个 Redis 才可以登录成功,
|
||||
如果您排查之后不是此原因,可以加入QQ群或者在issues反馈一下
|
||||
### 问:我参照文档搭建SSO-Client,一直提示:Ticket无效,请问怎么回事?
|
||||
如果使用的是模式二,出现此异常概率最大的原因是因为 `Client` 与 `Server` 没有连接同一个Redis,SSO模式二中两者必须连接同一个 Redis 才可以登录成功。
|
||||
|
||||
你可能会问:我看配置文件明明是同一个啊?
|
||||
|
||||
我的建议是:排查时不要仅凭肉眼判断,分别在你的 `Client` 与 `Server` 启动后调用 `SaManager.getSaTokenDao().set("name", "value", 100000);`
|
||||
随便写入一个值,看看能不能根据你的预期写进同一个Redis里,如果能的话才能证明 `Client` 与 `Server` 连接的Reids 是同一个,再进行下一步排查。
|
||||
|
||||
如果使用的是模式三,则排查是否有重复校验 ticket 的代码,一个 ticket 码只能使用一次,多次重复使用就会提示这个。
|
||||
|
||||
|
||||
### 模式一或者模式二报错:Could not write JSON: No serializer found for class com.pj.sso.SysUser and no properties discovered to create BeanSerializer
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
---
|
||||
|
||||
### 正式版本
|
||||
v1.32.0 正式版,可上生产:
|
||||
v1.33.0 正式版,可上生产:
|
||||
|
||||
``` xml
|
||||
<!-- Sa-Token 权限认证 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.32.0</version>
|
||||
<version>1.33.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
|
||||
|
||||
/* 右边导航 */
|
||||
.doc-header .nav-right{margin: 0; float: right; padding-right: 4em; font-size: 15px;}
|
||||
.doc-header .nav-right>*{padding: 0px; margin: 0 14px;}
|
||||
.doc-header .nav-right>*{padding: 0px; margin: 0 15px;}
|
||||
.doc-header .nav-right>*:last-child{position: relative; z-index: 1002;}
|
||||
.doc-header .nav-right>select{border-color: #999; color: #666; outline: 0; cursor: pointer; transition: all 0.2s; background-color: #FFF; border-width: 1px; outline: 0;}
|
||||
.doc-header .nav-right>select:hover{box-shadow: 0 0 10px #aaa;}
|
||||
@@ -285,6 +285,7 @@ body {
|
||||
background-size: 18px 18px;
|
||||
background-image: url(icon/code.svg);
|
||||
}
|
||||
#main .dt-btn{display: none;}
|
||||
|
||||
|
||||
/* ------------- 背景色相关 ------------- */
|
||||
|
||||
@@ -106,7 +106,7 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica
|
||||
/* -------- 集成案例 --------- */
|
||||
.s-case-box{justify-content: space-between;}
|
||||
.s-case{border: 1px #e5e5e5 solid; flex: 0 0 31.5%; margin-top: 30px; text-align: left; box-sizing: border-box; padding-bottom: 16px; overflow: hidden;}
|
||||
.s-case{position: relative; transition: all 0.2s;}
|
||||
.s-case{position: relative; transition: all 0.2s; background-color: #FFF;}
|
||||
.s-case-link{display: block; width: 100%; height: 0px; padding-bottom: 50%; position: relative; overflow: hidden;}
|
||||
.s-case-link img{width: 100%; height: 100%; object-fit: cover; object-position: center; position: absolute;}
|
||||
.s-case-link img{transition: all 0.3s;}
|
||||
@@ -234,4 +234,27 @@ body{font-size: 16px; color: #34495E; font-family: "Source Sans Pro","Helvetica
|
||||
|
||||
/* 下三角小图标 */
|
||||
.zk-icon{display: inline-block; width: 0px; height: 0px; position: relative;top: 3px; margin-left: 4px;}
|
||||
.zk-icon{border-style: solid; border-width: 5px; border-color: #aaa transparent transparent transparent; }
|
||||
.zk-icon{border-style: solid; border-width: 5px; border-color: #aaa transparent transparent transparent; }
|
||||
|
||||
|
||||
/* ------------- 背景色相关 ------------- */
|
||||
/* 侧边栏需要透明 */
|
||||
.sidebar-toggle{background-color: transparent !important;}
|
||||
.sidebar{background-color: transparent !important;}
|
||||
|
||||
/* 变色的动画 */
|
||||
.doc-header,body{transition: all 0.5s !important;}
|
||||
|
||||
/* 调色按钮 */
|
||||
.theme-btn{width: 25px; height: 25px; line-height: 60px; vertical-align: middle; position: relative; top: -1px;}
|
||||
.theme-box{width: 160px; text-align: left; line-height: 20px; margin-top: -20px; white-space: normal;}
|
||||
.theme-box span{
|
||||
display: inline-block;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin: 1px 2px;
|
||||
border: 1px #ccc solid;
|
||||
cursor: pointer;
|
||||
border-radius: 1px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ Sa-Token 提供一种侦听器机制,通过注册侦听器,你可以订阅
|
||||
|
||||

|
||||
|
||||
框架默认内置了侦听器 `SaTokenListenerForConsolePrint` 实现:[代码参考](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForConsolePrint.java)
|
||||
框架默认内置了侦听器 `SaTokenListenerForLog` 实现:[代码参考](https://gitee.com/dromara/sa-token/blob/master/sa-token-core/src/main/java/cn/dev33/satoken/listener/SaTokenListenerForLog.java)
|
||||
,功能是控制台 log 打印输出,你可以通过配置`sa-token.is-log=true`开启。
|
||||
|
||||
要注册自定义的侦听器也非常简单:
|
||||
@@ -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) {
|
||||
|
||||
@@ -83,7 +83,7 @@ for (String sessionId : sessionIdList) {
|
||||
请根据业务实际水平合理调用API。
|
||||
|
||||
|
||||
> 基础活动 Token 的统计方式会比实际情况略有延迟,如果需要精确统计实时在线用户信息,建议采用 WebSocket。
|
||||
> 基于活动 Token 的统计方式会比实际情况略有延迟,如果需要精确统计实时在线用户信息建议采用 WebSocket。
|
||||
|
||||
|
||||
---
|
||||
|
||||
@@ -98,7 +98,6 @@ public class SaTokenConfigure {
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
config.setIsLog(false); // 是否输出操作日志
|
||||
return config;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -4,8 +4,8 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtExceptionCode;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.jwt.JWT;
|
||||
@@ -146,19 +146,19 @@ public class SaJwtTemplate {
|
||||
try {
|
||||
jwt = JWT.of(token);
|
||||
} catch (JWTException e) {
|
||||
throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtExceptionCode.CODE_40101);
|
||||
throw new SaJwtException("jwt 解析失败:" + token, e).setCode(SaJwtErrorCode.CODE_30201);
|
||||
}
|
||||
JSONObject payloads = jwt.getPayloads();
|
||||
|
||||
// 校验 Token 签名
|
||||
boolean verify = jwt.setKey(keyt.getBytes()).verify();
|
||||
if(verify == false) {
|
||||
throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtExceptionCode.CODE_40102);
|
||||
throw new SaJwtException("jwt 签名无效:" + token).setCode(SaJwtErrorCode.CODE_30202);
|
||||
};
|
||||
|
||||
// 校验 loginType
|
||||
if(Objects.equals(loginType, payloads.getStr(LOGIN_TYPE)) == false) {
|
||||
throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtExceptionCode.CODE_40103);
|
||||
throw new SaJwtException("jwt loginType 无效:" + token).setCode(SaJwtErrorCode.CODE_30203);
|
||||
}
|
||||
|
||||
// 校验 Token 有效期
|
||||
@@ -166,7 +166,7 @@ public class SaJwtTemplate {
|
||||
Long effTime = payloads.getLong(EFF, 0L);
|
||||
if(effTime != NEVER_EXPIRE) {
|
||||
if(effTime == null || effTime < System.currentTimeMillis()) {
|
||||
throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtExceptionCode.CODE_40104);
|
||||
throw new SaJwtException("jwt 已过期:" + token).setCode(SaJwtErrorCode.CODE_30204);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.Map;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.ApiDisabledException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.stp.SaTokenInfo;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
@@ -40,7 +40,7 @@ public class StpLogicJwtForMixin extends StpLogic {
|
||||
*/
|
||||
public String jwtSecretKey() {
|
||||
String keyt = getConfig().getJwtSecretKey();
|
||||
SaTokenException.throwByNull(keyt, "请配置jwt秘钥");
|
||||
SaJwtException.throwByNull(keyt, "请配置jwt秘钥", SaJwtErrorCode.CODE_30205);
|
||||
return keyt;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ package cn.dev33.satoken.jwt;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
@@ -34,7 +35,7 @@ public class StpLogicJwtForSimple extends StpLogic {
|
||||
*/
|
||||
public String jwtSecretKey() {
|
||||
String keyt = getConfig().getJwtSecretKey();
|
||||
SaTokenException.throwByNull(keyt, "请配置jwt秘钥");
|
||||
SaJwtException.throwByNull(keyt, "请配置jwt秘钥", SaJwtErrorCode.CODE_30205);
|
||||
return keyt;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import java.util.Map;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.exception.ApiDisabledException;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.jwt.error.SaJwtErrorCode;
|
||||
import cn.dev33.satoken.jwt.exception.SaJwtException;
|
||||
import cn.dev33.satoken.listener.SaTokenEventCenter;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
@@ -42,7 +42,7 @@ public class StpLogicJwtForStateless extends StpLogic {
|
||||
*/
|
||||
public String jwtSecretKey() {
|
||||
String keyt = getConfig().getJwtSecretKey();
|
||||
SaTokenException.throwByNull(keyt, "请配置jwt秘钥");
|
||||
SaJwtException.throwByNull(keyt, "请配置jwt秘钥", SaJwtErrorCode.CODE_30205);
|
||||
return keyt;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ public class StpLogicJwtForStateless extends StpLogic {
|
||||
*/
|
||||
@Override
|
||||
public String createLoginSession(Object id, SaLoginModel loginModel) {
|
||||
SaTokenException.throwByNull(id, "账号id不能为空");
|
||||
SaJwtException.throwByNull(id, "账号id不能为空", SaJwtErrorCode.CODE_30206);
|
||||
|
||||
// ------ 1、初始化 loginModel
|
||||
loginModel.build(getConfig());
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.dev33.satoken.jwt.error;
|
||||
|
||||
/**
|
||||
* 定义 sa-token-jwt 所有异常细分状态码
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-31
|
||||
*/
|
||||
public class SaJwtErrorCode {
|
||||
|
||||
/** 对 jwt 字符串解析失败 */
|
||||
public static final int CODE_30201 = 30201;
|
||||
|
||||
/** 此 jwt 的签名无效 */
|
||||
public static final int CODE_30202 = 30202;
|
||||
|
||||
/** 此 jwt 的 loginType 字段不符合预期 */
|
||||
public static final int CODE_30203 = 30203;
|
||||
|
||||
/** 此 jwt 已超时 */
|
||||
public static final int CODE_30204 = 30204;
|
||||
|
||||
/** 没有配置jwt秘钥 */
|
||||
public static final int CODE_30205 = 30205;
|
||||
|
||||
/** 登录时提供的账号id为空 */
|
||||
public static final int CODE_30206 = 30206;
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
package cn.dev33.satoken.jwt.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
|
||||
/**
|
||||
* 一个异常:代表 jwt 解析错误
|
||||
* 一个异常:代表 jwt 相关错误
|
||||
*
|
||||
* @author kong
|
||||
* @since 2022-10-31
|
||||
*/
|
||||
public class SaJwtException extends SaTokenException {
|
||||
|
||||
@@ -52,5 +54,17 @@ public class SaJwtException extends SaTokenException {
|
||||
throw new SaJwtException(message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果value==null或者isEmpty,则抛出message异常
|
||||
* @param value 值
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分状态码
|
||||
*/
|
||||
public static void throwByNull(Object value, String message, int code) {
|
||||
if(SaFoxUtil.isEmpty(value)) {
|
||||
throw new SaJwtException(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
package cn.dev33.satoken.jwt.exception;
|
||||
|
||||
/**
|
||||
* 定义所有 JWT 异常细分状态码
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-5-1
|
||||
*/
|
||||
public class SaJwtExceptionCode {
|
||||
|
||||
/** 对 jwt 字符串解析失败 */
|
||||
public static final int CODE_40101 = 40101;
|
||||
|
||||
/** 此 jwt 的签名无效 */
|
||||
public static final int CODE_40102 = 40102;
|
||||
|
||||
/** 此 jwt 的 loginType 字段不符合预期 */
|
||||
public static final int CODE_40103 = 40103;
|
||||
|
||||
/** 此 jwt 已超时 */
|
||||
public static final int CODE_40104 = 40104;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package cn.dev33.satoken.oauth2.error;
|
||||
|
||||
/**
|
||||
* 定义 sa-token-oauth2 所有异常细分状态码
|
||||
*
|
||||
* @author kong
|
||||
* @since: 2022-10-31
|
||||
*/
|
||||
public interface SaOAuth2ErrorCode {
|
||||
|
||||
/** client_id 不可为空 */
|
||||
public static final int CODE_30101 = 30101;
|
||||
|
||||
/** scope 不可为空 */
|
||||
public static final int CODE_30102 = 30102;
|
||||
|
||||
/** redirect_uri 不可为空 */
|
||||
public static final int CODE_30103 = 30103;
|
||||
|
||||
/** LoginId 不可为空 */
|
||||
public static final int CODE_30104 = 30104;
|
||||
|
||||
/** 无效client_id */
|
||||
public static final int CODE_30105 = 30105;
|
||||
|
||||
/** 无效access_token */
|
||||
public static final int CODE_30106 = 30106;
|
||||
|
||||
/** 无效 client_token */
|
||||
public static final int CODE_30107 = 30107;
|
||||
|
||||
/** Access-Token 不具备指定的 Scope */
|
||||
public static final int CODE_30108 = 30108;
|
||||
|
||||
/** Client-Token 不具备指定的 Scope */
|
||||
public static final int CODE_30109 = 30109;
|
||||
|
||||
/** 无效 code 码 */
|
||||
public static final int CODE_30110 = 30110;
|
||||
|
||||
/** 无效 Refresh-Token */
|
||||
public static final int CODE_30111 = 30111;
|
||||
|
||||
/** 请求的Scope暂未签约 */
|
||||
public static final int CODE_30112 = 30112;
|
||||
|
||||
/** 无效redirect_url */
|
||||
public static final int CODE_30113 = 30113;
|
||||
|
||||
/** 非法redirect_url */
|
||||
public static final int CODE_30114 = 30114;
|
||||
|
||||
/** 无效client_secret */
|
||||
public static final int CODE_30115 = 30115;
|
||||
|
||||
/** 请求的Scope暂未签约 */
|
||||
public static final int CODE_30116 = 30116;
|
||||
|
||||
/** 无效code */
|
||||
public static final int CODE_30117 = 30117;
|
||||
|
||||
/** 无效client_id */
|
||||
public static final int CODE_30118 = 30118;
|
||||
|
||||
/** 无效client_secret */
|
||||
public static final int CODE_30119 = 30119;
|
||||
|
||||
/** 无效redirect_uri */
|
||||
public static final int CODE_30120 = 30120;
|
||||
|
||||
/** 无效refresh_token */
|
||||
public static final int CODE_30121 = 30121;
|
||||
|
||||
/** 无效client_id */
|
||||
public static final int CODE_30122 = 30122;
|
||||
|
||||
/** 无效client_secret */
|
||||
public static final int CODE_30123 = 30123;
|
||||
|
||||
/** 无效client_id */
|
||||
public static final int CODE_30124 = 30124;
|
||||
|
||||
/** 无效response_type */
|
||||
public static final int CODE_30125 = 30125;
|
||||
|
||||
/** 暂未开放授权码模式 */
|
||||
public static final int CODE_30131 = 30131;
|
||||
|
||||
/** 暂未开放隐藏式模式 */
|
||||
public static final int CODE_30132 = 30132;
|
||||
|
||||
/** 暂未开放密码式模式 */
|
||||
public static final int CODE_30133 = 30133;
|
||||
|
||||
/** 暂未开放凭证式模式 */
|
||||
public static final int CODE_30134 = 30134;
|
||||
|
||||
}
|
||||
@@ -26,10 +26,11 @@ public class SaOAuth2Exception extends SaTokenException {
|
||||
* 如果flag==true,则抛出message异常
|
||||
* @param flag 标记
|
||||
* @param message 异常信息
|
||||
* @param code 异常细分码
|
||||
*/
|
||||
public static void throwBy(boolean flag, String message) {
|
||||
public static void throwBy(boolean flag, String message, int code) {
|
||||
if(flag) {
|
||||
throw new SaOAuth2Exception(message);
|
||||
throw new SaOAuth2Exception(message).setCode(code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user