mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-02-27 16:50:24 +08:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8117a8021 | ||
|
|
c574e7f8d7 | ||
|
|
36afaf74d3 | ||
|
|
55b9c87d6a | ||
|
|
50ffda7bef | ||
|
|
a122a8b083 |
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/sz6/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.14.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.15.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的Java权限认证框架!</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/sz6/sa-token/stargazers"><img src="https://gitee.com/sz6/sa-token/badge/star.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.14.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.15.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token/stargazers"><img src="https://img.shields.io/github/stars/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/watchers"><img src="https://img.shields.io/github/watchers/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/network/members"><img src="https://img.shields.io/github/forks/click33/sa-token"></a>
|
||||
|
||||
4
pom.xml
4
pom.xml
@@ -8,7 +8,7 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
|
||||
<!-- 项目介绍 -->
|
||||
<name>sa-token</name>
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.0</sa-token-version>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>utf-8</project.reporting.outputEncoding>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package cn.dev33.satoken;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import cn.dev33.satoken.action.SaTokenAction;
|
||||
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
@@ -12,6 +15,7 @@ import cn.dev33.satoken.servlet.SaTokenServlet;
|
||||
import cn.dev33.satoken.servlet.SaTokenServletDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
@@ -21,129 +25,143 @@ import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
*/
|
||||
public class SaTokenManager {
|
||||
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
private static SaTokenConfig config;
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
initConfig();
|
||||
}
|
||||
return config;
|
||||
}
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaTokenManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaTokenInsideUtil.printSaToken();
|
||||
}
|
||||
}
|
||||
public synchronized static void initConfig() {
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* 持久化 Bean
|
||||
*/
|
||||
public static SaTokenDao saTokenDao;
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
initSaTokenDao();
|
||||
}
|
||||
return saTokenDao;
|
||||
}
|
||||
private static SaTokenDao saTokenDao;
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshTimer();
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshThread();
|
||||
}
|
||||
SaTokenManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public synchronized static void initSaTokenDao() {
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenDao;
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限认证 Bean
|
||||
*/
|
||||
public static StpInterface stpInterface;
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
initStpInterface();
|
||||
}
|
||||
return stpInterface;
|
||||
}
|
||||
private static StpInterface stpInterface;
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaTokenManager.stpInterface = stpInterface;
|
||||
}
|
||||
public synchronized static void initStpInterface() {
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return stpInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* 框架行为 Bean
|
||||
*/
|
||||
public static SaTokenAction saTokenAction;
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
initSaTokenAction();
|
||||
}
|
||||
return saTokenAction;
|
||||
}
|
||||
private static SaTokenAction saTokenAction;
|
||||
public static void setSaTokenAction(SaTokenAction saTokenAction) {
|
||||
SaTokenManager.saTokenAction = saTokenAction;
|
||||
}
|
||||
public synchronized static void initSaTokenAction() {
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenAction;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cookie操作 Bean
|
||||
*/
|
||||
public static SaTokenCookie saTokenCookie;
|
||||
public static SaTokenCookie getSaTokenCookie() {
|
||||
if (saTokenCookie == null) {
|
||||
initSaTokenCookie();
|
||||
}
|
||||
return saTokenCookie;
|
||||
}
|
||||
private static SaTokenCookie saTokenCookie;
|
||||
public static void setSaTokenCookie(SaTokenCookie saTokenCookie) {
|
||||
SaTokenManager.saTokenCookie = saTokenCookie;
|
||||
}
|
||||
public synchronized static void initSaTokenCookie() {
|
||||
public static SaTokenCookie getSaTokenCookie() {
|
||||
if (saTokenCookie == null) {
|
||||
setSaTokenCookie(new SaTokenCookieDefaultImpl());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
synchronized (SaTokenManager.class) {
|
||||
if (saTokenCookie == null) {
|
||||
setSaTokenCookie(new SaTokenCookieDefaultImpl());
|
||||
}
|
||||
}
|
||||
}
|
||||
return saTokenCookie;
|
||||
}
|
||||
|
||||
/**
|
||||
* Servlet操作 Bean
|
||||
*/
|
||||
public static SaTokenServlet saTokenServlet;
|
||||
public static SaTokenServlet getSaTokenServlet() {
|
||||
if (saTokenServlet == null) {
|
||||
initSaTokenServlet();
|
||||
}
|
||||
return saTokenServlet;
|
||||
}
|
||||
private static SaTokenServlet saTokenServlet;
|
||||
public static void setSaTokenServlet(SaTokenServlet saTokenServlet) {
|
||||
SaTokenManager.saTokenServlet = saTokenServlet;
|
||||
}
|
||||
public synchronized static void initSaTokenServlet() {
|
||||
public static SaTokenServlet getSaTokenServlet() {
|
||||
if (saTokenServlet == null) {
|
||||
setSaTokenServlet(new SaTokenServletDefaultImpl());
|
||||
// 如果对象为空,则使用框架默认方式初始化
|
||||
if (saTokenServlet == null) {
|
||||
setSaTokenServlet(new SaTokenServletDefaultImpl());
|
||||
}
|
||||
}
|
||||
return saTokenServlet;
|
||||
}
|
||||
|
||||
/**
|
||||
* StpLogic集合, 记录框架所有成功初始化的StpLogic
|
||||
*/
|
||||
public static Map<String, StpLogic> stpLogicMap = new HashMap<String, StpLogic>();
|
||||
/**
|
||||
* 向集合中 put 一个 StpLogic
|
||||
* @param stpLogic StpLogic
|
||||
*/
|
||||
public static void putStpLogic(StpLogic stpLogic) {
|
||||
stpLogicMap.put(stpLogic.getLoginKey(), stpLogic);
|
||||
}
|
||||
/**
|
||||
* 根据 LoginKey 获取对应的StpLogic,如果不存在则返回null
|
||||
* @param loginKey 对应的LoginKey
|
||||
* @return 对应的StpLogic
|
||||
*/
|
||||
public static StpLogic getStpLogic(String loginKey) {
|
||||
return stpLogicMap.get(loginKey);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -4,12 +4,9 @@ package cn.dev33.satoken.dao;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.util.SaTaskUtil;
|
||||
import cn.dev33.satoken.util.SaTaskUtil.FunctionRunClass;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
@@ -34,7 +31,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
* 构造函数
|
||||
*/
|
||||
public SaTokenDaoDefaultImpl() {
|
||||
initRefreshTimer();
|
||||
initRefreshThread();
|
||||
}
|
||||
|
||||
|
||||
@@ -166,9 +163,15 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
// --------------------- 定时清理过期数据
|
||||
|
||||
/**
|
||||
* 定时任务对象
|
||||
* 执行数据清理的线程
|
||||
*/
|
||||
public Timer refreshTimer;
|
||||
public Thread refreshThread;
|
||||
|
||||
/**
|
||||
* 是否继续执行数据清理的线程标记
|
||||
*/
|
||||
public boolean refreshFlag;
|
||||
|
||||
|
||||
/**
|
||||
* 清理所有已经过期的key
|
||||
@@ -183,30 +186,46 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
/**
|
||||
* 初始化定时任务
|
||||
*/
|
||||
public void initRefreshTimer() {
|
||||
// 如果已经被初始化过了, 则停止它
|
||||
if(this.refreshTimer != null) {
|
||||
this.endRefreshTimer();
|
||||
}
|
||||
|
||||
// 开始新的定时任务
|
||||
if(SaTokenManager.getConfig().getDataRefreshPeriod() < 0) {
|
||||
public void initRefreshThread() {
|
||||
|
||||
// 如果配置了<=0的值,则不启动定时清理
|
||||
if(SaTokenManager.getConfig().getDataRefreshPeriod() <= 0) {
|
||||
return;
|
||||
}
|
||||
int period = SaTokenManager.getConfig().getDataRefreshPeriod() * 1000;
|
||||
this.refreshTimer = SaTaskUtil.setInterval(new FunctionRunClass() {
|
||||
@Override
|
||||
public void run() {
|
||||
refreshDataMap();
|
||||
// 启动定时刷新
|
||||
this.refreshFlag = true;
|
||||
this.refreshThread = new Thread(() -> {
|
||||
for (;;) {
|
||||
try {
|
||||
try {
|
||||
// 如果已经被标记为结束
|
||||
if(refreshFlag == false) {
|
||||
return;
|
||||
}
|
||||
// 执行清理
|
||||
refreshDataMap();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 休眠N秒
|
||||
int dataRefreshPeriod = SaTokenManager.getConfig().getDataRefreshPeriod();
|
||||
if(dataRefreshPeriod <= 0) {
|
||||
dataRefreshPeriod = 1;
|
||||
}
|
||||
Thread.sleep(dataRefreshPeriod * 1000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, period, period);
|
||||
});
|
||||
refreshThread.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束定时任务
|
||||
*/
|
||||
public void endRefreshTimer() {
|
||||
this.refreshTimer.cancel();
|
||||
public void endRefreshThread() {
|
||||
this.refreshFlag = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.dev33.satoken.interceptor;
|
||||
package cn.dev33.satoken.router;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -1,13 +1,9 @@
|
||||
package cn.dev33.satoken.interceptor;
|
||||
package cn.dev33.satoken.router;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.autowired.SaTokenSpringAutowired;
|
||||
import cn.dev33.satoken.fun.IsRunFunction;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
|
||||
@@ -18,32 +14,6 @@ import cn.dev33.satoken.fun.SaFunction;
|
||||
*/
|
||||
public class SaRouterUtil {
|
||||
|
||||
/**
|
||||
* 在进行路由匹配时所使用的 PathMatcher 对象
|
||||
*/
|
||||
private static PathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* @return 在进行路由匹配时所使用的的 PathMatcher 对象
|
||||
*/
|
||||
public static PathMatcher getPathMatcher() {
|
||||
if(pathMatcher == null) {
|
||||
pathMatcher = SaTokenSpringAutowired.pathMatcher;
|
||||
if(pathMatcher == null) {
|
||||
pathMatcher = new AntPathMatcher();
|
||||
}
|
||||
}
|
||||
return pathMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param pathMatcher 写入: 在进行路由匹配时所使用的的 PathMatcher 对象
|
||||
*/
|
||||
public static void setPathMatcher(PathMatcher pathMatcher) {
|
||||
SaRouterUtil.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
|
||||
// -------------------- 路由匹配相关 --------------------
|
||||
|
||||
/**
|
||||
@@ -53,10 +23,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String path) {
|
||||
if(getPathMatcher().match(pattern, path)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return SaTokenManager.getSaTokenServlet().matchPath(pattern, path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -25,4 +25,12 @@ public interface SaTokenServlet {
|
||||
*/
|
||||
public HttpServletResponse getResponse();
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
* @param pattern 路由匹配符
|
||||
* @param path 需要匹配的路径
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public boolean matchPath(String pattern, String path);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ public class SaTokenServletDefaultImpl implements SaTokenServlet {
|
||||
*/
|
||||
@Override
|
||||
public HttpServletRequest getRequest() {
|
||||
throw new SaTokenException("请实现SaTokenServlet接口后进行Servlet相关操作");
|
||||
throw new SaTokenException("SaTokenServlet接口未实现");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,7 +26,16 @@ public class SaTokenServletDefaultImpl implements SaTokenServlet {
|
||||
*/
|
||||
@Override
|
||||
public HttpServletResponse getResponse() {
|
||||
throw new SaTokenException("请实现SaTokenServlet接口后进行Servlet相关操作");
|
||||
throw new SaTokenException("SaTokenServlet接口未实现");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
throw new SaTokenException("SaTokenServlet接口未实现");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -9,6 +7,8 @@ import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
|
||||
/**
|
||||
* Session Model
|
||||
*
|
||||
@@ -237,53 +237,6 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- 存取值 (类型转换)
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为Object类型
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public Object getObject(String key) {
|
||||
return getAttribute(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为String类型
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = getObject(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从Session中取值,并转化为int类型,如果value为空,则返回0
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
Object value = getObject(key);
|
||||
if(valueIsNull(value)) {
|
||||
return 0;
|
||||
}
|
||||
return Integer.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个值是否为null
|
||||
* @param value 指定值
|
||||
* @return 此value是否为null
|
||||
*/
|
||||
public boolean valueIsNull(Object value) {
|
||||
return value == null || value.equals("");
|
||||
}
|
||||
|
||||
|
||||
// ----------------------- 一些操作
|
||||
|
||||
/**
|
||||
@@ -305,4 +258,245 @@ public class SaSession implements Serializable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取此Session的剩余存活时间 (单位: 秒)
|
||||
* @return 此Session的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return SaTokenManager.getSaTokenDao().getSessionTimeout(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的剩余存活时间
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateTimeout(long timeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的最小剩余存活时间 (只有在Session的过期时间低于指定的minTimeout时才会进行修改)
|
||||
* @param minTimeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateMinTimeout(long minTimeout) {
|
||||
if(getTimeout() < minTimeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改此Session的最大剩余存活时间 (只有在Session的过期时间高于指定的maxTimeout时才会进行修改)
|
||||
* @param maxTimeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateMaxTimeout(long maxTimeout) {
|
||||
if(getTimeout() > maxTimeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------- 存取值 (类型转换)
|
||||
|
||||
/**
|
||||
* 写值
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void set(String key, Object value) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 写值(只有在此key原本无值的时候才会写入)
|
||||
* @param key 名称
|
||||
* @param value 值
|
||||
*/
|
||||
public void setDefaultValue(String key, Object value) {
|
||||
if(has(key) == false) {
|
||||
dataMap.put(key, value);
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public Object get(String key) {
|
||||
return dataMap.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 取值 (指定默认值)
|
||||
* @param <T> 默认值的类型
|
||||
* @param key key
|
||||
* @param defaultValue 取不到值时返回的默认值
|
||||
* @return 值
|
||||
*/
|
||||
public <T> T get(String key, T defaultValue) {
|
||||
return getValueByDefaultValue(get(key), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转String类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public String getString(String key) {
|
||||
Object value = get(key);
|
||||
if(value == null) {
|
||||
return null;
|
||||
}
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转int类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public int getInt(String key) {
|
||||
return getValueByDefaultValue(get(key), 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转long类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public long getLong(String key) {
|
||||
return getValueByDefaultValue(get(key), 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转double类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public double getDouble(String key) {
|
||||
return getValueByDefaultValue(get(key), 0.0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (转float类型)
|
||||
* @param key key
|
||||
* @return 值
|
||||
*/
|
||||
public float getFloat(String key) {
|
||||
return getValueByDefaultValue(get(key), 0.0f);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (指定转换类型)
|
||||
* @param <T> 泛型
|
||||
* @param key key
|
||||
* @param cs 指定转换类型
|
||||
* @return 值
|
||||
*/
|
||||
public <T> T getModel(String key, Class<T> cs) {
|
||||
return getValueByClass(get(key), cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取值 (指定转换类型, 并指定值为Null时返回的默认值)
|
||||
* @param <T> 泛型
|
||||
* @param key key
|
||||
* @param cs 指定转换类型
|
||||
* @param defaultValue 值为Null时返回的默认值
|
||||
* @return 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getModel(String key, Class<T> cs, Object defaultValue) {
|
||||
Object value = get(key);
|
||||
if(valueIsNull(value)) {
|
||||
return (T)defaultValue;
|
||||
}
|
||||
return getValueByClass(value, cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否含有某个key
|
||||
* @param key has
|
||||
* @return 是否含有
|
||||
*/
|
||||
public boolean has(String key) {
|
||||
return !valueIsNull(get(key));
|
||||
}
|
||||
|
||||
|
||||
// --------- 工具方法
|
||||
|
||||
/**
|
||||
* 判断一个值是否为null
|
||||
* @param value 指定值
|
||||
* @return 此value是否为null
|
||||
*/
|
||||
public boolean valueIsNull(Object value) {
|
||||
return value == null || value.equals("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定值转化为指定类型
|
||||
* @param <T> 泛型
|
||||
* @param obj 值
|
||||
* @param cs 类型
|
||||
* @return 转换后的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getValueByClass(Object obj, Class<T> cs) {
|
||||
// 如果 obj 本来就是 cs 类型
|
||||
if(obj != null && obj.getClass().equals(cs)) {
|
||||
return (T)obj;
|
||||
}
|
||||
// 开始转换
|
||||
String obj2 = String.valueOf(obj);
|
||||
Object obj3 = null;
|
||||
if (cs.equals(String.class)) {
|
||||
obj3 = obj2;
|
||||
} else if (cs.equals(int.class) || cs.equals(Integer.class)) {
|
||||
obj3 = Integer.valueOf(obj2);
|
||||
} else if (cs.equals(long.class) || cs.equals(Long.class)) {
|
||||
obj3 = Long.valueOf(obj2);
|
||||
} else if (cs.equals(short.class) || cs.equals(Short.class)) {
|
||||
obj3 = Short.valueOf(obj2);
|
||||
} else if (cs.equals(byte.class) || cs.equals(Byte.class)) {
|
||||
obj3 = Byte.valueOf(obj2);
|
||||
} else if (cs.equals(float.class) || cs.equals(Float.class)) {
|
||||
obj3 = Float.valueOf(obj2);
|
||||
} else if (cs.equals(double.class) || cs.equals(Double.class)) {
|
||||
obj3 = Double.valueOf(obj2);
|
||||
} else if (cs.equals(boolean.class) || cs.equals(Boolean.class)) {
|
||||
obj3 = Boolean.valueOf(obj2);
|
||||
} else {
|
||||
obj3 = (T)obj;
|
||||
}
|
||||
return (T)obj3;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据默认值来获取值
|
||||
* @param <T> 泛型
|
||||
* @param value 值
|
||||
* @param defaultValue 默认值
|
||||
* @return 转换后的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getValueByDefaultValue(Object value, T defaultValue) {
|
||||
|
||||
// 如果 obj 为 null,则直接返回默认值
|
||||
if(valueIsNull(value)) {
|
||||
return (T)defaultValue;
|
||||
}
|
||||
|
||||
// 开始转换
|
||||
Class<T> cs = (Class<T>) defaultValue.getClass();
|
||||
return getValueByClass(value, cs);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -45,6 +45,8 @@ public class StpLogic {
|
||||
*/
|
||||
public StpLogic(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
// 在 SaTokenManager 中记录下此 StpLogic,以便根据 LoginKey 进行查找此对象
|
||||
SaTokenManager.putStpLogic(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,13 +90,22 @@ public class StpLogic {
|
||||
/**
|
||||
* 在当前会话写入当前tokenValue
|
||||
* @param tokenValue token值
|
||||
* @param cookieTimeout Cookie存活时间(秒)
|
||||
*/
|
||||
public void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
SaTokenConfig config = getConfig();
|
||||
// 将token保存到本次request里
|
||||
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
|
||||
request.setAttribute(splicingKeyJustCreatedSave(), tokenValue);
|
||||
// 判断是否配置了token前缀
|
||||
String tokenPrefix = config.getTokenPrefix();
|
||||
if(SaTokenInsideUtil.isEmpty(tokenPrefix)) {
|
||||
request.setAttribute(splicingKeyJustCreatedSave(), tokenValue);
|
||||
} else {
|
||||
// 如果配置了token前缀,则拼接上前缀一起写入
|
||||
request.setAttribute(splicingKeyJustCreatedSave(), tokenPrefix + SaTokenConsts.TOKEN_CONNECTOR_CHAT + tokenValue);
|
||||
}
|
||||
|
||||
// 注入Cookie
|
||||
SaTokenConfig config = getConfig();
|
||||
if(config.getIsReadCookie() == true){
|
||||
HttpServletResponse response = SaTokenManager.getSaTokenServlet().getResponse();
|
||||
SaTokenManager.getSaTokenCookie().addCookie(response, getTokenName(), tokenValue,
|
||||
@@ -136,9 +147,11 @@ public class StpLogic {
|
||||
// 5. 如果打开了前缀模式
|
||||
String tokenPrefix = getConfig().getTokenPrefix();
|
||||
if(SaTokenInsideUtil.isEmpty(tokenPrefix) == false && SaTokenInsideUtil.isEmpty(tokenValue) == false) {
|
||||
// 如果token以指定的前缀开头, 则裁剪掉它
|
||||
if(tokenValue.startsWith(tokenPrefix + " ")) {
|
||||
tokenValue = tokenValue.substring(tokenPrefix.length() + 1);
|
||||
// 如果token以指定的前缀开头, 则裁剪掉它, 否则视为未提供token
|
||||
if(tokenValue.startsWith(tokenPrefix + SaTokenConsts.TOKEN_CONNECTOR_CHAT)) {
|
||||
tokenValue = tokenValue.substring(tokenPrefix.length() + SaTokenConsts.TOKEN_CONNECTOR_CHAT.length());
|
||||
} else {
|
||||
tokenValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,19 +255,18 @@ public class StpLogic {
|
||||
if(session == null) {
|
||||
session = getSessionByLoginId(loginId);
|
||||
} else {
|
||||
// 保证此Session的有效期 >= token的有效期
|
||||
if(dao.getSessionTimeout(session.getId()) < loginModel.getTimeout()) {
|
||||
dao.updateSessionTimeout(session.getId(), loginModel.getTimeout());
|
||||
}
|
||||
session.updateMinTimeout(loginModel.getTimeout());
|
||||
}
|
||||
// 在session上记录token签名
|
||||
session.addTokenSign(new TokenSign(tokenValue, loginModel.getDevice()));
|
||||
|
||||
// ------ 4. 持久化其它数据
|
||||
// token -> uid
|
||||
dao.set(splicingKeyTokenValue(tokenValue), String.valueOf(loginId), loginModel.getTimeout());
|
||||
dao.set(splicingKeyTokenValue(tokenValue), String.valueOf(loginId), loginModel.getTimeout());
|
||||
|
||||
// 写入 [最后操作时间]
|
||||
setLastActivityToNow(tokenValue);
|
||||
setLastActivityToNow(tokenValue);
|
||||
|
||||
// 在当前会话写入当前tokenValue
|
||||
setTokenValue(tokenValue, loginModel.getCookieTimeout());
|
||||
}
|
||||
|
||||
@@ -36,6 +36,15 @@ public class StpUtil {
|
||||
return stpLogic.getTokenName();
|
||||
}
|
||||
|
||||
/**
|
||||
* 在当前会话写入当前tokenValue
|
||||
* @param tokenValue token值
|
||||
* @param cookieTimeout Cookie存活时间(秒)
|
||||
*/
|
||||
public static void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
stpLogic.setTokenValue(tokenValue, cookieTimeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前tokenValue
|
||||
* @return 当前tokenValue
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
package cn.dev33.satoken.util;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* 任务调度Util
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTaskUtil {
|
||||
|
||||
/**
|
||||
* 延时指定毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setTimeout(FunctionRunClass fc, int delay) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
timer.cancel();
|
||||
}
|
||||
}, delay);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 延时delay毫秒,每隔period毫秒执行一个函数
|
||||
* @param fc 要执行的函数
|
||||
* @param delay 延时的毫秒数
|
||||
* @param period 每隔多少毫秒执行一次
|
||||
* @return timer任务对象
|
||||
*/
|
||||
public static Timer setInterval(FunctionRunClass fc, int delay, int period) {
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
fc.run();
|
||||
}
|
||||
}, delay, period);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 封装一个内部类,便于操作
|
||||
* @author kong
|
||||
*/
|
||||
public static interface FunctionRunClass{
|
||||
/**
|
||||
* 要执行的方法
|
||||
*/
|
||||
public void run();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class SaTokenConsts {
|
||||
/**
|
||||
* sa-token 版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.14.0";
|
||||
public static final String VERSION_NO = "v1.15.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
@@ -42,8 +42,8 @@ public class SaTokenConsts {
|
||||
* 常量key标记: 在进行临时身份切换时使用的key
|
||||
*/
|
||||
public static final String SWITCH_TO_SAVE_KEY = "SWITCH_TO_SAVE_KEY_";
|
||||
|
||||
|
||||
|
||||
|
||||
// =================== token-style 相关 ===================
|
||||
|
||||
/**
|
||||
@@ -75,6 +75,13 @@ public class SaTokenConsts {
|
||||
* token风格: tik风格 (2_14_16)
|
||||
*/
|
||||
public static final String TOKEN_STYLE_RANDOM_TIK = "tik";
|
||||
|
||||
|
||||
// =================== 其它 ===================
|
||||
|
||||
/**
|
||||
* 连接token前缀和token值的字符
|
||||
*/
|
||||
public static final String TOKEN_CONNECTOR_CHAT = " ";
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.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.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.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.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -39,7 +39,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.14.0-alpha</version>
|
||||
<version>1.15.0-alpha</version>
|
||||
</dependency>
|
||||
|
||||
<!-- sa-token整合redis (使用jackson序列化方式) -->
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.14.0</sa-token-version>
|
||||
<sa-token-version>1.15.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.pj;
|
||||
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
|
||||
|
||||
/**
|
||||
@@ -15,20 +14,6 @@ import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
|
||||
@Configuration
|
||||
public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
|
||||
// 获取配置Bean (以代码的方式配置sa-token, 此配置会覆盖yml中的配置 )
|
||||
// @Primary
|
||||
// @Bean(name="MySaTokenConfig")
|
||||
public SaTokenConfig getSaTokenConfig() {
|
||||
SaTokenConfig config = new SaTokenConfig();
|
||||
config.setTokenName("satoken"); // token名称 (同时也是cookie名称)
|
||||
config.setTimeout(30 * 24 * 60 * 60); // token有效期,单位s 默认30天
|
||||
config.setActivityTimeout(-1); // token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
|
||||
config.setAllowConcurrentLogin(true); // 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
|
||||
config.setIsShare(true); // 在多人登录同一账号时,是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
|
||||
config.setTokenStyle("uuid"); // token风格
|
||||
return config;
|
||||
}
|
||||
|
||||
// 注册sa-token的拦截器,打开注解式鉴权功能
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
|
||||
@@ -5,9 +5,10 @@ import java.io.IOException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
@@ -18,7 +19,7 @@ import cn.dev33.satoken.exception.NotRoleException;
|
||||
/**
|
||||
* 全局异常处理
|
||||
*/
|
||||
@RestControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
|
||||
@ControllerAdvice // 可指定包前缀,比如:(basePackages = "com.pj.admin")
|
||||
public class GlobalException {
|
||||
|
||||
// 在当前类每个方法进入之前触发的操作
|
||||
@@ -28,14 +29,14 @@ public class GlobalException {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 全局异常拦截(拦截项目中的所有异常)
|
||||
@ResponseBody
|
||||
@ExceptionHandler
|
||||
public AjaxJson handlerException(Exception e, HttpServletRequest request, HttpServletResponse response)
|
||||
throws Exception {
|
||||
|
||||
// 打印堆栈,以供调试
|
||||
System.out.println("全局异常---------------");
|
||||
e.printStackTrace();
|
||||
|
||||
// 不同异常返回不同状态码
|
||||
|
||||
@@ -3,8 +3,6 @@ package com.pj.test;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -241,14 +239,13 @@ public class TestController {
|
||||
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test(HttpServletResponse response) {
|
||||
public AjaxJson test() {
|
||||
System.out.println("进来了");
|
||||
// StpUtil.setLoginId(10001, new SaLoginModel()
|
||||
// .setDevice("PC") // 此次登录的客户端设备标识, 用于[同端互斥登录]时指定此次登录的设备名称
|
||||
// .setIsLastingCookie(true) // 是否为持久Cookie(临时Cookie在浏览器关闭时会自动删除,持久Cookie在重新打开后依然存在)
|
||||
// .setTimeout(60 * 60 * 24 * 7) // 指定此次登录token的有效期, 单位:秒 (如未指定,自动取全局配置的timeout值)
|
||||
// );
|
||||
StpUtil.getTokenSession();
|
||||
return AjaxJson.getSuccess("访问成功");
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ spring:
|
||||
token-style: uuid
|
||||
|
||||
|
||||
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/sz6/sa-token/raw/master/sa-token-doc/doc/logo.png" width="150" height="150">
|
||||
</p>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.14.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.15.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的Java权限认证框架!</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/sz6/sa-token/stargazers"><img src="https://gitee.com/sz6/sa-token/badge/star.svg"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.14.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token"><img src="https://img.shields.io/badge/sa--token-v1.15.0-2B9939"></a>
|
||||
<a href="https://github.com/click33/sa-token/stargazers"><img src="https://img.shields.io/github/stars/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/watchers"><img src="https://img.shields.io/github/watchers/click33/sa-token"></a>
|
||||
<a href="https://github.com/click33/sa-token/network/members"><img src="https://img.shields.io/github/forks/click33/sa-token"></a>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
- [注解式鉴权](/use/at-check)
|
||||
- [路由拦截式鉴权](/use/route-check)
|
||||
- [花式token](/use/token-style)
|
||||
- [Token前缀](/use/token-prefix)
|
||||
- [框架配置](/use/config)
|
||||
- [会话治理](/use/search-session)
|
||||
- [记住我模式](/use/remember-me)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
- SpringBoot2.0、Redis、Jackson、Hutool、jwt
|
||||
- SpringBoot自定义starter、Spring包扫码 + 依赖注入、AOP注解切面、yml配置映射、拦截器
|
||||
- Java8 接口与default实现、静态方法、枚举、定时器、异常类、泛型、反射、IO流、自定义注解、Lambda表达式、函数式编程
|
||||
- package-info注释、Serializable序列化接口、
|
||||
- package-info注释、Serializable序列化接口、synchronized锁
|
||||
- java加密算法:MD5、SHA1、SHA256、AES、RSA
|
||||
- OAuth2.0、同域单点登录、集群与分布式、路由Ant匹配
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<nav>
|
||||
<select onchange="location.href=this.value">
|
||||
<option value="http://sa-token.dev33.cn/doc/index.html">最新版</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.14.0/doc/index.html">v1.14.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.13.0/doc/index.html">v1.13.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.12.1/doc/index.html">v1.12.1</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.12.0/doc/index.html">v1.12.0</option>
|
||||
@@ -43,7 +44,7 @@
|
||||
</div>
|
||||
<script>
|
||||
var name = '<img style="width: 50px; height: 50px; vertical-align: middle;" src="logo.png" alt="logo" /> ';
|
||||
name += '<b style="font-size: 24px; vertical-align: middle;">sa-token</b> <sub>v1.14.0</sub>'
|
||||
name += '<b style="font-size: 24px; vertical-align: middle;">sa-token</b> <sub>v1.15.0</sub>'
|
||||
window.$docsify = {
|
||||
name: name, // 名字
|
||||
repo: 'https://github.com/click33/sa-token', // github地址
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
# 更新日志
|
||||
|
||||
|
||||
### 2021-3-23 @v1.15.0
|
||||
- 新增:文档添加源码涉及技术栈说明
|
||||
- 优化:优化路由拦截器模块文档,更简洁的示例
|
||||
- 修复:修复非web环境下的错误提示,Request->Response
|
||||
- 修复:修复Cookie注入时path判断错误,感谢@zhangzi0291提供的PR
|
||||
- 新增:文档集成Redis章节新增redis配置示例说明,感谢群友 `@-)` 提供的建议
|
||||
- 新增:增加token前缀模式,可在配置token读取前缀,适配`Bearer token`规范 **[重要]**
|
||||
- 优化:`SaTokenManager`初始化Bean去除`initXxx`方法,优化代码逻辑
|
||||
- 新增:`SaTokenManager`新增`stpLogicMap`集合,记录所有`StpLogic`的初始化,方便查找
|
||||
- 新增:`Session`新增timeout操作API,可灵活修改Session的剩余有效时间
|
||||
- 新增:token前缀改为强制校验模式,如果配置了前缀,则前端提交token时必须带有
|
||||
- 优化:精简`SaRouteInterceptor`,只保留自定义验证和默认的登陆验证,去除冗余功能
|
||||
- 优化:`SaRouterUtil`迁移到core核心包,优化依赖架构
|
||||
- 优化:默认Dao实现类里`Timer定时器`改为子线程 + sleep 模拟
|
||||
- 新增:`Session`新增各种类型转换API,可快速方便存取值 **[重要]**
|
||||
- 升级注意:
|
||||
- `SaRouterUtil`类迁移到核心包,注意更换import地址
|
||||
- `SaRouteInterceptor`去出冗余API,详情参考路由鉴权部分
|
||||
|
||||
|
||||
### 2021-3-12 @v1.14.0
|
||||
- 新增:新增`SaLoginModel`登录参数Model,适配 [记住我] 模式 **[重要]**
|
||||
- 新增:新增 `StpUtil.setLoginId()` 时指定token有效期,可灵活控制用户的一次登录免验证时长
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## Gradle依赖
|
||||
Gradle用户引入依赖:
|
||||
```
|
||||
implementation 'cn.dev33:sa-token-spring-boot-starter:1.14.0'
|
||||
implementation 'cn.dev33:sa-token-spring-boot-starter:1.15.0'
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ sa-token内置两种模式完成注解鉴权,分别是`AOP模式`和`拦截器
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-aop</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
@@ -71,4 +71,5 @@ public class MySaTokenConfig {
|
||||
| dataRefreshPeriod | int | 30 | 默认dao层实现类中,每次清理过期数据间隔的时间 (单位: 秒) ,默认值30秒,设置为-1代表不启动定时清理 |
|
||||
| tokenSessionCheckLogin | Boolean | true | 获取token专属session时是否必须登录 (如果配置为true,会在每次获取token专属session时校验是否登录) |
|
||||
| autoRenew | Boolean | true | 是否打开自动续签 (如果此值为true, 框架会在每次直接或间接调用getLoginId()时进行一次过期检查与续签操作) |
|
||||
| tokenPrefix | Boolean | true | token前缀, 格式样例(satoken: Bearer xxxx-xxxx-xxxx-xxxx) [参考:token前缀](/use/token-prefix) |
|
||||
| isV | Boolean | true | 是否在初始化配置时打印版本字符画 |
|
||||
|
||||
@@ -14,7 +14,7 @@ Sa-token默认将会话数据保存在内存中,此模式读写速度最快,
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:兼容性好,缺点:Session序列化后基本不可读,对开发者来讲等同于乱码
|
||||
@@ -26,7 +26,7 @@ Sa-token默认将会话数据保存在内存中,此模式读写速度最快,
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-dao-redis-jackson</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</dependency>
|
||||
```
|
||||
优点:Session序列化后可读性强,可灵活手动修改,缺点:兼容性稍差
|
||||
|
||||
@@ -99,8 +99,18 @@ public class MySaTokenConfig implements WebMvcConfigurer {
|
||||
|
||||
|
||||
|
||||
## 注意事项
|
||||
在`v1.14`及以前版本下,路由拦截器提供了提供了封装式写法,该方法代码比较冗余,在`v1.15`版本已移除,解决方案如下:
|
||||
|
||||
``` java
|
||||
// 原写法
|
||||
registry.addInterceptor(SaRouteInterceptor.createPermissionVal("user")).addPathPatterns("/user/**");
|
||||
|
||||
|
||||
|
||||
|
||||
// 改为以下方式,效果同上
|
||||
registry.addInterceptor(new SaRouteInterceptor((request, response, handler) -> {
|
||||
SaRouterUtil.match("/user/**", () -> StpUtil.checkPermission("user"));
|
||||
})).addPathPatterns("/**");
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -65,32 +65,97 @@ SaSessionCustomUtil.deleteSessionById("goods-10001");
|
||||
### Session相关操作
|
||||
那么获取到的`SaSession`具体有哪些方法可供操作?
|
||||
``` java
|
||||
session.getId(); // 返回此Session的id
|
||||
session.getCreateTime(); // 返回此Session的创建时间 (时间戳)
|
||||
session.getAttribute('name'); // 在Session上获取一个值
|
||||
session.getAttribute('name', 'zhang'); // 在Session上获取一个值,并指定取不到值时返回的默认值
|
||||
session.setAttribute('name', 'zhang'); // 在Session上写入一个值
|
||||
session.removeAttribute('name'); // 在Session上移除一个值
|
||||
session.clearAttribute(); // 清空此Session的所有值
|
||||
session.containsAttribute('name'); // 获取此Session是否含有指定key (返回true或false)
|
||||
session.attributeKeys(); // 获取此Session会话上所有key (返回Set<String>)
|
||||
session.getDataMap(); // 返回此Session会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免产生脏数据)
|
||||
session.update(); // 将这个Session从持久库更新一下
|
||||
session.logout(); // 注销此Session会话 (从持久库删除此Session)
|
||||
// 返回此Session的id
|
||||
session.getId();
|
||||
|
||||
// 返回此Session的创建时间 (时间戳)
|
||||
session.getCreateTime();
|
||||
|
||||
// 在Session上获取一个值
|
||||
session.getAttribute('name');
|
||||
|
||||
// 在Session上获取一个值,并指定取不到值时返回的默认值
|
||||
session.getAttribute('name', 'zhang');
|
||||
|
||||
// 在Session上写入一个值
|
||||
session.setAttribute('name', 'zhang');
|
||||
|
||||
// 在Session上移除一个值
|
||||
session.removeAttribute('name');
|
||||
|
||||
// 清空此Session的所有值
|
||||
session.clearAttribute();
|
||||
|
||||
// 获取此Session是否含有指定key (返回true或false)
|
||||
session.containsAttribute('name');
|
||||
|
||||
// 获取此Session会话上所有key (返回Set<String>)
|
||||
session.attributeKeys();
|
||||
|
||||
// 返回此Session会话上的底层数据对象(如果更新map里的值,请调用session.update()方法避免产生脏数据)
|
||||
session.getDataMap();
|
||||
|
||||
// 将这个Session从持久库更新一下
|
||||
session.update();
|
||||
|
||||
// 注销此Session会话 (从持久库删除此Session)
|
||||
session.logout();
|
||||
```
|
||||
|
||||
|
||||
### 类型转换API
|
||||
由于Session存取值默认的类型都是Object,因此我们通常会写很多不必要类型转换代码 <br>
|
||||
为了简化操作,sa-token自`v1.15.0`封装了存取值API的类型转换,你可以非常方便的调用以下方法:
|
||||
``` java
|
||||
// 写值
|
||||
session.set("name", "zhang");
|
||||
|
||||
// 写值(只有在此key原本无值的时候才会写入)
|
||||
session.set("name", "zhang");
|
||||
|
||||
// 取值
|
||||
session.get("name");
|
||||
|
||||
// 取值 (指定默认值)
|
||||
session.get("name", "<defaultValue>");
|
||||
|
||||
// 取值 (转String类型)
|
||||
session.getString("name");
|
||||
|
||||
// 取值 (转int类型)
|
||||
session.getInt("age");
|
||||
|
||||
// 取值 (转long类型)
|
||||
session.getLong("age");
|
||||
|
||||
// 取值 (转double类型)
|
||||
session.getDouble("result");
|
||||
|
||||
// 取值 (转float类型)
|
||||
session.getFloat("result");
|
||||
|
||||
// 取值 (指定转换类型)
|
||||
session.getModel("key", Student.class);
|
||||
|
||||
// 取值 (指定转换类型, 并指定值为Null时返回的默认值)
|
||||
session.getModel("key", Student.class, <defaultValue>);
|
||||
|
||||
// 是否含有某个key
|
||||
session.has("key");
|
||||
```
|
||||
具体可参考`javax.servlet.http.HttpSession`,`SaSession`所含方法与其大体类似
|
||||
|
||||
|
||||
### Session环境隔离说明
|
||||
在springboot环境下取得的session环境和通过StpUtil获取的session环境并不相通, 示例
|
||||
有同学经常会把 `SaSession` 与 `HttpSession` 进行混淆,例如:
|
||||
``` java
|
||||
@PostMapping("/resetPoints")
|
||||
public void reset(HttpSession session) {
|
||||
session.setAttribute("pointsKey", 66);
|
||||
SaSession session2 = StpUtil.getSession();
|
||||
Object value = session2.getAttribute("pointsKey");
|
||||
System.out.println(value)
|
||||
// 输出null
|
||||
// 在HttpSession上写入一个值
|
||||
session.setAttribute("name", 66);
|
||||
// 在SaSession进行取值
|
||||
System.out.println(StpUtil.getSession().getAttribute("name")); // 输出null
|
||||
}
|
||||
```
|
||||
而且, 在使用sa-token多账号模式下, 不同的StpUtil获取的session之间也是环境隔离
|
||||
**要点:**
|
||||
1. `SaSession` 与 `HttpSession` 没有任何关系,在`HttpSession`上写入的值,在`SaSession`中无法取出
|
||||
2. `HttpSession`并未被框架接管,在使用sa-token时,请在任何情况下均使用`SaSession`,不要使用`HttpSession`
|
||||
|
||||
32
sa-token-doc/doc/use/token-prefix.md
Normal file
32
sa-token-doc/doc/use/token-prefix.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Token前缀
|
||||
|
||||
### 需求场景
|
||||
|
||||
在某些系统中,前端提交token时会在前面加个固定的前缀,例如:
|
||||
|
||||
``` js
|
||||
{
|
||||
"satoken": "Bearer xxxx-xxxx-xxxx-xxxx"
|
||||
}
|
||||
```
|
||||
|
||||
此时后端如果不做任何特殊处理,框架将会把`Bearer `视为token的一部分,无法正常读取token信息,导致鉴权失败
|
||||
|
||||
为此,我们需要在yml中添加如下配置:
|
||||
``` java
|
||||
spring:
|
||||
# sa-token配置
|
||||
sa-token:
|
||||
# token前缀
|
||||
tokenPrefix: Bearer
|
||||
```
|
||||
|
||||
此时 sa-token 便可在读取token时裁剪掉 `Bearer`,成功获取`xxxx-xxxx-xxxx-xxxx`
|
||||
|
||||
|
||||
### 注意点
|
||||
|
||||
1. `token前缀` 与 `token值` 之间必须有一个空格
|
||||
2. 一旦配置了`token前缀`,则前端提交token时,必须带有前缀,否则会导致框架无法读取token
|
||||
3. 由于`Cookie`中无法存储空格字符,也就意味配置token前缀后,`Cookie`鉴权方式将会失效,此时只能将token提交到`header`里进行传输
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
<!-- 内容部分 -->
|
||||
<div class="main-box">
|
||||
<div class="content-box">
|
||||
<h1>sa-token<small>v1.14.0</small></h1>
|
||||
<h1>sa-token<small>v1.15.0</small></h1>
|
||||
<div class="sub-title">这可能是史上功能最全的java权限认证框架!</div>
|
||||
<!-- <p>0配置开箱即用,低学习成本</p> -->
|
||||
<p>登录验证、权限验证、Session会话、踢人下线、集成Redis、分布式会话、单点登录、前后台分离、记住我模式、模拟他人账号、临时身份切换、多账号体系、注解式鉴权、路由拦截式鉴权、花式token、自动续签、同端互斥登录、会话治理、密码加密、jwt集成、Spring集成...</p>
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>sa-token-dao-redis</name>
|
||||
<artifactId>sa-token-oauth2</artifactId>
|
||||
<version>1.14.0-alpha</version>
|
||||
<version>1.15.0-alpha</version>
|
||||
<description>sa-token realization oauth2.0</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<parent>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<version>1.14.0</version>
|
||||
<version>1.15.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -105,19 +105,15 @@ public class SaTokenSpringAutowired {
|
||||
SaTokenManager.setSaTokenServlet(saTokenServlet);
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由匹配器
|
||||
*/
|
||||
public static PathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* 利用自动匹配特性,获取SpringMVC框架内部使用的路由匹配器
|
||||
*
|
||||
* @param pathMatcher 要设置的 pathMatcher
|
||||
*/
|
||||
@Autowired(required = false)
|
||||
public static void setPathMatcher(PathMatcher pathMatcher) {
|
||||
SaTokenSpringAutowired.pathMatcher = pathMatcher;
|
||||
public void setPathMatcher(PathMatcher pathMatcher) {
|
||||
SaTokenServletSpringImpl.setPathMatcher(pathMatcher);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.router.SaRouteFunction;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
|
||||
/**
|
||||
@@ -15,204 +14,25 @@ import cn.dev33.satoken.stp.StpUtil;
|
||||
*/
|
||||
public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
|
||||
|
||||
// ----------------- 属性 -----------------
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
private StpLogic stpLogic;
|
||||
|
||||
/**
|
||||
* 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
|
||||
*/
|
||||
private int type;
|
||||
|
||||
/**
|
||||
* 验证模式 AND | OR
|
||||
*/
|
||||
private SaMode mode;
|
||||
|
||||
/**
|
||||
* 标识码数组
|
||||
*/
|
||||
private String[] codes;
|
||||
|
||||
/**
|
||||
* 自定义模式下的执行函数
|
||||
*/
|
||||
private SaRouteFunction function;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 表示登录验证
|
||||
*/
|
||||
public static final int LOGIN = 1;
|
||||
|
||||
/**
|
||||
* 表示角色验证
|
||||
*/
|
||||
public static final int ROLE = 2;
|
||||
|
||||
/**
|
||||
* 表示权限验证
|
||||
*/
|
||||
public static final int PERMISSION = 3;
|
||||
|
||||
/**
|
||||
* 表示自定义验证
|
||||
*/
|
||||
public static final int CUSTOM = 4;
|
||||
|
||||
|
||||
/**
|
||||
* @return 底层的 StpLogic 对象
|
||||
*/
|
||||
public StpLogic getStpLogic() {
|
||||
if(stpLogic == null) {
|
||||
stpLogic = StpUtil.stpLogic;
|
||||
}
|
||||
return stpLogic;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stpLogic 底层的 StpLogic 对象
|
||||
* @return 拦截器自身
|
||||
*/
|
||||
public SaRouteInterceptor setStpLogic(StpLogic stpLogic) {
|
||||
this.stpLogic = stpLogic;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
|
||||
* @return 拦截器自身
|
||||
*/
|
||||
public SaRouteInterceptor setType(int type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 验证模式 AND | OR
|
||||
*/
|
||||
public SaMode getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mode 验证模式 AND | OR
|
||||
* @return 拦截器自身
|
||||
*/
|
||||
public SaRouteInterceptor setMode(SaMode mode) {
|
||||
this.mode = mode;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 标识码数组
|
||||
*/
|
||||
public String[] getCodes() {
|
||||
return codes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param codes 标识码数组
|
||||
* @return 拦截器自身
|
||||
*/
|
||||
public SaRouteInterceptor setCodes(String... codes) {
|
||||
this.codes = codes;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 自定义模式下的执行函数
|
||||
*/
|
||||
public SaRouteFunction getFunction() {
|
||||
return function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param function 设置自定义模式下的执行函数
|
||||
* @return 拦截器自身
|
||||
*/
|
||||
public SaRouteInterceptor setFunction(SaRouteFunction function) {
|
||||
this.type = SaRouteInterceptor.CUSTOM;
|
||||
this.function = function;
|
||||
return this;
|
||||
}
|
||||
|
||||
// ----------------- 构建相关 -----------------
|
||||
|
||||
/**
|
||||
* 创建 (全参数)
|
||||
* @param type 验证类型 (1=登录验证, 2=角色验证, 3=权限验证, 4=自定义验证)
|
||||
* @param mode 验证模式 AND | OR
|
||||
* @param codes 标识码数组
|
||||
*/
|
||||
public SaRouteInterceptor(int type, SaMode mode, String... codes) {
|
||||
super();
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
this.codes = codes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 (默认为登录验证)
|
||||
*/
|
||||
public SaRouteInterceptor() {
|
||||
this(SaRouteInterceptor.LOGIN, null, new String[0]);
|
||||
}
|
||||
public SaRouteFunction function;
|
||||
|
||||
/**
|
||||
* 创建 (默认为自定义认证)
|
||||
* @param function 自定义模式下的执行函数
|
||||
*/
|
||||
public SaRouteInterceptor(SaRouteFunction function) {
|
||||
this(SaRouteInterceptor.CUSTOM, null, new String[0]);
|
||||
setFunction(function);
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个模式为登录认证的sa路由拦截器
|
||||
* @return sa拦截器
|
||||
*/
|
||||
public static SaRouteInterceptor createLoginVal() {
|
||||
return new SaRouteInterceptor();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个模式为角色认证的sa路由拦截器
|
||||
* @param roles 需要验证的角色标识列表
|
||||
* @return sa拦截器
|
||||
*/
|
||||
public static SaRouteInterceptor createRoleVal(String... roles) {
|
||||
return new SaRouteInterceptor(SaRouteInterceptor.ROLE, SaMode.AND, roles);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建一个模式为权限认证的sa路由拦截器
|
||||
* @param permissions 需要验证的权限列表
|
||||
* @return sa拦截器
|
||||
*/
|
||||
public static SaRouteInterceptor createPermissionVal(String... permissions) {
|
||||
return new SaRouteInterceptor(SaRouteInterceptor.PERMISSION, SaMode.AND, permissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个模式为自定义认证的sa路由拦截器
|
||||
* 静态方法快速构建一个
|
||||
* @param function 自定义模式下的执行函数
|
||||
* @return sa拦截器
|
||||
* @return sa路由拦截器
|
||||
*/
|
||||
public static SaRouteInterceptor createCustomVal(SaRouteFunction function) {
|
||||
public static SaRouteInterceptor newInstance(SaRouteFunction function) {
|
||||
return new SaRouteInterceptor(function);
|
||||
}
|
||||
|
||||
@@ -226,22 +46,10 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
|
||||
throws Exception {
|
||||
|
||||
// 根据模式进行验证
|
||||
if(this.type == SaRouteInterceptor.LOGIN) {
|
||||
getStpLogic().checkLogin();
|
||||
} else if(this.type == SaRouteInterceptor.ROLE) {
|
||||
if(mode == SaMode.AND) {
|
||||
getStpLogic().checkRoleAnd(codes);
|
||||
} else {
|
||||
getStpLogic().checkRoleOr(codes);
|
||||
}
|
||||
} else if(this.type == SaRouteInterceptor.PERMISSION) {
|
||||
if(mode == SaMode.AND) {
|
||||
getStpLogic().checkPermissionAnd(codes);
|
||||
} else {
|
||||
getStpLogic().checkPermissionOr(codes);
|
||||
}
|
||||
} else if(this.type == SaRouteInterceptor.CUSTOM) {
|
||||
// 如果未提供function,默认进行登录验证
|
||||
if(function == null) {
|
||||
StpUtil.checkLogin();
|
||||
} else {
|
||||
function.run(request, response, handler);
|
||||
}
|
||||
|
||||
@@ -250,6 +58,4 @@ public class SaRouteInterceptor implements HandlerInterceptor {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,13 @@ package cn.dev33.satoken.spring;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.util.PathMatcher;
|
||||
|
||||
import cn.dev33.satoken.servlet.SaTokenServlet;
|
||||
|
||||
/**
|
||||
* sa-token 对cookie的相关操作 接口实现类
|
||||
* sa-token 对Cookie的相关操作 接口实现类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
@@ -29,4 +32,37 @@ public class SaTokenServletSpringImpl implements SaTokenServlet {
|
||||
return SpringMVCUtil.getResponse();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 路由匹配器
|
||||
*/
|
||||
private static PathMatcher pathMatcher;
|
||||
|
||||
/**
|
||||
* 获取路由匹配器
|
||||
* @return 路由匹配器
|
||||
*/
|
||||
public static PathMatcher getPathMatcher() {
|
||||
if(pathMatcher == null) {
|
||||
pathMatcher = new AntPathMatcher();
|
||||
}
|
||||
return pathMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入路由匹配器
|
||||
* @param pathMatcher 路由匹配器
|
||||
*/
|
||||
public static void setPathMatcher(PathMatcher pathMatcher) {
|
||||
SaTokenServletSpringImpl.pathMatcher = pathMatcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验指定路由匹配符是否可以匹配成功指定路径
|
||||
*/
|
||||
@Override
|
||||
public boolean matchPath(String pattern, String path) {
|
||||
return getPathMatcher().match(pattern, path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user