mirror of
https://gitee.com/dromara/sa-token.git
synced 2026-02-27 16:50:24 +08:00
Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5fe7897ee | ||
|
|
041294e790 | ||
|
|
0a7a8138b3 | ||
|
|
ca2599c528 | ||
|
|
4398a5808c | ||
|
|
9965821b51 | ||
|
|
5cde169e7f | ||
|
|
479b40b92b | ||
|
|
76dd333c9b | ||
|
|
e6e53d44d5 | ||
|
|
3c429cbee9 | ||
|
|
8b8c01a76d | ||
|
|
9465357d6b | ||
|
|
fb4733792d | ||
|
|
a75d461275 | ||
|
|
9c1ff87023 | ||
|
|
6d164a0726 | ||
|
|
2bb2248522 | ||
|
|
a69e41b04c | ||
|
|
2d4267b1da | ||
|
|
3405188531 | ||
|
|
7a6d027d59 | ||
|
|
eae7f9ffbf | ||
|
|
865a280365 | ||
|
|
b34aed5f97 | ||
|
|
cd99053640 | ||
|
|
c0eeaa6ddd | ||
|
|
72530a223a | ||
|
|
ec42359377 | ||
|
|
d01db3442b | ||
|
|
4ee161031f | ||
|
|
79d7967e0d | ||
|
|
d139bfd858 | ||
|
|
f2454dd244 | ||
|
|
9a2e14d147 | ||
|
|
b7d1ca88af | ||
|
|
36744a64ee | ||
|
|
377801d800 | ||
|
|
6d301a0a69 | ||
|
|
26cde5d244 | ||
|
|
5269e30331 | ||
|
|
e40a39e3ef |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -11,4 +11,4 @@ unpackage/
|
||||
.factorypath
|
||||
/.factorypath
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/dromara/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.17.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.19.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的 Java 权限认证框架!</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
|
||||
@@ -150,6 +150,7 @@ sa-token秉承着开放的思想,欢迎大家为框架添砖加瓦:
|
||||
|
||||
[**[ jthink]** 一个基于springboot+sa-token+thymeleaf的博客系统](https://gitee.com/wtsoftware/jthink)
|
||||
|
||||
[**[ dcy-fast]** 一个基于springboot+sa-token+mybatis-plus的后台管理系统,前端vue-element-admin,并且内置代码生成器](https://gitee.com/dcy421/dcy-fast)
|
||||
|
||||
如果您的项目使用了sa-token,欢迎提交pr
|
||||
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
|
||||
:: 整体clean
|
||||
call mvn clean
|
||||
|
||||
:: demo模块clean
|
||||
cd sa-token-demo
|
||||
|
||||
cd sa-token-demo-jwt
|
||||
call mvn clean
|
||||
cd ..
|
||||
@@ -13,14 +17,21 @@ cd sa-token-demo-webflux
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-oauth2\sa-token-demo-oauth2-client
|
||||
cd sa-token-demo-oauth2-client
|
||||
call mvn clean
|
||||
cd ../..
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-oauth2\sa-token-demo-oauth2-server
|
||||
cd sa-token-demo-oauth2-server
|
||||
call mvn clean
|
||||
cd ../..
|
||||
cd ..
|
||||
|
||||
cd sa-token-demo-quick-login
|
||||
call mvn clean
|
||||
cd ..
|
||||
|
||||
cd ..
|
||||
|
||||
:: 最后打印
|
||||
echo;
|
||||
echo;
|
||||
echo ----------- clean end -----------
|
||||
|
||||
14
pom.xml
14
pom.xml
@@ -8,7 +8,7 @@
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
|
||||
<!-- 项目介绍 -->
|
||||
<name>sa-token</name>
|
||||
@@ -19,13 +19,9 @@
|
||||
<!-- 所有模块 -->
|
||||
<modules>
|
||||
<module>sa-token-core</module>
|
||||
<module>sa-token-servlet</module>
|
||||
<module>sa-token-spring-boot-starter</module>
|
||||
<module>sa-token-reactor-spring-boot-starter</module>
|
||||
<module>sa-token-dao-redis</module>
|
||||
<module>sa-token-dao-redis-jackson</module>
|
||||
<module>sa-token-spring-aop</module>
|
||||
<!-- <module>sa-token-oauth2</module> -->
|
||||
<module>sa-token-starter</module>
|
||||
<module>sa-token-plugin</module>
|
||||
<!-- <module>sa-token-demo\sa-token-demo-quick-login</module> -->
|
||||
</modules>
|
||||
|
||||
<!-- 开源协议 apache 2.0 -->
|
||||
@@ -40,7 +36,7 @@
|
||||
|
||||
<!-- 一些属性 -->
|
||||
<properties>
|
||||
<sa-token-version>1.17.0</sa-token-version>
|
||||
<sa-token-version>1.19.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.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</parent>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
|
||||
@@ -11,33 +11,37 @@ import cn.dev33.satoken.context.SaTokenContext;
|
||||
import cn.dev33.satoken.context.SaTokenContextDefaultImpl;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.dao.SaTokenDaoDefaultImpl;
|
||||
import cn.dev33.satoken.exception.SaTokenException;
|
||||
import cn.dev33.satoken.listener.SaTokenListener;
|
||||
import cn.dev33.satoken.listener.SaTokenListenerDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpInterface;
|
||||
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
|
||||
import cn.dev33.satoken.stp.StpLogic;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* 管理sa-token所有接口对象
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenManager {
|
||||
public class SaManager {
|
||||
|
||||
/**
|
||||
* 配置文件 Bean
|
||||
*/
|
||||
private static SaTokenConfig config;
|
||||
public static void setConfig(SaTokenConfig config) {
|
||||
SaTokenManager.config = config;
|
||||
SaManager.config = config;
|
||||
if(config.getIsV()) {
|
||||
SaTokenInsideUtil.printSaToken();
|
||||
SaFoxUtil.printSaToken();
|
||||
}
|
||||
// 调用一次StpUtil中的方法,保证其可以尽早的初始化 StpLogic
|
||||
StpUtil.getLoginKey();
|
||||
}
|
||||
public static SaTokenConfig getConfig() {
|
||||
if (config == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (config == null) {
|
||||
setConfig(SaTokenConfigFactory.createConfig());
|
||||
}
|
||||
@@ -51,14 +55,14 @@ public class SaTokenManager {
|
||||
*/
|
||||
private static SaTokenDao saTokenDao;
|
||||
public static void setSaTokenDao(SaTokenDao saTokenDao) {
|
||||
if(SaTokenManager.saTokenDao != null && (SaTokenManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaTokenManager.saTokenDao).endRefreshThread();
|
||||
if(SaManager.saTokenDao != null && (SaManager.saTokenDao instanceof SaTokenDaoDefaultImpl)) {
|
||||
((SaTokenDaoDefaultImpl)SaManager.saTokenDao).endRefreshThread();
|
||||
}
|
||||
SaTokenManager.saTokenDao = saTokenDao;
|
||||
SaManager.saTokenDao = saTokenDao;
|
||||
}
|
||||
public static SaTokenDao getSaTokenDao() {
|
||||
if (saTokenDao == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenDao == null) {
|
||||
setSaTokenDao(new SaTokenDaoDefaultImpl());
|
||||
}
|
||||
@@ -72,11 +76,11 @@ public class SaTokenManager {
|
||||
*/
|
||||
private static StpInterface stpInterface;
|
||||
public static void setStpInterface(StpInterface stpInterface) {
|
||||
SaTokenManager.stpInterface = stpInterface;
|
||||
SaManager.stpInterface = stpInterface;
|
||||
}
|
||||
public static StpInterface getStpInterface() {
|
||||
if (stpInterface == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (stpInterface == null) {
|
||||
setStpInterface(new StpInterfaceDefaultImpl());
|
||||
}
|
||||
@@ -90,11 +94,11 @@ public class SaTokenManager {
|
||||
*/
|
||||
private static SaTokenAction saTokenAction;
|
||||
public static void setSaTokenAction(SaTokenAction saTokenAction) {
|
||||
SaTokenManager.saTokenAction = saTokenAction;
|
||||
SaManager.saTokenAction = saTokenAction;
|
||||
}
|
||||
public static SaTokenAction getSaTokenAction() {
|
||||
if (saTokenAction == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenAction == null) {
|
||||
setSaTokenAction(new SaTokenActionDefaultImpl());
|
||||
}
|
||||
@@ -108,11 +112,11 @@ public class SaTokenManager {
|
||||
*/
|
||||
private static SaTokenContext saTokenContext;
|
||||
public static void setSaTokenContext(SaTokenContext saTokenContext) {
|
||||
SaTokenManager.saTokenContext = saTokenContext;
|
||||
SaManager.saTokenContext = saTokenContext;
|
||||
}
|
||||
public static SaTokenContext getSaTokenContext() {
|
||||
if (saTokenContext == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenContext == null) {
|
||||
setSaTokenContext(new SaTokenContextDefaultImpl());
|
||||
}
|
||||
@@ -126,11 +130,11 @@ public class SaTokenManager {
|
||||
*/
|
||||
private static SaTokenListener saTokenListener;
|
||||
public static void setSaTokenListener(SaTokenListener saTokenListener) {
|
||||
SaTokenManager.saTokenListener = saTokenListener;
|
||||
SaManager.saTokenListener = saTokenListener;
|
||||
}
|
||||
public static SaTokenListener getSaTokenListener() {
|
||||
if (saTokenListener == null) {
|
||||
synchronized (SaTokenManager.class) {
|
||||
synchronized (SaManager.class) {
|
||||
if (saTokenListener == null) {
|
||||
setSaTokenListener(new SaTokenListenerDefaultImpl());
|
||||
}
|
||||
@@ -153,12 +157,31 @@ public class SaTokenManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据 LoginKey 获取对应的StpLogic,如果不存在则返回null
|
||||
* 根据 LoginKey 获取对应的StpLogic,如果不存在则抛出异常
|
||||
* @param loginKey 对应的LoginKey
|
||||
* @return 对应的StpLogic
|
||||
*/
|
||||
public static StpLogic getStpLogic(String loginKey) {
|
||||
return stpLogicMap.get(loginKey);
|
||||
// 如果key为空则返回框架内置的
|
||||
if(loginKey == null || loginKey.isEmpty()) {
|
||||
return StpUtil.stpLogic;
|
||||
}
|
||||
|
||||
// 从SaManager中获取
|
||||
StpLogic stpLogic = stpLogicMap.get(loginKey);
|
||||
if(stpLogic == null) {
|
||||
/*
|
||||
* 此时有两种情况会造成 StpLogic == null
|
||||
* 1. LoginKey拼写错误,请改正 (建议使用常量)
|
||||
* 2. 自定义StpUtil尚未初始化(静态类中的属性至少一次调用后才会初始化),解决方法两种
|
||||
* (1) 从main方法里调用一次
|
||||
* (2) 在自定义StpUtil类加上类似 @Component 的注解让容器启动时扫描到自动初始化
|
||||
*/
|
||||
throw new SaTokenException("未能获取对应StpLogic,key="+ loginKey);
|
||||
}
|
||||
|
||||
// 返回
|
||||
return stpLogic;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
|
||||
/**
|
||||
@@ -25,4 +28,18 @@ public interface SaTokenAction {
|
||||
*/
|
||||
public SaSession createSession(String sessionId);
|
||||
|
||||
/**
|
||||
* 指定集合是否包含指定元素(模糊匹配)
|
||||
* @param list 集合
|
||||
* @param element 元素
|
||||
* @return 是否包含
|
||||
*/
|
||||
public boolean hasElement(List<String> list, String element);
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解检查(注解鉴权内部实现)
|
||||
* @param method Method对象
|
||||
*/
|
||||
public void checkMethodAnnotation(Method method);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package cn.dev33.satoken.action;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* 对 SaTokenAction 接口的默认实现
|
||||
@@ -14,14 +19,13 @@ import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
*/
|
||||
public class SaTokenActionDefaultImpl implements SaTokenAction {
|
||||
|
||||
|
||||
/**
|
||||
* 根据一定的算法生成一个token
|
||||
*/
|
||||
@Override
|
||||
public String createToken(Object loginId, String loginKey) {
|
||||
// 根据配置的tokenStyle生成不同风格的token
|
||||
String tokenStyle = SaTokenManager.getConfig().getTokenStyle();
|
||||
String tokenStyle = SaManager.getConfig().getTokenStyle();
|
||||
// uuid
|
||||
if(SaTokenConsts.TOKEN_STYLE_UUID.equals(tokenStyle)) {
|
||||
return UUID.randomUUID().toString();
|
||||
@@ -32,25 +36,24 @@ public class SaTokenActionDefaultImpl implements SaTokenAction {
|
||||
}
|
||||
// 32位随机字符串
|
||||
if(SaTokenConsts.TOKEN_STYLE_RANDOM_32.equals(tokenStyle)) {
|
||||
return SaTokenInsideUtil.getRandomString(32);
|
||||
return SaFoxUtil.getRandomString(32);
|
||||
}
|
||||
// 64位随机字符串
|
||||
if(SaTokenConsts.TOKEN_STYLE_RANDOM_64.equals(tokenStyle)) {
|
||||
return SaTokenInsideUtil.getRandomString(64);
|
||||
return SaFoxUtil.getRandomString(64);
|
||||
}
|
||||
// 128位随机字符串
|
||||
if(SaTokenConsts.TOKEN_STYLE_RANDOM_128.equals(tokenStyle)) {
|
||||
return SaTokenInsideUtil.getRandomString(128);
|
||||
return SaFoxUtil.getRandomString(128);
|
||||
}
|
||||
// tik风格 (2_14_16)
|
||||
if(SaTokenConsts.TOKEN_STYLE_TIK.equals(tokenStyle)) {
|
||||
return SaTokenInsideUtil.getRandomString(2) + "_" + SaTokenInsideUtil.getRandomString(14) + "_" + SaTokenInsideUtil.getRandomString(16) + "__";
|
||||
return SaFoxUtil.getRandomString(2) + "_" + SaFoxUtil.getRandomString(14) + "_" + SaFoxUtil.getRandomString(16) + "__";
|
||||
}
|
||||
// 默认,还是uuid
|
||||
return UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 SessionId 创建一个 Session
|
||||
*/
|
||||
@@ -58,5 +61,72 @@ public class SaTokenActionDefaultImpl implements SaTokenAction {
|
||||
public SaSession createSession(String sessionId) {
|
||||
return new SaSession(sessionId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定集合是否包含指定元素(模糊匹配)
|
||||
*/
|
||||
@Override
|
||||
public boolean hasElement(List<String> list, String element) {
|
||||
// 集合为空直接返回false
|
||||
if(list == null || list.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
// 遍历匹配
|
||||
for (String patt : list) {
|
||||
if(SaFoxUtil.vagueMatch(patt, element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 走出for循环说明没有一个元素可以匹配成功
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解权限校验(注解鉴权逻辑内部实现)
|
||||
*/
|
||||
@Override
|
||||
public void checkMethodAnnotation(Method method) {
|
||||
|
||||
// 获取这个 Method 所属的 Class
|
||||
Class<?> clazz = method.getDeclaringClass();
|
||||
|
||||
|
||||
// 从 Class 校验 @SaCheckLogin 注解
|
||||
if(clazz.isAnnotationPresent(SaCheckLogin.class)) {
|
||||
SaCheckLogin at = clazz.getAnnotation(SaCheckLogin.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 从 Class 校验 @SaCheckRole 注解
|
||||
if(clazz.isAnnotationPresent(SaCheckRole.class)) {
|
||||
SaCheckRole at = clazz.getAnnotation(SaCheckRole.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 从 Class 校验 @SaCheckPermission 注解
|
||||
if(clazz.isAnnotationPresent(SaCheckPermission.class)) {
|
||||
SaCheckPermission at = clazz.getAnnotation(SaCheckPermission.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 从 Method 校验 @SaCheckLogin 注解
|
||||
if(method.isAnnotationPresent(SaCheckLogin.class)) {
|
||||
SaCheckLogin at = method.getAnnotation(SaCheckLogin.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 从 Method 校验 @SaCheckRole 注解
|
||||
if(method.isAnnotationPresent(SaCheckRole.class)) {
|
||||
SaCheckRole at = method.getAnnotation(SaCheckRole.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
// 从 Method 校验 @SaCheckPermission 注解
|
||||
if(method.isAnnotationPresent(SaCheckPermission.class)) {
|
||||
SaCheckPermission at = method.getAnnotation(SaCheckPermission.class);
|
||||
SaManager.getStpLogic(at.key()).checkByAnnotation(at);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,4 +15,10 @@ import java.lang.annotation.Target;
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface SaCheckLogin {
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -26,5 +26,11 @@ public @interface SaCheckPermission {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -26,5 +26,11 @@ public @interface SaCheckRole {
|
||||
* @return 验证模式
|
||||
*/
|
||||
SaMode mode() default SaMode.AND;
|
||||
|
||||
/**
|
||||
* 多账号体系下所属的账号体系标识
|
||||
* @return see note
|
||||
*/
|
||||
String key() default "";
|
||||
|
||||
}
|
||||
|
||||
@@ -333,8 +333,6 @@ public class SaTokenConfig {
|
||||
+ tokenSessionCheckLogin + ", autoRenew=" + autoRenew + ", cookieDomain=" + cookieDomain
|
||||
+ ", tokenPrefix=" + tokenPrefix + ", isV=" + isV + ", isLog=" + isLog + "]";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package cn.dev33.satoken.context;
|
||||
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
|
||||
/**
|
||||
* Sa-Token 上下文持有类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaHolder {
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Request] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaRequest getRequest() {
|
||||
return SaManager.getSaTokenContext().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [Response] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaResponse getResponse() {
|
||||
return SaManager.getSaTokenContext().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的 [存储器] 对象
|
||||
*
|
||||
* @return see note
|
||||
*/
|
||||
public static SaStorage getStorage() {
|
||||
return SaManager.getSaTokenContext().getStorage();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,9 +35,15 @@ public interface SaRequest {
|
||||
public String getCookieValue(String name);
|
||||
|
||||
/**
|
||||
* 返回当前请求的URL
|
||||
* 返回当前请求path (不包括上下文名称)
|
||||
* @return see note
|
||||
*/
|
||||
public String getRequestURI();
|
||||
public String getRequestPath();
|
||||
|
||||
/**
|
||||
* 返回当前请求的类型
|
||||
* @return see note
|
||||
*/
|
||||
public String getMethod();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,4 +29,21 @@ public interface SaResponse {
|
||||
*/
|
||||
public void addCookie(String name, String value, String path, String domain, int timeout);
|
||||
|
||||
/**
|
||||
* 在响应头里写入一个值
|
||||
* @param name 名字
|
||||
* @param value 值
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaResponse setHeader(String name, String value);
|
||||
|
||||
/**
|
||||
* 在响应头写入 [Server] 服务器名称
|
||||
* @param value 服务器名称
|
||||
* @return 对象自身
|
||||
*/
|
||||
public default SaResponse setServer(String value) {
|
||||
return this.setHeader("Server", value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* sa-token持久层默认的实现类 , 基于内存Map
|
||||
@@ -189,7 +189,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
public void initRefreshThread() {
|
||||
|
||||
// 如果配置了<=0的值,则不启动定时清理
|
||||
if(SaTokenManager.getConfig().getDataRefreshPeriod() <= 0) {
|
||||
if(SaManager.getConfig().getDataRefreshPeriod() <= 0) {
|
||||
return;
|
||||
}
|
||||
// 启动定时刷新
|
||||
@@ -208,7 +208,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
e.printStackTrace();
|
||||
}
|
||||
// 休眠N秒
|
||||
int dataRefreshPeriod = SaTokenManager.getConfig().getDataRefreshPeriod();
|
||||
int dataRefreshPeriod = SaManager.getConfig().getDataRefreshPeriod();
|
||||
if(dataRefreshPeriod <= 0) {
|
||||
dataRefreshPeriod = 1;
|
||||
}
|
||||
@@ -235,7 +235,7 @@ public class SaTokenDaoDefaultImpl implements SaTokenDao {
|
||||
|
||||
@Override
|
||||
public List<String> searchData(String prefix, String keyword, int start, int size) {
|
||||
return SaTokenInsideUtil.searchList(expireMap.keySet(), prefix, keyword, start, size);
|
||||
return SaFoxUtil.searchList(expireMap.keySet(), prefix, keyword, start, size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ public class NotPermissionException extends SaTokenException {
|
||||
/**
|
||||
* 序列化版本号
|
||||
*/
|
||||
private static final long serialVersionUID = 6806129545290130142L;
|
||||
private static final long serialVersionUID = 6806129545290130141L;
|
||||
|
||||
/** 权限码 */
|
||||
private String code;
|
||||
|
||||
@@ -44,7 +44,6 @@ public class NotRoleException extends SaTokenException {
|
||||
}
|
||||
|
||||
public NotRoleException(String role, String loginKey) {
|
||||
// 这里到底要不要拼接上loginKey呢?纠结
|
||||
super("无此角色:" + role);
|
||||
this.role = role;
|
||||
this.loginKey = loginKey;
|
||||
|
||||
@@ -6,6 +6,7 @@ package cn.dev33.satoken.fun;
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaFunction {
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,9 @@ package cn.dev33.satoken.listener;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
|
||||
/**
|
||||
* Sa-Token 侦听器的默认实现:log打印
|
||||
@@ -51,7 +51,7 @@ public class SaTokenListenerDefaultImpl implements SaTokenListener {
|
||||
@Override
|
||||
public void doDisable(String loginKey, Object loginId, long disableTime) {
|
||||
Date date = new Date(System.currentTimeMillis() + disableTime * 1000);
|
||||
println("账号[" + loginId + "]被封禁 (解封时间: " + SaTokenInsideUtil.formatDate(date) + ")");
|
||||
println("账号[" + loginId + "]被封禁 (解封时间: " + SaFoxUtil.formatDate(date) + ")");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,7 +88,7 @@ public class SaTokenListenerDefaultImpl implements SaTokenListener {
|
||||
* @param str 字符串
|
||||
*/
|
||||
public void println(String str) {
|
||||
if(SaTokenManager.getConfig().getIsLog()) {
|
||||
if(SaManager.getConfig().getIsLog()) {
|
||||
System.out.println(LOG_PREFIX + str);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import cn.dev33.satoken.context.model.SaResponse;
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface SaRouteFunction {
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,7 +3,8 @@ package cn.dev33.satoken.router;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.fun.IsRunFunction;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
|
||||
@@ -23,7 +24,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatch(String pattern, String path) {
|
||||
return SaTokenManager.getSaTokenContext().matchPath(pattern, path);
|
||||
return SaManager.getSaTokenContext().matchPath(pattern, path);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -47,7 +48,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(String pattern) {
|
||||
return isMatch(pattern, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
|
||||
return isMatch(pattern, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,7 +57,7 @@ public class SaRouterUtil {
|
||||
* @return 是否匹配成功
|
||||
*/
|
||||
public static boolean isMatchCurrURI(List<String> patterns) {
|
||||
return isMatch(patterns, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
|
||||
return isMatch(patterns, SaHolder.getRequest().getRequestPath());
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +120,7 @@ public class SaRouterUtil {
|
||||
* @return 匹配结果包装对象
|
||||
*/
|
||||
public static IsRunFunction match(String... patterns) {
|
||||
boolean matchResult = isMatch(Arrays.asList(patterns), SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
|
||||
boolean matchResult = isMatch(Arrays.asList(patterns), SaHolder.getRequest().getRequestPath());
|
||||
return new IsRunFunction(matchResult);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.Set;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* Session Model
|
||||
@@ -45,7 +45,7 @@ public class SaSession implements Serializable {
|
||||
this.id = id;
|
||||
this.createTime = System.currentTimeMillis();
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doCreateSession(id);
|
||||
SaManager.getSaTokenListener().doCreateSession(id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,14 +246,14 @@ public class SaSession implements Serializable {
|
||||
* 更新Session(从持久库更新刷新一下)
|
||||
*/
|
||||
public void update() {
|
||||
SaTokenManager.getSaTokenDao().updateSession(this);
|
||||
SaManager.getSaTokenDao().updateSession(this);
|
||||
}
|
||||
|
||||
/** 注销Session (从持久库删除) */
|
||||
public void logout() {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(this.id);
|
||||
SaManager.getSaTokenDao().deleteSession(this.id);
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doLogoutSession(id);
|
||||
SaManager.getSaTokenListener().doLogoutSession(id);
|
||||
}
|
||||
|
||||
/** 当Session上的tokenSign数量为零时,注销会话 */
|
||||
@@ -268,7 +268,7 @@ public class SaSession implements Serializable {
|
||||
* @return 此Session的剩余存活时间 (单位: 秒)
|
||||
*/
|
||||
public long getTimeout() {
|
||||
return SaTokenManager.getSaTokenDao().getSessionTimeout(this.id);
|
||||
return SaManager.getSaTokenDao().getSessionTimeout(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,7 +276,7 @@ public class SaSession implements Serializable {
|
||||
* @param timeout 过期时间 (单位: 秒)
|
||||
*/
|
||||
public void updateTimeout(long timeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,7 +285,7 @@ public class SaSession implements Serializable {
|
||||
*/
|
||||
public void updateMinTimeout(long minTimeout) {
|
||||
if(getTimeout() < minTimeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, minTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -295,7 +295,7 @@ public class SaSession implements Serializable {
|
||||
*/
|
||||
public void updateMaxTimeout(long maxTimeout) {
|
||||
if(getTimeout() > maxTimeout) {
|
||||
SaTokenManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
|
||||
SaManager.getSaTokenDao().updateSessionTimeout(this.id, maxTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.dev33.satoken.session;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* 自定义Session工具类
|
||||
@@ -22,7 +22,7 @@ public class SaSessionCustomUtil {
|
||||
* @return sessionId
|
||||
*/
|
||||
public static String splicingSessionKey(String sessionId) {
|
||||
return SaTokenManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
|
||||
return SaManager.getConfig().getTokenName() + ":" + sessionKey + ":session:" + sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,7 +32,7 @@ public class SaSessionCustomUtil {
|
||||
* @return 是否存在
|
||||
*/
|
||||
public static boolean isExists(String sessionId) {
|
||||
return SaTokenManager.getSaTokenDao().getSession(splicingSessionKey(sessionId)) != null;
|
||||
return SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId)) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,10 +43,10 @@ public class SaSessionCustomUtil {
|
||||
* @return SaSession
|
||||
*/
|
||||
public static SaSession getSessionById(String sessionId, boolean isCreate) {
|
||||
SaSession session = SaTokenManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
|
||||
SaSession session = SaManager.getSaTokenDao().getSession(splicingSessionKey(sessionId));
|
||||
if (session == null && isCreate) {
|
||||
session = SaTokenManager.getSaTokenAction().createSession(sessionId);
|
||||
SaTokenManager.getSaTokenDao().setSession(session, SaTokenManager.getConfig().getTimeout());
|
||||
session = SaManager.getSaTokenAction().createSession(splicingSessionKey(sessionId));
|
||||
SaManager.getSaTokenDao().setSession(session, SaManager.getConfig().getTimeout());
|
||||
}
|
||||
return session;
|
||||
}
|
||||
@@ -67,7 +67,7 @@ public class SaSessionCustomUtil {
|
||||
* @param sessionId 指定key
|
||||
*/
|
||||
public static void deleteSessionById(String sessionId) {
|
||||
SaTokenManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
|
||||
SaManager.getSaTokenDao().deleteSession(splicingSessionKey(sessionId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
@@ -97,7 +97,7 @@ public class SaLoginModel {
|
||||
* @return 对象自身
|
||||
*/
|
||||
public SaLoginModel build() {
|
||||
return build(SaTokenManager.getConfig());
|
||||
return build(SaManager.getConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
package cn.dev33.satoken.stp;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.annotation.SaCheckLogin;
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaCheckRole;
|
||||
import cn.dev33.satoken.annotation.SaMode;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.context.model.SaRequest;
|
||||
import cn.dev33.satoken.context.model.SaResponse;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
@@ -23,8 +23,8 @@ import cn.dev33.satoken.exception.NotRoleException;
|
||||
import cn.dev33.satoken.fun.SaFunction;
|
||||
import cn.dev33.satoken.session.SaSession;
|
||||
import cn.dev33.satoken.session.TokenSign;
|
||||
import cn.dev33.satoken.util.SaFoxUtil;
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
import cn.dev33.satoken.util.SaTokenInsideUtil;
|
||||
|
||||
/**
|
||||
* sa-token 权限验证,逻辑实现类
|
||||
@@ -46,7 +46,7 @@ public class StpLogic {
|
||||
public StpLogic(String loginKey) {
|
||||
this.loginKey = loginKey;
|
||||
// 在 SaTokenManager 中记录下此 StpLogic,以便根据 LoginKey 进行查找此对象
|
||||
SaTokenManager.putStpLogic(this);
|
||||
SaManager.putStpLogic(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ public class StpLogic {
|
||||
* @return 生成的tokenValue
|
||||
*/
|
||||
public String createTokenValue(Object loginId) {
|
||||
return SaTokenManager.getSaTokenAction().createToken(loginId, loginKey);
|
||||
return SaManager.getSaTokenAction().createToken(loginId, loginKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,10 +95,10 @@ public class StpLogic {
|
||||
public void setTokenValue(String tokenValue, int cookieTimeout){
|
||||
SaTokenConfig config = getConfig();
|
||||
// 将token保存到[存储器]里
|
||||
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
// 判断是否配置了token前缀
|
||||
String tokenPrefix = config.getTokenPrefix();
|
||||
if(SaTokenInsideUtil.isEmpty(tokenPrefix)) {
|
||||
if(SaFoxUtil.isEmpty(tokenPrefix)) {
|
||||
storage.set(splicingKeyJustCreatedSave(), tokenValue);
|
||||
} else {
|
||||
// 如果配置了token前缀,则拼接上前缀一起写入
|
||||
@@ -107,7 +107,7 @@ public class StpLogic {
|
||||
|
||||
// 注入Cookie
|
||||
if(config.getIsReadCookie() == true){
|
||||
SaResponse response = SaTokenManager.getSaTokenContext().getResponse();
|
||||
SaResponse response = SaHolder.getResponse();
|
||||
response.addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), cookieTimeout);
|
||||
}
|
||||
}
|
||||
@@ -118,8 +118,8 @@ public class StpLogic {
|
||||
*/
|
||||
public String getTokenValue(){
|
||||
// 0. 获取相应对象
|
||||
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
|
||||
SaRequest request = SaTokenManager.getSaTokenContext().getRequest();
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
SaRequest request = SaHolder.getRequest();
|
||||
SaTokenConfig config = getConfig();
|
||||
String keyTokenName = getTokenName();
|
||||
String tokenValue = null;
|
||||
@@ -143,7 +143,7 @@ public class StpLogic {
|
||||
|
||||
// 5. 如果打开了前缀模式
|
||||
String tokenPrefix = getConfig().getTokenPrefix();
|
||||
if(SaTokenInsideUtil.isEmpty(tokenPrefix) == false && SaTokenInsideUtil.isEmpty(tokenValue) == false) {
|
||||
if(SaFoxUtil.isEmpty(tokenPrefix) == false && SaFoxUtil.isEmpty(tokenValue) == false) {
|
||||
// 如果token以指定的前缀开头, 则裁剪掉它, 否则视为未提供token
|
||||
if(tokenValue.startsWith(tokenPrefix + SaTokenConsts.TOKEN_CONNECTOR_CHAT)) {
|
||||
tokenValue = tokenValue.substring(tokenPrefix.length() + SaTokenConsts.TOKEN_CONNECTOR_CHAT.length());
|
||||
@@ -220,7 +220,7 @@ public class StpLogic {
|
||||
|
||||
// ------ 1、获取相应对象
|
||||
SaTokenConfig config = getConfig();
|
||||
SaTokenDao dao = SaTokenManager.getSaTokenDao();
|
||||
SaTokenDao dao = SaManager.getSaTokenDao();
|
||||
loginModel.build(config);
|
||||
|
||||
// ------ 2、生成一个token
|
||||
@@ -246,7 +246,7 @@ public class StpLogic {
|
||||
// 3. 清理user-session上的token签名记录
|
||||
session.removeTokenSign(tokenSign.getValue());
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doReplaced(loginKey, loginId, tokenSign.getValue(), tokenSign.getDevice());
|
||||
SaManager.getSaTokenListener().doReplaced(loginKey, loginId, tokenSign.getValue(), tokenSign.getDevice());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -277,7 +277,7 @@ public class StpLogic {
|
||||
setTokenValue(tokenValue, loginModel.getCookieTimeout());
|
||||
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doLogin(loginKey, loginId, loginModel);
|
||||
SaManager.getSaTokenListener().doLogin(loginKey, loginId, loginModel);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -291,7 +291,7 @@ public class StpLogic {
|
||||
}
|
||||
// 如果打开了cookie模式,第一步,先把cookie清除掉
|
||||
if(getConfig().getIsReadCookie() == true){
|
||||
SaTokenManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
|
||||
SaHolder.getResponse().deleteCookie(getTokenName());
|
||||
}
|
||||
logoutByTokenValue(tokenValue);
|
||||
}
|
||||
@@ -303,25 +303,28 @@ public class StpLogic {
|
||||
public void logoutByTokenValue(String tokenValue) {
|
||||
// 1. 清理掉[token-最后操作时间]
|
||||
clearLastActivity(tokenValue);
|
||||
|
||||
// 2. 清理Token-Session
|
||||
SaManager.getSaTokenDao().delete(splicingKeyTokenSession(tokenValue));
|
||||
|
||||
// 2. 尝试清除token-id键值对 (先从db中获取loginId值,如果根本查不到loginId,那么无需继续操作 )
|
||||
// 3. 尝试清除token-id键值对 (先从db中获取loginId值,如果根本查不到loginId,那么无需继续操作 )
|
||||
String loginId = getLoginIdNotHandle(tokenValue);
|
||||
if(loginId == null || NotLoginException.ABNORMAL_LIST.contains(loginId)) {
|
||||
return;
|
||||
}
|
||||
SaTokenManager.getSaTokenDao().delete(splicingKeyTokenValue(tokenValue));
|
||||
SaManager.getSaTokenDao().delete(splicingKeyTokenValue(tokenValue));
|
||||
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doLogout(loginKey, loginId, tokenValue);
|
||||
|
||||
// 3. 尝试清理账号session上的token签名 (如果为null或已被标记为异常, 那么无需继续执行 )
|
||||
SaManager.getSaTokenListener().doLogout(loginKey, loginId, tokenValue);
|
||||
|
||||
// 4. 尝试清理User-Session上的token签名 (如果为null或已被标记为异常, 那么无需继续执行 )
|
||||
SaSession session = getSessionByLoginId(loginId, false);
|
||||
if(session == null) {
|
||||
return;
|
||||
}
|
||||
session.removeTokenSign(tokenValue);
|
||||
|
||||
// 4. 尝试注销session
|
||||
// 5. 尝试注销User-Session
|
||||
session.logoutByTokenSignCountToZero();
|
||||
}
|
||||
|
||||
@@ -356,11 +359,11 @@ public class StpLogic {
|
||||
// 2. 清理掉[token-最后操作时间]
|
||||
clearLastActivity(tokenValue);
|
||||
// 3. 标记:已被踢下线
|
||||
SaTokenManager.getSaTokenDao().update(splicingKeyTokenValue(tokenValue), NotLoginException.KICK_OUT);
|
||||
SaManager.getSaTokenDao().update(splicingKeyTokenValue(tokenValue), NotLoginException.KICK_OUT);
|
||||
// 4. 清理账号session上的token签名
|
||||
session.removeTokenSign(tokenValue);
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doLogoutByLoginId(loginKey, loginId, tokenValue, tokenSign.getDevice());
|
||||
SaManager.getSaTokenListener().doLogoutByLoginId(loginKey, loginId, tokenValue, tokenSign.getDevice());
|
||||
}
|
||||
}
|
||||
// 3. 尝试注销session
|
||||
@@ -375,10 +378,10 @@ public class StpLogic {
|
||||
*/
|
||||
public void disable(Object loginId, long disableTime) {
|
||||
// 标注为已被封禁
|
||||
SaTokenManager.getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime);
|
||||
SaManager.getSaTokenDao().set(splicingKeyDisable(loginId), DisableLoginException.BE_VALUE, disableTime);
|
||||
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doDisable(loginKey, loginId, disableTime);
|
||||
SaManager.getSaTokenListener().doDisable(loginKey, loginId, disableTime);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -387,7 +390,7 @@ public class StpLogic {
|
||||
* @return see note
|
||||
*/
|
||||
public boolean isDisable(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
|
||||
return SaManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -396,7 +399,7 @@ public class StpLogic {
|
||||
* @return see note
|
||||
*/
|
||||
public long getDisableTime(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyDisable(loginId));
|
||||
return SaManager.getSaTokenDao().getTimeout(splicingKeyDisable(loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -404,10 +407,10 @@ public class StpLogic {
|
||||
* @param loginId 账号id
|
||||
*/
|
||||
public void untieDisable(Object loginId) {
|
||||
SaTokenManager.getSaTokenDao().delete(splicingKeyDisable(loginId));
|
||||
SaManager.getSaTokenDao().delete(splicingKeyDisable(loginId));
|
||||
|
||||
// $$ 通知监听器
|
||||
SaTokenManager.getSaTokenListener().doUntieDisable(loginKey, loginId);
|
||||
SaManager.getSaTokenListener().doUntieDisable(loginKey, loginId);
|
||||
}
|
||||
|
||||
|
||||
@@ -460,9 +463,10 @@ public class StpLogic {
|
||||
if(loginId.equals(NotLoginException.KICK_OUT)) {
|
||||
throw NotLoginException.newInstance(loginKey, NotLoginException.KICK_OUT);
|
||||
}
|
||||
// 如果配置了自动续签, 则: 检查是否已经 [临时过期],同时更新[最后操作时间]
|
||||
// 检查是否已经 [临时过期]
|
||||
checkActivityTimeout(tokenValue);
|
||||
// 如果配置了自动续签, 则: 更新[最后操作时间]
|
||||
if(getConfig().getAutoRenew()) {
|
||||
checkActivityTimeout(tokenValue);
|
||||
updateLastActivityToNow(tokenValue);
|
||||
}
|
||||
// 至此,返回loginId
|
||||
@@ -564,7 +568,7 @@ public class StpLogic {
|
||||
* @return loginId
|
||||
*/
|
||||
public String getLoginIdNotHandle(String tokenValue) {
|
||||
return SaTokenManager.getSaTokenDao().get(splicingKeyTokenValue(tokenValue));
|
||||
return SaManager.getSaTokenDao().get(splicingKeyTokenValue(tokenValue));
|
||||
}
|
||||
|
||||
|
||||
@@ -577,10 +581,10 @@ public class StpLogic {
|
||||
* @return session对象
|
||||
*/
|
||||
public SaSession getSessionBySessionId(String sessionId, boolean isCreate) {
|
||||
SaSession session = SaTokenManager.getSaTokenDao().getSession(sessionId);
|
||||
SaSession session = SaManager.getSaTokenDao().getSession(sessionId);
|
||||
if(session == null && isCreate) {
|
||||
session = SaTokenManager.getSaTokenAction().createSession(sessionId);
|
||||
SaTokenManager.getSaTokenDao().setSession(session, getConfig().getTimeout());
|
||||
session = SaManager.getSaTokenAction().createSession(sessionId);
|
||||
SaManager.getSaTokenDao().setSession(session, getConfig().getTimeout());
|
||||
}
|
||||
return session;
|
||||
}
|
||||
@@ -699,7 +703,7 @@ public class StpLogic {
|
||||
return;
|
||||
}
|
||||
// 将[最后操作时间]标记为当前时间戳
|
||||
SaTokenManager.getSaTokenDao().set(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout());
|
||||
SaManager.getSaTokenDao().set(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), getConfig().getTimeout());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -712,9 +716,9 @@ public class StpLogic {
|
||||
return;
|
||||
}
|
||||
// 删除[最后操作时间]
|
||||
SaTokenManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
|
||||
SaManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
|
||||
// 清除标记
|
||||
SaTokenManager.getSaTokenContext().getStorage().delete((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
|
||||
SaHolder.getStorage().delete((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -727,7 +731,7 @@ public class StpLogic {
|
||||
return;
|
||||
}
|
||||
// 如果本次请求已经有了[检查标记], 则立即返回
|
||||
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
|
||||
SaStorage storage = SaHolder.getStorage();
|
||||
if(storage.get(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
|
||||
return;
|
||||
}
|
||||
@@ -764,7 +768,7 @@ public class StpLogic {
|
||||
if(tokenValue == null || getConfig().getActivityTimeout() == SaTokenDao.NEVER_EXPIRE) {
|
||||
return;
|
||||
}
|
||||
SaTokenManager.getSaTokenDao().update(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
|
||||
SaManager.getSaTokenDao().update(splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -784,7 +788,7 @@ public class StpLogic {
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenTimeout() {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
|
||||
return SaManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -793,7 +797,7 @@ public class StpLogic {
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenTimeoutByLoginId(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValueByLoginId(loginId)));
|
||||
return SaManager.getSaTokenDao().getTimeout(splicingKeyTokenValue(getTokenValueByLoginId(loginId)));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -810,7 +814,7 @@ public class StpLogic {
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getSessionTimeoutByLoginId(Object loginId) {
|
||||
return SaTokenManager.getSaTokenDao().getSessionTimeout(splicingKeySession(loginId));
|
||||
return SaManager.getSaTokenDao().getSessionTimeout(splicingKeySession(loginId));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -827,7 +831,7 @@ public class StpLogic {
|
||||
* @return token剩余有效时间
|
||||
*/
|
||||
public long getTokenSessionTimeoutByTokenValue(String tokenValue) {
|
||||
return SaTokenManager.getSaTokenDao().getSessionTimeout(splicingKeyTokenSession(tokenValue));
|
||||
return SaManager.getSaTokenDao().getSessionTimeout(splicingKeyTokenSession(tokenValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,7 +859,7 @@ public class StpLogic {
|
||||
// ------ 开始查询
|
||||
// 获取相关数据
|
||||
String keyLastActivityTime = splicingKeyLastActivityTime(tokenValue);
|
||||
String lastActivityTimeString = SaTokenManager.getSaTokenDao().get(keyLastActivityTime);
|
||||
String lastActivityTimeString = SaManager.getSaTokenDao().get(keyLastActivityTime);
|
||||
// 查不到,返回-2
|
||||
if(lastActivityTimeString == null) {
|
||||
return SaTokenDao.NOT_VALUE_EXPIRE;
|
||||
@@ -881,8 +885,9 @@ public class StpLogic {
|
||||
* @return 是否含有指定角色标识
|
||||
*/
|
||||
public boolean hasRole(Object loginId, String role) {
|
||||
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
return !(roleList == null || roleList.contains(role) == false);
|
||||
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
return SaManager.getSaTokenAction().hasElement(roleList, role);
|
||||
// return !(roleList == null || roleList.contains(role) == false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -910,9 +915,9 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkRoleAnd(String... roleArray){
|
||||
Object loginId = getLoginId();
|
||||
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
for (String role : roleArray) {
|
||||
if(roleList.contains(role) == false) {
|
||||
if(SaManager.getSaTokenAction().hasElement(roleList, role) == false) {
|
||||
throw new NotRoleException(role, this.loginKey);
|
||||
}
|
||||
}
|
||||
@@ -924,9 +929,9 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkRoleOr(String... roleArray){
|
||||
Object loginId = getLoginId();
|
||||
List<String> roleList = SaTokenManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
List<String> roleList = SaManager.getStpInterface().getRoleList(loginId, loginKey);
|
||||
for (String role : roleArray) {
|
||||
if(roleList.contains(role) == true) {
|
||||
if(SaManager.getSaTokenAction().hasElement(roleList, role) == true) {
|
||||
// 有的话提前退出
|
||||
return;
|
||||
}
|
||||
@@ -946,8 +951,9 @@ public class StpLogic {
|
||||
* @return 是否含有指定权限
|
||||
*/
|
||||
public boolean hasPermission(Object loginId, String permission) {
|
||||
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
return !(permissionList == null || permissionList.contains(permission) == false);
|
||||
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
return SaManager.getSaTokenAction().hasElement(permissionList, permission);
|
||||
// return !(permissionList == null || permissionList.contains(permission) == false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -975,9 +981,9 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkPermissionAnd(String... permissionArray){
|
||||
Object loginId = getLoginId();
|
||||
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
for (String permission : permissionArray) {
|
||||
if(permissionList.contains(permission) == false) {
|
||||
if(SaManager.getSaTokenAction().hasElement(permissionList, permission) == false) {
|
||||
throw new NotPermissionException(permission, this.loginKey);
|
||||
}
|
||||
}
|
||||
@@ -989,9 +995,9 @@ public class StpLogic {
|
||||
*/
|
||||
public void checkPermissionOr(String... permissionArray){
|
||||
Object loginId = getLoginId();
|
||||
List<String> permissionList = SaTokenManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
List<String> permissionList = SaManager.getStpInterface().getPermissionList(loginId, loginKey);
|
||||
for (String permission : permissionArray) {
|
||||
if(permissionList.contains(permission) == true) {
|
||||
if(SaManager.getSaTokenAction().hasElement(permissionList, permission) == true) {
|
||||
// 有的话提前退出
|
||||
return;
|
||||
}
|
||||
@@ -1100,7 +1106,7 @@ public class StpLogic {
|
||||
* @return token集合
|
||||
*/
|
||||
public List<String> searchTokenValue(String keyword, int start, int size) {
|
||||
return SaTokenManager.getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size);
|
||||
return SaManager.getSaTokenDao().searchData(splicingKeyTokenValue(""), keyword, start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1111,7 +1117,7 @@ public class StpLogic {
|
||||
* @return sessionId集合
|
||||
*/
|
||||
public List<String> searchSessionId(String keyword, int start, int size) {
|
||||
return SaTokenManager.getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size);
|
||||
return SaManager.getSaTokenDao().searchData(splicingKeySession(""), keyword, start, size);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1122,7 +1128,7 @@ public class StpLogic {
|
||||
* @return sessionId集合
|
||||
*/
|
||||
public List<String> searchTokenSessionId(String keyword, int start, int size) {
|
||||
return SaTokenManager.getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size);
|
||||
return SaManager.getSaTokenDao().searchData(splicingKeyTokenSession(""), keyword, start, size);
|
||||
}
|
||||
|
||||
|
||||
@@ -1205,68 +1211,44 @@ public class StpLogic {
|
||||
*/
|
||||
public SaTokenConfig getConfig() {
|
||||
// 为什么再次代理一层? 为某些极端业务场景下[需要不同StpLogic不同配置]提供便利
|
||||
return SaTokenManager.getConfig();
|
||||
return SaManager.getConfig();
|
||||
}
|
||||
|
||||
|
||||
// =================== 其它方法 ===================
|
||||
|
||||
/**
|
||||
* 根据注解(@SaCheckLogin)鉴权
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckLogin at) {
|
||||
this.checkLogin();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据注解(@SaCheckRole)鉴权
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkByAnnotation(SaCheckRole at) {
|
||||
String[] roleArray = at.value();
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对一个Method对象进行注解检查(注解鉴权内部实现)
|
||||
* @param method Method对象
|
||||
* 根据注解(@SaCheckPermission)鉴权
|
||||
* @param at 注解对象
|
||||
*/
|
||||
public void checkMethodAnnotation(Method method) {
|
||||
|
||||
// ----------- 验证登录
|
||||
if(method.isAnnotationPresent(SaCheckLogin.class) || method.getDeclaringClass().isAnnotationPresent(SaCheckLogin.class)) {
|
||||
this.checkLogin();
|
||||
public void checkByAnnotation(SaCheckPermission at) {
|
||||
String[] permissionArray = at.value();
|
||||
if(at.mode() == SaMode.AND) {
|
||||
this.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
this.checkPermissionOr(permissionArray);
|
||||
}
|
||||
|
||||
// ----------- 验证角色
|
||||
// 验证方法上的
|
||||
SaCheckRole scr = method.getAnnotation(SaCheckRole.class);
|
||||
if(scr != null) {
|
||||
String[] roleArray = scr.value();
|
||||
if(scr.mode() == SaMode.AND) {
|
||||
this.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
// 验证类上的
|
||||
scr = method.getDeclaringClass().getAnnotation(SaCheckRole.class);
|
||||
if(scr != null) {
|
||||
String[] roleArray = scr.value();
|
||||
if(scr.mode() == SaMode.AND) {
|
||||
this.checkRoleAnd(roleArray);
|
||||
} else {
|
||||
this.checkRoleOr(roleArray);
|
||||
}
|
||||
}
|
||||
|
||||
// ----------- 验证权限
|
||||
// 验证方法上的
|
||||
SaCheckPermission scp = method.getAnnotation(SaCheckPermission.class);
|
||||
if(scp != null) {
|
||||
String[] permissionArray = scp.value();
|
||||
if(scp.mode() == SaMode.AND) {
|
||||
this.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
this.checkPermissionOr(permissionArray);
|
||||
}
|
||||
}
|
||||
// 验证类上的
|
||||
scp = method.getDeclaringClass().getAnnotation(SaCheckPermission.class);
|
||||
if(scp != null) {
|
||||
String[] permissionArray = scp.value();
|
||||
if(scp.mode() == SaMode.AND) {
|
||||
this.checkPermissionAnd(permissionArray);
|
||||
} else {
|
||||
this.checkPermissionOr(permissionArray);
|
||||
}
|
||||
}
|
||||
|
||||
// 验证通过
|
||||
}
|
||||
|
||||
|
||||
@@ -1277,14 +1259,14 @@ public class StpLogic {
|
||||
* @param loginId 指定loginId
|
||||
*/
|
||||
public void switchTo(Object loginId) {
|
||||
SaTokenManager.getSaTokenContext().getStorage().set(splicingKeySwitch(), loginId);
|
||||
SaHolder.getStorage().set(splicingKeySwitch(), loginId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 结束临时切换身份
|
||||
*/
|
||||
public void endSwitch() {
|
||||
SaTokenManager.getSaTokenContext().getStorage().delete(splicingKeySwitch());
|
||||
SaHolder.getStorage().delete(splicingKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1292,7 +1274,7 @@ public class StpLogic {
|
||||
* @return 是否正处于[身份临时切换]中
|
||||
*/
|
||||
public boolean isSwitch() {
|
||||
return SaTokenManager.getSaTokenContext().getStorage().get(splicingKeySwitch()) != null;
|
||||
return SaHolder.getStorage().get(splicingKeySwitch()) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1300,7 +1282,7 @@ public class StpLogic {
|
||||
* @return 返回[身份临时切换]的loginId
|
||||
*/
|
||||
public Object getSwitchLoginId() {
|
||||
return SaTokenManager.getSaTokenContext().getStorage().get(splicingKeySwitch());
|
||||
return SaHolder.getStorage().get(splicingKeySwitch());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,13 +10,17 @@ import cn.dev33.satoken.session.SaSession;
|
||||
* @author kong
|
||||
*/
|
||||
public class StpUtil {
|
||||
|
||||
|
||||
/**
|
||||
* 账号体系标识
|
||||
*/
|
||||
public static final String KEY = "login";
|
||||
|
||||
/**
|
||||
* 底层的 StpLogic 对象
|
||||
*/
|
||||
public static StpLogic stpLogic = new StpLogic("login");
|
||||
public static StpLogic stpLogic = new StpLogic(KEY);
|
||||
|
||||
|
||||
/**
|
||||
* 获取当前StpLogin的loginKey
|
||||
* @return 当前StpLogin的loginKey
|
||||
|
||||
@@ -7,14 +7,15 @@ import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* sa-token 内部代码工具类
|
||||
* Sa-Token 内部工具类
|
||||
*
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
public class SaTokenInsideUtil {
|
||||
public class SaFoxUtil {
|
||||
|
||||
/**
|
||||
* 打印 sa-token 版本字符画
|
||||
@@ -129,4 +130,21 @@ public class SaTokenInsideUtil {
|
||||
return list2;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串模糊匹配
|
||||
* <p>example:
|
||||
* <p> user* user-add -- true
|
||||
* <p> user* art-add -- false
|
||||
* @param patt 表达式
|
||||
* @param str 待匹配的字符串
|
||||
* @return 是否可以匹配
|
||||
*/
|
||||
public static boolean vagueMatch(String patt, String str) {
|
||||
// 如果表达式不带有*号,则只需简单equals即可 (速度提升200倍)
|
||||
if(patt.indexOf("*") == -1) {
|
||||
return patt.equals(str);
|
||||
}
|
||||
return Pattern.matches(patt.replaceAll("\\*", ".*"), str);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,7 +13,7 @@ public class SaTokenConsts {
|
||||
/**
|
||||
* sa-token 当前版本号
|
||||
*/
|
||||
public static final String VERSION_NO = "v1.17.0";
|
||||
public static final String VERSION_NO = "v1.19.0";
|
||||
|
||||
/**
|
||||
* sa-token 开源地址
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
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.interceptor.SaAnnotationInterceptor;
|
||||
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 注册sa-token的拦截器,打开注解式鉴权功能
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册注解拦截器
|
||||
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**").excludePathPatterns("");
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 注册 [sa-token全局过滤器]
|
||||
// */
|
||||
// @Bean
|
||||
// public SaServletFilter getSaReactorFilter() {
|
||||
// return new SaServletFilter()
|
||||
// // 指定 [拦截路由]
|
||||
// .addInclude("/**")
|
||||
// // 指定 [放行路由]
|
||||
// .addExclude("/favicon.ico")
|
||||
// // 指定[认证函数]: 每次请求执行
|
||||
// .setAuth(r -> {
|
||||
// System.out.println("---------- sa全局认证");
|
||||
// SaRouterUtil.match("/test/test", () -> StpUtil.checkLogin());
|
||||
// })
|
||||
// // 指定[异常处理函数]:每次[认证函数]发生异常时执行此函数
|
||||
// .setError(e -> {
|
||||
// System.out.println("---------- sa全局异常 ");
|
||||
// return AjaxJson.getError(e.getMessage());
|
||||
// })
|
||||
// ;
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.17.0</sa-token-version>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -3,14 +3,14 @@ package com.pj;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SaTokenJwtDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenJwtDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import java.util.Date;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
import cn.dev33.satoken.config.SaTokenConfig;
|
||||
import cn.dev33.satoken.context.model.SaStorage;
|
||||
import cn.dev33.satoken.dao.SaTokenDao;
|
||||
@@ -124,13 +124,13 @@ public class SaTokenJwtUtil {
|
||||
@Override
|
||||
public void setLoginId(Object loginId, SaLoginModel loginModel) {
|
||||
// ------ 1、获取相应对象
|
||||
SaStorage storage = SaTokenManager.getSaTokenContext().getStorage();
|
||||
SaStorage storage = SaManager.getSaTokenContext().getStorage();
|
||||
SaTokenConfig config = getConfig();
|
||||
// ------ 2、生成一个token
|
||||
String tokenValue = createTokenValue(loginId);
|
||||
storage.set(splicingKeyJustCreatedSave(), tokenValue); // 将token保存到本次request里
|
||||
if(config.getIsReadCookie() == true){ // cookie注入
|
||||
SaTokenManager.getSaTokenContext().getResponse().addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), (int)config.getTimeout());
|
||||
SaManager.getSaTokenContext().getResponse().addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), (int)config.getTimeout());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ public class SaTokenJwtUtil {
|
||||
}
|
||||
// 如果打开了cookie模式,把cookie清除掉
|
||||
if(getConfig().getIsReadCookie() == true){
|
||||
SaTokenManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
|
||||
SaManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +71,10 @@ public class TestJwtController {
|
||||
// 测试 浏览器访问: http://localhost:8081/test/test
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test() {
|
||||
StpUtil.getTokenSession().logout();
|
||||
StpUtil.logoutByLoginId(10001);
|
||||
System.out.println();
|
||||
System.out.println("--------------进入请求--------------");
|
||||
StpUtil.setLoginId(10001);
|
||||
System.out.println(StpUtil.getTokenInfo().getTokenValue());
|
||||
return AjaxJson.getSuccess();
|
||||
}
|
||||
|
||||
68
sa-token-demo/sa-token-demo-quick-login/pom.xml
Normal file
68
sa-token-demo/sa-token-demo-quick-login/pom.xml
Normal file
@@ -0,0 +1,68 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-demo-quick-login</artifactId>
|
||||
<version>0.0.1-SNAPSHOT</version>
|
||||
|
||||
<!-- SpringBoot -->
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.0.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- springboot依赖 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>${sa-token-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- quick-login -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-quick-login</artifactId>
|
||||
<version>${sa-token-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- @ConfigurationProperties -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- 热更新插件 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-devtools</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.pj;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.dev33.satoken.quick.SaQuickManager;
|
||||
|
||||
/**
|
||||
* springboot启动之后
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class SaQuicikStartup implements CommandLineRunner {
|
||||
|
||||
@Value("${spring.application.name:sa-quick}")
|
||||
private String applicationName;
|
||||
|
||||
@Value("${server.port:8080}")
|
||||
private String port;
|
||||
|
||||
@Value("${server.servlet.context-path:}")
|
||||
private String path;
|
||||
|
||||
// @Value("${spring.profiles.active:}")
|
||||
// private String active;
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
String str = "\n------------- " + applicationName + " 启动成功 (" + getNow() + ") -------------\n" +
|
||||
" - home: " + "http://localhost:" + port + path + "\n" +
|
||||
" - name: " + SaQuickManager.getConfig().getName() + "\n"+
|
||||
" - pwd : " + SaQuickManager.getConfig().getPwd() + "\n";
|
||||
System.out.println(str);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 返回系统当前时间的YYYY-MM-dd hh:mm:ss 字符串格式
|
||||
*/
|
||||
private static String getNow(){
|
||||
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.pj;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SaTokenQuickDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenQuickDemoApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.pj.test;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.dev33.satoken.util.SaTokenConsts;
|
||||
|
||||
/**
|
||||
* 测试专用Controller
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@RestController
|
||||
public class TestController {
|
||||
|
||||
// 浏览器访问测试: http://localhost:8081
|
||||
@RequestMapping({"/"})
|
||||
public String login(String username, String password) {
|
||||
String str = "<br />"
|
||||
// + "<h1 style='text-align: center;'>Welcome to the system</h1>"
|
||||
+ "<h1 style='text-align: center;'>资源页 (登录后才可进入本页面) </h1>"
|
||||
+ "<hr/>"
|
||||
+ "<p style='text-align: center;'> Sa-Token " + SaTokenConsts.VERSION_NO + " </p>";
|
||||
return str;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
# 端口
|
||||
server:
|
||||
port: 8081
|
||||
|
||||
# Sa-Token-Quick-Login 配置
|
||||
sa:
|
||||
# 登录账号
|
||||
name: sa
|
||||
# 登录密码
|
||||
pwd: 123456
|
||||
# 是否自动随机生成账号密码 (此项为true时, name与pwd失效)
|
||||
auto: false
|
||||
# 是否开启全局认证(关闭后将不再强行拦截)
|
||||
auth: true
|
||||
# 登录页标题
|
||||
title: Sa-Token 登录
|
||||
# 是否显示底部版权信息
|
||||
copr: true
|
||||
# 将本地磁盘的某个路径作为静态资源开放
|
||||
# dir: file:E:\static
|
||||
|
||||
|
||||
# 静态文件路径映射
|
||||
spring:
|
||||
resources:
|
||||
static-locations: classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/, ${sa.dir:}
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.17.0</sa-token-version>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -3,7 +3,7 @@ package com.pj;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* sa-token整合SpringBoot 示例
|
||||
@@ -15,7 +15,7 @@ public class SaTokenDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.pj.satoken;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import com.pj.util.AjaxJson;
|
||||
|
||||
import cn.dev33.satoken.context.SaHolder;
|
||||
import cn.dev33.satoken.filter.SaServletFilter;
|
||||
import cn.dev33.satoken.interceptor.SaAnnotationInterceptor;
|
||||
|
||||
|
||||
/**
|
||||
* [Sa-Token 权限认证] 配置类
|
||||
* @author kong
|
||||
*
|
||||
*/
|
||||
@Configuration
|
||||
public class SaTokenConfigure implements WebMvcConfigurer {
|
||||
|
||||
/**
|
||||
* 注册sa-token的拦截器,打开注解式鉴权功能
|
||||
*/
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 注册注解拦截器
|
||||
registry.addInterceptor(new SaAnnotationInterceptor()).addPathPatterns("/**").excludePathPatterns("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册 [sa-token全局过滤器]
|
||||
*/
|
||||
@Bean
|
||||
public SaServletFilter getSaServletFilter() {
|
||||
return new SaServletFilter()
|
||||
|
||||
// 指定 [拦截路由] 与 [放行路由]
|
||||
.addInclude("/**").addExclude("/favicon.ico")
|
||||
|
||||
// 认证函数: 每次请求执行
|
||||
.setAuth(r -> {
|
||||
// System.out.println("---------- sa全局认证");
|
||||
|
||||
// SaRouterUtil.match("/test/test", () -> new Object());
|
||||
})
|
||||
|
||||
// 异常处理函数:每次认证函数发生异常时执行此函数
|
||||
.setError(e -> {
|
||||
System.out.println("---------- sa全局异常 ");
|
||||
return AjaxJson.getError(e.getMessage());
|
||||
})
|
||||
|
||||
// 前置函数:在每次认证函数之前执行
|
||||
.setBeforeAuth(r -> {
|
||||
// ---------- 设置一些安全响应头 ----------
|
||||
SaHolder.getResponse()
|
||||
// 服务器名称
|
||||
.setServer("sa-server")
|
||||
// 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
|
||||
.setHeader("X-Frame-Options", "SAMEORIGIN")
|
||||
// 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面
|
||||
.setHeader("X-Frame-Options", "1; mode=block")
|
||||
// 禁用浏览器内容嗅探
|
||||
.setHeader("X-Content-Type-Options", "nosniff")
|
||||
;
|
||||
})
|
||||
;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -241,8 +241,7 @@ public class TestController {
|
||||
@RequestMapping("test")
|
||||
public AjaxJson test() {
|
||||
System.out.println("进来了");
|
||||
StpUtil.disable(10001, 10002);
|
||||
StpUtil.untieDisable(10001);
|
||||
System.out.println(StpUtil.getTokenInfo());
|
||||
return AjaxJson.getSuccess("访问成功");
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ spring:
|
||||
# 是否输出操作日志
|
||||
is-log: false
|
||||
|
||||
|
||||
# redis配置
|
||||
redis:
|
||||
# Redis数据库索引(默认为0)
|
||||
@@ -44,4 +43,7 @@ spring:
|
||||
# 连接池中的最小空闲连接
|
||||
min-idle: 0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
12
sa-token-demo/sa-token-demo-webflux/.gitignore
vendored
Normal file
12
sa-token-demo/sa-token-demo-webflux/.gitignore
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
target/
|
||||
|
||||
node_modules/
|
||||
bin/
|
||||
.settings/
|
||||
unpackage/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
.idea/
|
||||
|
||||
.factorypath
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<!-- 定义sa-token版本号 -->
|
||||
<properties>
|
||||
<sa-token-version>1.17.0</sa-token-version>
|
||||
<sa-token-version>1.19.0</sa-token-version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -14,7 +14,7 @@ package com.pj;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
import cn.dev33.satoken.SaTokenManager;
|
||||
import cn.dev33.satoken.SaManager;
|
||||
|
||||
/**
|
||||
* sa-token整合webflux 示例
|
||||
@@ -26,7 +26,7 @@ public class SaTokenWebfluxDemoApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenWebfluxDemoApplication.class, args);
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
System.out.println("\n启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<p align="center">
|
||||
<img alt="logo" src="https://gitee.com/dromara/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.17.0</h1>
|
||||
<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">sa-token v1.19.0</h1>
|
||||
<h4 align="center">这可能是史上功能最全的 Java 权限认证框架!</h4>
|
||||
<h4 align="center">
|
||||
<a href="https://gitee.com/dromara/sa-token/stargazers"><img src="https://gitee.com/dromara/sa-token/badge/star.svg"></a>
|
||||
@@ -91,6 +91,7 @@ StpUtil.checkLogin();
|
||||
当你受够Shiro、Security等框架的三拜九叩之后,你就会明白,相对于这些传统老牌框架,sa-token的API设计是多么的清爽!
|
||||
|
||||
权限认证示例 (只有具有`user:add`权限的会话才可以进入请求)
|
||||
|
||||
``` java
|
||||
@SaCheckPermission("user:add")
|
||||
@RequestMapping("/user/insert")
|
||||
@@ -150,6 +151,7 @@ sa-token秉承着开放的思想,欢迎大家为框架添砖加瓦:
|
||||
|
||||
[**[ jthink]** 一个基于springboot+sa-token+thymeleaf的博客系统](https://gitee.com/wtsoftware/jthink)
|
||||
|
||||
[**[ dcy-fast]** 一个基于springboot+sa-token+mybatis-plus的后台管理系统,前端vue-element-admin,并且内置代码生成器](https://gitee.com/dcy421/dcy-fast)
|
||||
|
||||
如果您的项目使用了sa-token,欢迎提交pr
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
- [在WebFlux环境集成](/start/webflux-example)
|
||||
|
||||
- **基础**
|
||||
- [登录验证](/use/login-auth)
|
||||
- [权限验证](/use/jur-auth)
|
||||
- [登录认证](/use/login-auth)
|
||||
- [权限认证](/use/jur-auth)
|
||||
- [Session会话](/use/session)
|
||||
- [踢人下线](/use/kick)
|
||||
- [注解式鉴权](/use/at-check)
|
||||
@@ -33,6 +33,10 @@
|
||||
- [单点登录](/senior/sso)
|
||||
- [多账号验证](/use/many-account)
|
||||
|
||||
- **插件**
|
||||
- [AOP注解鉴权](/plugin/aop-at)
|
||||
- [Quick-Login快速登录插件](/plugin/quick-login)
|
||||
|
||||
- **其它**
|
||||
- [常见问题](/more/common-questions)
|
||||
- [更新日志](/more/update-log)
|
||||
@@ -45,6 +49,7 @@
|
||||
- [Session模型详解](/fun/session-model)
|
||||
- [TokenInfo参数详解](/fun/token-info)
|
||||
- [框架源码所有技术栈](/fun/tech-stack)
|
||||
<!-- - [Web开发常见漏洞防护](/fun/web-loophole) -->
|
||||
<!-- - [Sa-Token大事记](/fun/timeline) -->
|
||||
|
||||
|
||||
|
||||
112
sa-token-doc/doc/fun/web-loophole.md
Normal file
112
sa-token-doc/doc/fun/web-loophole.md
Normal file
@@ -0,0 +1,112 @@
|
||||
# Web开发常见漏洞防护
|
||||
本章介绍web开发时常见漏洞的防护方法
|
||||
|
||||
|
||||
### 点击劫持
|
||||
|
||||
简而言之,点击劫持就是攻击者会自己搭建一个网页,这个网页分为两层:
|
||||
- 上层是被iframe导入的被攻击网站,具有一些敏感性操作,比如转账、点赞等按钮,这一层会完全透明
|
||||
- 下层是攻击者自己精心制作的网页,它会准备一个按钮诱导你进行点击(比如点击领取红包等),当你点击这个按钮时,响应你的将不会是这个按钮,而是上层的转账页面,在不知情的情况下造成财产损失
|
||||
|
||||
详情介绍参考:[https://blog.csdn.net/qq_32523587/article/details/79613768](https://blog.csdn.net/qq_32523587/article/details/79613768)
|
||||
|
||||
防范点击劫持的最有效做法就是增加响应头:`X-Frame-Options: DENY`, 告诉浏览器我们的网站不可以通过 iframe 进行展示(浏览器收到此响应头的指示之后,会拒绝渲染页面),
|
||||
从根本上杜绝了点击劫持发生的可能,在 [全局过滤器](/use/global-filter) 章节的示例中,我们已经展示了如何在过滤器中增加安全响应头
|
||||
|
||||
响应头`X-Frame-Options`有三个取值:
|
||||
- `DENY`: 任何时候都不可以通过 iframe 展示视图
|
||||
- `SAMEORIGIN`: 在同域下可以通过 iframe 展示视图
|
||||
- `ALLOW-FROM uri`: 指定地址来源的访问下可以通过 iframe 展示视图
|
||||
|
||||
除了后端的响应头,我们还可以在前端使用如下方式进行判断:
|
||||
``` js
|
||||
// 判断当前页面是否在顶层视口打开
|
||||
if(top != window) {
|
||||
// 跳入一个安全页面,比如404页
|
||||
location.href="xxx";
|
||||
}
|
||||
```
|
||||
除了跳转页面,你还可以用其它方法防御点击劫持,比如加载一个全局遮罩来隔离用户的点击操作,或者在非顶层窗口下拒绝提交token,使用户保持未登录状态
|
||||
|
||||
|
||||
### XSS攻击
|
||||
|
||||
XSS(跨站脚本攻击)就是指攻击者在一段正常的内容中嵌入恶意脚本,使得访问网页的用户自动运行一些破坏性的代码
|
||||
|
||||
例如一个论坛具有发帖功能,攻击者在发帖时故意插入一段如下内容:
|
||||
``` java
|
||||
<img src="xxx" onerror="alert('xss攻击!')" />
|
||||
```
|
||||
如果论坛服务端没有对此进行任何防护,那么用户每次访问这个帖子的时候都会被强制弹窗,
|
||||
事实上真正的`XSS攻击`绝不只是弹窗骚扰一下那么简单,它可以完成窃取Cookie,自动转账等破坏性操作
|
||||
|
||||
防范XSS攻击:
|
||||
1. 首先安全响应头给安排上:`X-Frame-Options: 1; mode=block`, 这是浏览器默认提供的XSS防护机制
|
||||
2. 有条件的情况下,尽量使用前后台分离架构,传统服务端渲染视图时几乎每一个变量都可能成为XSS注入点,而前后台分离下一般只有富文本渲染才会有机会XSS注入
|
||||
3. 对所有的用户输入必须XSS过滤,特别是字符串型参数
|
||||
4. 可以使用一些自动扫描工具寻找潜在的 XSS 漏洞
|
||||
|
||||
|
||||
### CSRF攻击
|
||||
CSRF(跨站请求伪造),又称 XSRF,攻击流程如下:
|
||||
|
||||
1. 用户登陆站点`a.com`,身份令牌被写入Cookie中
|
||||
2. 攻击者搭建站点`b.com`,引诱用户访问
|
||||
3. 用户访问`b.com`时,自动执行了攻击者准备的js代码,即:调用`a.com`的转账接口
|
||||
4. 用户在不知情的情况下,造成了财产损失
|
||||
|
||||
仅仅访问一个不安全的站点就让我们造成了财产损失?事实上,真正的CSRF攻击并没有这么简单,挡在攻击者第一道门槛便是`CORS同源策略`
|
||||
|
||||
同源策略限制了js在`b.com`中只能操作`b.com`的数据(`Cookie`、`localStorage`、`DOM`等),而无法直接操作`a.com`的数据。
|
||||
|
||||
这就导致一个结果:虽然在`b.com`可以调用`a.com`的转账接口,但是却无法携带用户储存在`a.com`的授权Cookie,对于`a.com`来讲,即使收到了浏览器发来的请求,
|
||||
也因为请求中没有携带token令牌,而无法识别调用者具体是谁,只能将其视为一次无效调用。
|
||||
|
||||
但是,请注意!这个小小的限制,虽然为用户提供了安全保护,却也为我们开发者造成了不小的困扰,特别是在前后端分离架构下,我们经常会遇到这个错误:
|
||||
|
||||

|
||||
|
||||
这就是导致无数前端后端互相撕逼的 —— 跨域!
|
||||
|
||||
浏览器在检测到你身处`b.com`却想要调用`a.com`的接口时,会率先发送一个`OPTIONS`预检请求,目的是为了询问`a.com`是否同意`b.com`发起的请求,
|
||||
在默认情况下,`a.com`收到一个陌生的第三方网站发来的请求,做出的回应肯定是:`不允许`, 浏览器收到回应就识相的关闭了请求,跨域请求失败
|
||||
|
||||
但是,有些开发者为了省事,直接设置了响应头: `Access-Control-Allow-Origin: *`,允许任何第三方网站的请求,这就给`CSRF攻击`留下了可乘之机
|
||||
|
||||
假设我们设置了只允许指定的网站跨域请求,就万事大吉了吗?并没有,攻击者仍可以通过抓包等手段得到我们的转账url,
|
||||
在`b.com`里,通过`open(url)`直接打开一个新的窗口调用转账接口,由于是属于打开新页面,浏览器连`OPTIONS`预检请求都不会发送,而是直接调用接口成功
|
||||
|
||||
此招无解吗?并不。由于它是属于打开新页面,这就导致调用接口时只能发送`get请求`,我们在设计接口时只需要遵守一个准则:`敏感接口一律post,禁止get调用`即可。
|
||||
|
||||
究其原因,导致`CSRF攻击`频频发生的原因是什么?是我们在跨域请求时,浏览器总是“自作聪明”的自动提交主站`Cookie`,
|
||||
在浏览器的不断更新中,Cookie的跨域规则变得愈发复杂,新手开发者及其容易绕的晕头转向,而同时`w3c`对`Cookie`规范的各种修修补补,又总是解决一个问题的同时暴露出其他的N多问题
|
||||
|
||||
既然Cookie机制如此难以驾驭,我们何不果断的放弃Cookie机制,改用`localStorage`机制存储会话token,这种方式轻松避免了`自动提交`带来的各种安全问题。
|
||||
事实上,`localStorage存储` + `header请求头提交`也是前后台分离趋势下的常见会话处理方案
|
||||
|
||||
篇幅有限,我们总结一下防范`CSRF攻击`要点
|
||||
|
||||
**在Cookie模式下**:
|
||||
1. 仅靠`CORS同源策略`无法彻底防范`CSRF攻击`,我们必须在后台建立`第三方域名白名单`,只有在白名单中的第三方域名才可以跨域调用我们的接口
|
||||
2. 涉及到数据增删改类型的接口,必须是`post`模式(或其它),严禁`get`模式,查询接口可以`get`
|
||||
3. 敏感操作增加验证码或者二次验证密码,减小被攻击的概率
|
||||
|
||||
**在 localStorage存储 + header请求头提交 模式下**:
|
||||
1. 在配置文件中,配置`is-read-cookie: false`,关闭Cookie模式,防止Sa-Token在登录时注入Cookie
|
||||
2. 同上,敏感操作增加验证码或者二次验证密码,减小被攻击的概率
|
||||
|
||||
有关CSRF攻防讲解的比较通透的一篇文章:[https://juejin.cn/post/6844903689702866952](https://juejin.cn/post/6844903689702866952)
|
||||
|
||||
|
||||
### Token泄露
|
||||
Token泄露一般发生在客户端,比如用户连接了不安全的WiFi导致通讯被监听,虽然此情形下token泄露的责任在于用户,但是我们还是有必要采取一定的措施使其损失降到最低
|
||||
1. 有条件上https的话一律https
|
||||
2. token有效期一定不能设置为永久,而且要尽量的短(but:为了不影响用户体验又不能设置特别的短,so: 7-30天是个比较合适的范围)
|
||||
3. 对敏感操作接口,增加密码二次校验(或手机验证码等)
|
||||
4. 用户更改密码后使其历史会话直接过期
|
||||
5. 有条件的情况下后台管理增加踢人下线功能,对已经泄露token的账号可以及时清理下线
|
||||
|
||||
|
||||
<br><br>
|
||||
更多类型漏洞连载中.... (欢迎提交pr)
|
||||
|
||||
@@ -15,12 +15,14 @@
|
||||
<a href="/">
|
||||
<div class="logo-box">
|
||||
<img src="logo.png" title="logo" />
|
||||
<h1 class="logo-text">sa-token</h1>
|
||||
<h1 class="logo-text">Sa-Token</h1>
|
||||
</div>
|
||||
</a>
|
||||
<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.18.0/doc/index.html">v1.18.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.17.0/doc/index.html">v1.17.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.16.0/doc/index.html">v1.16.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.15.0/doc/index.html">v1.15.0</option>
|
||||
<option value="http://sa-token.dev33.cn/v/v1.14.0/doc/index.html">v1.14.0</option>
|
||||
@@ -47,7 +49,7 @@
|
||||
</div>
|
||||
<script>
|
||||
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>v1.17.0</sub>'
|
||||
name += '<b style="font-size: 28px; vertical-align: middle;">Sa-Token</b> <sub>v1.19.0</sub>'
|
||||
window.$docsify = {
|
||||
name: name, // 名字
|
||||
repo: 'https://github.com/dromara/sa-token', // github地址
|
||||
|
||||
@@ -82,7 +82,7 @@ body{font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu
|
||||
}
|
||||
|
||||
/* 代码行号盒子样式 */
|
||||
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px;}
|
||||
.code-line-box {list-style-type: none; border-right: 1px solid #000; position: absolute; top: 0; left: 0; width: 40px; user-select: none;}
|
||||
.code-line-box {padding: calc(1.5em + 1px) 0px !important; padding-bottom: calc(1.5em + 20px) !important; margin: 0px !important;}
|
||||
.code-line-box {line-height: inherit !important; background-color: #111; color: #aaa;font-weight: 400;font-size: 0.85em;text-align: center;}
|
||||
.code-line-box {font-family: source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace;}
|
||||
|
||||
@@ -7,6 +7,36 @@
|
||||
|
||||
<table class="gzh-table" style="text-align: center;">
|
||||
<tr>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzk0MjE5MTk5Mw==&mid=2247485576&idx=1&sn=d955d60ab193d895fbd15c37bedebcb8&send_time="/>
|
||||
<b>Github导航站</b>
|
||||
<span>分享好玩有趣、新奇、实用的开源项目 </span>
|
||||
</td>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzI1MTA3Mzk4Mg==&mid=2651026326&idx=1&sn=3244e18a9a799cd8e0ec375c6c730670&send_time="/>
|
||||
<b>Java爱好者</b>
|
||||
<span>分享Java开发编程资源和Java技术文章 </span>
|
||||
</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzIxODQxMjc0MA==&mid=2247511029&idx=1&sn=42fbb1b8180dc2c995429dabc6f97500&send_time="/>
|
||||
<b>IT大咖说</b>
|
||||
<span>大咖干货,不再错过。 </span>
|
||||
</td>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzIxNjA5MTM2MA==&mid=2652444329&idx=1&sn=2a040e87f49a977a116c90e1107a9fdc&send_time="/>
|
||||
<b>Java编程</b>
|
||||
<span>专注Java技术分享,Java基础知识/数据结构/算法</span>
|
||||
</td>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=MzA4MDMyODg4OQ==&mid=2649482871&idx=2&sn=b376585faaf814d9072af539efda68fe&send_time="/>
|
||||
<b>大侠学JAVA</b>
|
||||
<span>道阻且长,行则将至,专注分享JAVA领域的干货</span>
|
||||
</td>
|
||||
<td>
|
||||
<img src="https://mp.weixin.qq.com/mp/qrcode?scene=10000005&size=102&__biz=Mzg2MDIxNjAzNg==&mid=2247485810&idx=1&sn=afd46d5924afbc1030a87b5d56265fdf&send_time="/>
|
||||
<b>Java大厂面试官</b>
|
||||
@@ -17,9 +47,6 @@
|
||||
<b>程序员大神</b>
|
||||
<span>有一个在程序员圈混了10年的老程序员, 分享程序员相关的精选内容教程</span>
|
||||
</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
@@ -1,5 +1,25 @@
|
||||
# 更新日志
|
||||
|
||||
### 2021-5-10 @v1.19.0
|
||||
- 新增:注解鉴权新增定制loginKey功能 **[重要]**
|
||||
- 重构:重构目录结构,抽离`plugin`模块 **[重要]**
|
||||
- 新增:新增 `sa-token-quick-login` 插件,零代码集成登录功能 **[重要]**
|
||||
- 优化:所有函数式接口增加`@FunctionalInterface`注解,感谢群友`@MrXionGe`提供的建议
|
||||
- 优化:文档优化...
|
||||
|
||||
|
||||
### 2021-4-24 @v1.18.0
|
||||
- 新增:新增权限通配符功能,灵活设置权限 **[重要]**
|
||||
- 修复:修复自动续签处的逻辑错误
|
||||
- 新增:新增Web开发常见漏洞防护建议
|
||||
- 修复:修复`SaRequest`中缺少`getMethod()`的bug
|
||||
- 修复:修复自动续签时的逻辑错误,感谢群成员`@N`的建议
|
||||
- 新增:全局过滤器新增 `beforAuth` 前置函数
|
||||
- 修复:修复在带有上下文的项目中无法正确获取请求路径的bug,感谢群成员`@dlwlrma`提供的建议
|
||||
- 新增:新增`SaHolder`上下文持有类,可方便的在上下文中读写数据
|
||||
- 重构:`SaTokenManager` -> `SaManager`
|
||||
- 重构:`SaTokenInsideUtil` -> `SaFoxUtil`
|
||||
|
||||
|
||||
### 2021-4-17 @v1.17.0
|
||||
- 修复:在WebFlux环境中引入Redis集成包无法启动的问题
|
||||
|
||||
30
sa-token-doc/doc/plugin/aop-at.md
Normal file
30
sa-token-doc/doc/plugin/aop-at.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# AOP注解鉴权
|
||||
---
|
||||
|
||||
在 [注解式鉴权](/use/at-check) 章节,我们非常轻松的实现了注解鉴权,
|
||||
但是默认的拦截器模式却有一个缺点,那就是无法在`Controller层`以外的代码使用进行校验
|
||||
|
||||
因此Sa-Token提供AOP插件,你只需在`pom.xml`里添加如下依赖,便可以在任意层级使用注解鉴权
|
||||
|
||||
``` xml
|
||||
<!-- sa-token整合SpringAOP实现注解鉴权 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-aop</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
|
||||
#### 注意点:
|
||||
- 使用拦截器模式,只能把注解写在`Controller层`,使用AOP模式,可以将注解写在任意层级 <br>
|
||||
- **拦截器模式和AOP模式不可同时集成**,否则会在`Controller层`发生一个注解校验两次的bug
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
225
sa-token-doc/doc/plugin/quick-login.md
Normal file
225
sa-token-doc/doc/plugin/quick-login.md
Normal file
@@ -0,0 +1,225 @@
|
||||
# Sa-Token-Quick-Login 快速登录认证
|
||||
---
|
||||
|
||||
|
||||
### 解决什么问题
|
||||
|
||||
Sa-Token-Quick-Login 可以为一个系统快速的、零代码 注入一个登录页面
|
||||
|
||||
试想一下,假如我们开发了一个非常简单的小系统,比如说:服务器性能监控页面,
|
||||
我们将它部署在服务器上,通过访问这个页面,我们可以随时了解服务器性能信息,非常方便
|
||||
|
||||
然而,这个页面方便我们的同时,也方便了一些不法的攻击者,由于这个页面毫无防护的暴露在公网中,任何一台安装了浏览器的电脑都可以随时访问它!
|
||||
|
||||
为此,我们必须给这个系统加上一个登录认证,只有知晓了后台密码的人员才可以进行访问
|
||||
|
||||
细细想来,完成这个功能你需要:
|
||||
|
||||
1. 编写前端登录页面,手写各种表单样式
|
||||
2. 寻找合适的ajax类库,`jQuery`?`Axios`?还是直接前后台不分离?
|
||||
3. 寻找合适的模板引擎,比如`jsp`、`Thymeleaf`、`FreeMarker`、`Velocity`……选哪个呢?
|
||||
4. 处理后台各种拦截认证逻辑,前后台接口对接
|
||||
5. 你可能还会遇到令人头痛欲裂的模板引擎中`ContextPath`处理
|
||||
6. ……
|
||||
|
||||
你马上就会发现,写个监控页你一下午就可以搞定,然而这个登录页你却可能需要花上两三天的时间,这是一笔及其不划算的时间浪费
|
||||
|
||||
那么现在你可能就会有个疑问,难道就没有什么方法给我的小项目快速增加一个登录功能吗?
|
||||
|
||||
Sa-Token-Quick-Login便是为了解决这个问题!
|
||||
|
||||
|
||||
### 适用场景
|
||||
|
||||
Sa-Token-Quick-Login 旨在用最小的成本为项目增加一个登录认证功能
|
||||
|
||||
- **简单**:只需要引入一个依赖便可为系统注入登录功能,快速、简单、零代码!
|
||||
- **不可定制**:由于登录页面不可定制,所以Sa-Token-Quick-Login非常不适合普通项目的登录认证模块,STQL也无意去解决所有项目的登录认证模块
|
||||
|
||||
Sa-Token-Quick-Login的定位是这样的场景:你的项目需要一个登录认证功能、这个认证页面可以不华丽、可以烂,但是一定要有,同时你又不想花费太多的时间浪费在登录页面上,
|
||||
那么你便可以尝试一下`Sa-Token-Quick-Login`
|
||||
|
||||
|
||||
### 集成步骤
|
||||
首先我们需要创建一个SpringBoot的demo项目,比如:`sa-token-demo-quick-login`
|
||||
|
||||
##### 1、添加pom依赖
|
||||
``` xml
|
||||
<!-- Sa-Token-Quick-Login 插件 -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-quick-login</artifactId>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
##### 2、启动类
|
||||
``` java
|
||||
@SpringBootApplication
|
||||
public class SaTokenQuickDemoApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SaTokenQuickDemoApplication.class, args);
|
||||
|
||||
System.out.println("\n------ 启动成功 ------");
|
||||
System.out.println("name: " + SaQuickManager.getConfig().getName());
|
||||
System.out.println("pwd: " + SaQuickManager.getConfig().getPwd());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
##### 3、新建测试Controller
|
||||
``` java
|
||||
/**
|
||||
* 测试专用Controller
|
||||
*/
|
||||
@RestController
|
||||
public class TestController {
|
||||
// 浏览器访问测试: http://localhost:8081
|
||||
@RequestMapping({"/", "/index"})
|
||||
public String login(String username, String password) {
|
||||
String str = "<br />"
|
||||
+ "<h1 style='text-align: center;'>资源页 (登录后才可进入本页面) </h1>"
|
||||
+ "<hr/>"
|
||||
+ "<p style='text-align: center;'> Sa-Token " + SaTokenConsts.VERSION_NO + " </p>";
|
||||
return str;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 测试访问
|
||||
启动项目,使用浏览器访问:`http://localhost:8081`,首次访问时,由于处于未登录状态,会被强制进入登录页面
|
||||
|
||||

|
||||
|
||||
使用默认账号:`sa / 123456`进行登录,会看到资源页面
|
||||
|
||||

|
||||
|
||||
|
||||
### 可配置信息
|
||||
你可以在yml中添加如下配置 (所有配置都是可选的)
|
||||
``` java
|
||||
# Sa-Token-Quick-Login 配置
|
||||
sa:
|
||||
# 登录账号
|
||||
name: sa
|
||||
# 登录密码
|
||||
pwd: 123456
|
||||
# 是否自动随机生成账号密码 (此项为true时, name与pwd失效)
|
||||
auto: false
|
||||
# 是否开启全局认证(关闭后将不再强行拦截)
|
||||
auth: true
|
||||
# 登录页标题
|
||||
title: Sa-Token 登录
|
||||
# 是否显示底部版权信息
|
||||
copr: true
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
**注:**示例源码在`/sa-token-demo/sa-token-demo-quick-login`目录下,可结合源码查看学习
|
||||
|
||||
|
||||
|
||||
### 使用独立jar包运行
|
||||
使用`sa-token-quick-login`只需引入一个依赖即可为系统注入登录模块,现在我们更进一步,将这个项目打成一个独立的jar包
|
||||
|
||||
通过这个jar包,我们可以方便的部署任意静态网站!做到真正的零编码注入登录功能。
|
||||
|
||||
|
||||
##### 打包步骤
|
||||
|
||||
首先放上懒人链接:[sa-quick-dist.jar](https://gitee.com/dromara/sa-token/attach_files/695353/download) ,不想手动操作的同学可以直接点此链接下载打包后的jar文件
|
||||
|
||||
1、首先将 `sa-token-demo-quick-login` 模块添加到顶级父模块的`<modules>`节点中
|
||||
|
||||
``` xml
|
||||
<!-- 所有模块 -->
|
||||
<modules>
|
||||
<module>sa-token-core</module>
|
||||
<module>sa-token-starter</module>
|
||||
<module>sa-token-plugin</module>
|
||||
<module>sa-token-demo\sa-token-demo-quick-login</module>
|
||||
</modules>
|
||||
```
|
||||
|
||||
2、在项目根目录进入cmd执行打包命令
|
||||
|
||||
``` cmd
|
||||
mvn clean package
|
||||
```
|
||||
|
||||
3、进入`\sa-token-demo\sa-token-demo-quick-login\target` 文件夹,找到打包好的jar文件
|
||||
|
||||
``` cmd
|
||||
sa-token-demo-quick-login-0.0.1-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
4、我们将其重命名为`sa-quick-dist.jar`,现在这个jar包就是我们的最终程序,我们在这个`\target`目录直接进入cmd,执行如下命令启动jar包
|
||||
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar
|
||||
```
|
||||
|
||||
5、测试访问,根据控制台输出提示,我们使用浏览器访问测试: `http://localhost:8080`
|
||||
|
||||

|
||||
|
||||
如果可以进入登录界面,则代表打包运行成功 <br>
|
||||
当然仅仅运行成功还不够,下面我们演示一下如何使用这个jar包进行静态网站部署
|
||||
|
||||
|
||||
### 所有功能示例
|
||||
|
||||
##### Case 1. 指定静态资源路径
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --sa.dir file:E:\www
|
||||
```
|
||||
使用dir参数指定`E:\www`目录作为资源目录进行部署 (现在我们可以通过浏览器访问`E:\www`目录下的文件了!)
|
||||
|
||||
##### Case 2. 指定登录名与密码
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --sa.name=zhang --sa.pwd=zhang123
|
||||
```
|
||||
现在,默认的账号`sa/123456`将被废弃,而是使用`zhang/zhang123`进行账号校验
|
||||
|
||||
##### Case 3. 指定其自动生成账号密码
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --sa.auto=true
|
||||
```
|
||||
每次启动时随机生成账号密码(会在启动成功时打印到控制台上)
|
||||
|
||||
##### Case 4. 指定登录页的标题
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --sa.title="XXX 系统登录"
|
||||
```
|
||||
|
||||
##### Case 5. 关闭账号校验,仅作为静态资源部署使用
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --sa.auth=false
|
||||
```
|
||||
|
||||
##### Case 6. 指定启动端口(默认8080)
|
||||
``` cmd
|
||||
java -jar sa-quick-dist.jar --server.port=80
|
||||
```
|
||||
|
||||
注:所有参数可组合使用
|
||||
|
||||
|
||||
### 使用SpringBoot默认资源路径
|
||||
SpringBoot默认开放了一些路径作为资源目录,比如`classpath:/static/`,
|
||||
怎么使用呢?我们只需要在jar包同目录创建一个`\static`文件夹,将静态资源文件复制到此目录下,然后启动jar包即可访问
|
||||
|
||||
同时,我们还可以在jar包同目录创建yml配置文件,来覆盖jar包内的yml配置,如下图所示:
|
||||
|
||||

|
||||
|
||||
例如如上目录中`/static`中有一个`1.jpg`文件,我们启动jar包后访问`http://localhost:8080/1.jpg`即可查看到此文件,这是Springboot自带的功能,在此不再赘述
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,27 +3,29 @@
|
||||
------
|
||||
|
||||
## Maven依赖
|
||||
在项目中直接通过 `pom.xml` 导入 `sa-token` 的依赖即可:
|
||||
在项目中直接通过 `pom.xml` 引入 `sa-token` 的依赖即可(四选一):
|
||||
|
||||
<!------------------------------ tabs:start ------------------------------>
|
||||
|
||||
<!-- tab:SpringMVC环境 (ServletAPI) -->
|
||||
如果你使用的框架基于 ServletAPI 构建( `SpringMVC`、`SpringBoot`、`Zuul`等 ),请引入此包
|
||||
``` xml
|
||||
<!-- sa-token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
<!-- tab:WebFlux环境 (Reactor) -->
|
||||
注:此依赖适合在 Reactor模式 的web框架中导入(例如`Netty`、`WebFlux`等),如果您的项目基于 ServletAPI (`SpringMVC`、`SpringBoot`等),请以前者为准
|
||||
注:如果你使用的框架基于 Reactor 模型构建(`Netty`、`WebFlux`、`Soul`、`SC Gateway`等),请引入此包
|
||||
``` xml
|
||||
<!-- sa-token 权限认证(Reactor响应式集成), 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-reactor-spring-boot-starter</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -34,7 +36,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-servlet</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -45,7 +47,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-core</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
<!---------------------------- tabs:end ------------------------------>
|
||||
@@ -56,19 +58,19 @@
|
||||
<!-- tabs:start -->
|
||||
<!-- tab:SpringMVC环境 (ServletAPI) -->
|
||||
``` xml
|
||||
implementation 'cn.dev33:sa-token-spring-boot-starter:1.17.0'
|
||||
implementation 'cn.dev33:sa-token-spring-boot-starter:1.19.0'
|
||||
```
|
||||
<!-- tab:WebFlux环境 (Reactor) -->
|
||||
``` xml
|
||||
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:1.17.0'
|
||||
implementation 'cn.dev33:sa-token-reactor-spring-boot-starter:1.19.0'
|
||||
```
|
||||
<!-- tab:Servlet容器环境 -->
|
||||
``` xml
|
||||
implementation 'cn.dev33:sa-token-servlet:1.17.0'
|
||||
implementation 'cn.dev33:sa-token-servlet:1.19.0'
|
||||
```
|
||||
<!-- tab:其它 -->
|
||||
``` xml
|
||||
implementation 'cn.dev33:sa-token-core:1.17.0'
|
||||
implementation 'cn.dev33:sa-token-core:1.19.0'
|
||||
```
|
||||
<!-- tabs:end -->
|
||||
|
||||
@@ -82,21 +84,23 @@ implementation 'cn.dev33:sa-token-core:1.17.0'
|
||||
|
||||
``` js
|
||||
── sa-token
|
||||
├── sa-token-core // sa-token 核心模块
|
||||
├── sa-token-servlet // sa-token 整合 Servlet容器实现类包
|
||||
├── sa-token-spring-boot-starter // sa-token 整合 SpringBoot 快速集成
|
||||
├── sa-token-reactor-spring-boot-starter // sa-token 整合 Reactor响应式编程 快速集成
|
||||
├── sa-token-dao-redis // sa-token 整合 Redis (使用jdk默认序列化方式)
|
||||
├── sa-token-dao-redis-jackson // sa-token 整合 Redis (使用jackson序列化方式)
|
||||
├── sa-token-spring-aop // sa-token 整合 SpringAOP 注解鉴权
|
||||
├── sa-token-oauth2 // sa-token 实现 OAuth2.0 模块(内测暂未发布)
|
||||
├── sa-token-demo-springboot // [示例] sa-token 整合 SpringBoot
|
||||
├── sa-token-demo-jwt // [示例] sa-token 集成 jwt [示例]
|
||||
├── sa-token-demo-webflux // [示例] sa-token 整合 WebFlux [示例]
|
||||
├── sa-token-demo-oauth2 // [示例] sa-token集成OAuth2.0模块 [示例]
|
||||
├── sa-token-demo-oauth2-client // [示例] OAuth2.0 客户端
|
||||
├── sa-token-demo-oauth2-server // [示例] OAuth2.0 服务端
|
||||
├── sa-token-doc // [文档] sa-token开发文档
|
||||
├── sa-token-core // [核心] sa-token 核心模块
|
||||
├── sa-token-starter // [整合] sa-token 与其它框架整合
|
||||
├── sa-token-servlet // [整合] sa-token 整合 Servlet容器实现类包
|
||||
├── sa-token-spring-boot-starter // [整合] sa-token 整合 SpringBoot 快速集成
|
||||
├── sa-token-reactor-spring-boot-starter // [整合] sa-token 整合 Reactor响应式编程 快速集成
|
||||
├── sa-token-plugin // [插件] sa-token 插件合集
|
||||
├── sa-token-dao-redis // [插件] sa-token 整合 Redis (使用jdk默认序列化方式)
|
||||
├── sa-token-dao-redis-jackson // [插件] sa-token 整合 Redis (使用jackson序列化方式)
|
||||
├── sa-token-spring-aop // [插件] sa-token 整合 SpringAOP 注解鉴权
|
||||
├── sa-token-oauth2 // [插件] sa-token 实现 OAuth2.0 模块(内测暂未发布)
|
||||
├── sa-token-demo // [示例] sa-token 示例合集
|
||||
├── sa-token-demo-springboot // [示例] sa-token 整合 SpringBoot
|
||||
├── sa-token-demo-webflux // [示例] sa-token 整合 WebFlux [示例]
|
||||
├── sa-token-demo-jwt // [示例] sa-token 集成 jwt [示例]
|
||||
├── sa-token-demo-oauth2-server // [示例] sa-token 集成 OAuth2.0 (服务端)
|
||||
├── sa-token-demo-oauth2-client // [示例] sa-token 集成 OAuth2.0 (客户端)
|
||||
├── sa-token-doc // [文档] sa-token 开发文档
|
||||
├──pom.xml
|
||||
```
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# SpringBoot 集成 Sa-Token 示例
|
||||
|
||||
本篇将带你从零开始集成sa-token,从而让你快速熟悉sa-token的使用姿势 <br>
|
||||
整合示例在官方仓库的`/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习
|
||||
整合示例在官方仓库的`/sa-token-demo/sa-token-demo-springboot`文件夹下,如遇到难点可结合源码进行测试学习
|
||||
|
||||
---
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<dependency>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.17.0</version>
|
||||
<version>1.19.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@@ -61,7 +61,7 @@ spring:
|
||||
public class SaTokenDemoApplication {
|
||||
public static void main(String[] args) throws JsonProcessingException {
|
||||
SpringApplication.run(SaTokenDemoApplication.class, args);
|
||||
System.out.println("启动成功:sa-token配置如下:" + SaTokenManager.getConfig());
|
||||
System.out.println("启动成功:sa-token配置如下:" + SaManager.getConfig());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user