抽离包装类,核心包脱离ServletAPI

This commit is contained in:
shengzhang
2021-04-05 22:54:25 +08:00
parent 9b44e05c28
commit 15eefbed33
30 changed files with 522 additions and 405 deletions

View File

@@ -16,11 +16,7 @@
<description>A Java Web lightweight authority authentication framework, comprehensive function, easy to use</description>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- Zero dependence -->
</dependencies>

View File

@@ -7,12 +7,10 @@ import cn.dev33.satoken.action.SaTokenAction;
import cn.dev33.satoken.action.SaTokenActionDefaultImpl;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.config.SaTokenConfigFactory;
import cn.dev33.satoken.cookie.SaTokenCookie;
import cn.dev33.satoken.cookie.SaTokenCookieDefaultImpl;
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.servlet.SaTokenServlet;
import cn.dev33.satoken.servlet.SaTokenServletDefaultImpl;
import cn.dev33.satoken.stp.StpInterface;
import cn.dev33.satoken.stp.StpInterfaceDefaultImpl;
import cn.dev33.satoken.stp.StpLogic;
@@ -108,47 +106,29 @@ public class SaTokenManager {
}
/**
* Cookie操作 Bean
* 容器操作 Bean
*/
private static SaTokenCookie saTokenCookie;
public static void setSaTokenCookie(SaTokenCookie saTokenCookie) {
SaTokenManager.saTokenCookie = saTokenCookie;
private static SaTokenContext saTokenContext;
public static void setSaTokenContext(SaTokenContext saTokenContext) {
SaTokenManager.saTokenContext = saTokenContext;
}
public static SaTokenCookie getSaTokenCookie() {
if (saTokenCookie == null) {
public static SaTokenContext getSaTokenContext() {
if (saTokenContext == null) {
// 如果对象为空,则使用框架默认方式初始化
synchronized (SaTokenManager.class) {
if (saTokenCookie == null) {
setSaTokenCookie(new SaTokenCookieDefaultImpl());
if (saTokenContext == null) {
setSaTokenContext(new SaTokenContextDefaultImpl());
}
}
}
return saTokenCookie;
}
/**
* Servlet操作 Bean
*/
private static SaTokenServlet saTokenServlet;
public static void setSaTokenServlet(SaTokenServlet saTokenServlet) {
SaTokenManager.saTokenServlet = saTokenServlet;
}
public static SaTokenServlet getSaTokenServlet() {
if (saTokenServlet == null) {
// 如果对象为空,则使用框架默认方式初始化
synchronized (SaTokenManager.class) {
if (saTokenServlet == null) {
setSaTokenServlet(new SaTokenServletDefaultImpl());
}
}
}
return saTokenServlet;
return saTokenContext;
}
/**
* StpLogic集合, 记录框架所有成功初始化的StpLogic
*/
public static Map<String, StpLogic> stpLogicMap = new HashMap<String, StpLogic>();
/**
* 向集合中 put 一个 StpLogic
* @param stpLogic StpLogic
@@ -156,6 +136,7 @@ public class SaTokenManager {
public static void putStpLogic(StpLogic stpLogic) {
stpLogicMap.put(stpLogic.getLoginKey(), stpLogic);
}
/**
* 根据 LoginKey 获取对应的StpLogic如果不存在则返回null
* @param loginKey 对应的LoginKey

View File

@@ -0,0 +1,36 @@
package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
/**
* 与底层容器交互接口
* @author kong
*
*/
public interface SaTokenContext {
/**
* 获取当前请求的 Request 对象
*
* @return see note
*/
public SaRequest getRequest();
/**
* 获取当前请求的 Response 对象
*
* @return see note
*/
public SaResponse getResponse();
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*
* @param pattern 路由匹配符
* @param path 需要匹配的路径
* @return see note
*/
public boolean matchPath(String pattern, String path);
}

View File

@@ -0,0 +1,38 @@
package cn.dev33.satoken.context;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.exception.SaTokenException;
/**
* Sa-Token 与底层容器交互接口 [默认实现类]
* @author kong
*
*/
public class SaTokenContextDefaultImpl implements SaTokenContext {
/**
* 获取当前请求的Request对象
*/
@Override
public SaRequest getRequest() {
throw new SaTokenException("未初始化任何有效容器");
}
/**
* 获取当前请求的Response对象
*/
@Override
public SaResponse getResponse() {
throw new SaTokenException("未初始化任何有效容器");
}
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*/
@Override
public boolean matchPath(String pattern, String path) {
throw new SaTokenException("未初始化任何有效容器");
}
}

View File

@@ -0,0 +1,10 @@
package cn.dev33.satoken.context.model;
/**
* Cookie 包装类
* @author kong
*
*/
public class SaCookie {
}

View File

@@ -0,0 +1,63 @@
package cn.dev33.satoken.context.model;
/**
* Request包装类
* @author kong
*
*/
public interface SaRequest {
/**
* 获取底层源对象
* @return see note
*/
public Object getSource();
/**
* 在 [Request作用域] 里写入一个值
* @param name 键
* @param value 值
*/
public void setAttribute(String name, Object value);
/**
* 在 [Request作用域] 里获取一个值
* @param name 键
* @return 值
*/
public Object getAttribute(String name);
/**
* 在 [Request作用域] 里删除一个值
* @param name 键
*/
public void removeAttribute(String name);
/**
* 在 [请求体] 里获取一个值
* @param name 键
* @return 值
*/
public String getParameter(String name);
/**
* 在 [请求头] 里获取一个值
* @param name 键
* @return 值
*/
public String getHeader(String name);
/**
* 在 [Cookie作用域] 里获取一个值
* @param name 键
* @return 值
*/
public String getCookieValue(String name);
/**
* 返回当前请求的URL
* @return see note
*/
public String getRequestURI();
}

View File

@@ -0,0 +1,32 @@
package cn.dev33.satoken.context.model;
/**
* Response 包装类
* @author kong
*
*/
public interface SaResponse {
/**
* 获取底层源对象
* @return see note
*/
public Object getSource();
/**
* 删除指定Cookie
* @param name Cookie名称
*/
public void deleteCookie(String name);
/**
* 写入指定Cookie
* @param name Cookie名称
* @param value Cookie值
* @param path Cookie路径
* @param domain Cookie的作用域
* @param timeout 过期时间 (秒)
*/
public void addCookie(String name, String value, String path, String domain, int timeout);
}

View File

@@ -0,0 +1,4 @@
/**
* 因为不能确定最终运行的容器属于标准Servlet模型还是非Servlet模型特封装此包下的包装类进行对接
*/
package cn.dev33.satoken.context;

View File

@@ -1,55 +0,0 @@
package cn.dev33.satoken.cookie;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sa-token 对cookie的相关操作 接口类
*
* @author kong
*
*/
public interface SaTokenCookie {
/**
* 在request对象中获取指定Cookie
*
* @param request request对象
* @param cookieName Cookie名称
* @return 查找到的Cookie对象
*/
public Cookie getCookie(HttpServletRequest request, String cookieName);
/**
* 添加Cookie
*
* @param response response对象
* @param name Cookie名称
* @param value Cookie值
* @param path Cookie路径
* @param domain Cookie的作用域
* @param timeout 过期时间 (秒)
*/
public void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout);
/**
* 删除Cookie
*
* @param request request对象
* @param response response对象
* @param name Cookie名称
*/
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name);
/**
* 修改Cookie的value值
*
* @param request request对象
* @param response response对象
* @param name Cookie名称
* @param value Cookie值
*/
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value);
}

View File

@@ -1,47 +0,0 @@
package cn.dev33.satoken.cookie;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* sa-token 对cookie的相关操作 接口实现类
*
* @author kong
*
*/
public class SaTokenCookieDefaultImpl implements SaTokenCookie {
/**
* 获取指定cookie
*/
@Override
public Cookie getCookie(HttpServletRequest request, String cookieName) {
return SaTokenCookieUtil.getCookie(request, cookieName);
}
/**
* 添加cookie
*/
@Override
public void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout) {
SaTokenCookieUtil.addCookie(response, name, value, path, domain, timeout);
}
/**
* 删除cookie
*/
@Override
public void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
SaTokenCookieUtil.delCookie(request, response, name);
}
/**
* 修改cookie的value值
*/
@Override
public void updateCookie(HttpServletRequest request, HttpServletResponse response, String name, String value) {
SaTokenCookieUtil.updateCookie(request, response, name, value);
}
}

View File

@@ -1,98 +0,0 @@
package cn.dev33.satoken.cookie;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.util.SaTokenInsideUtil;
/**
* Cookie操作工具类
*
* @author kong
*/
public class SaTokenCookieUtil {
/**
* 在request对象中获取指定Cookie
*
* @param request request对象
* @param cookieName Cookie名称
* @return 查找到的Cookie对象
*/
public static Cookie getCookie(HttpServletRequest request, String cookieName) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && cookieName.equals(cookie.getName())) {
return cookie;
}
}
}
return null;
}
/**
* 添加cookie
*
* @param response response
* @param name Cookie名称
* @param value Cookie值
* @param path Cookie写入路径
* @param domain Cookie的作用域
* @param timeout Cookie有效期 (秒)
*/
public static void addCookie(HttpServletResponse response, String name, String value, String path, String domain, int timeout) {
Cookie cookie = new Cookie(name, value);
if(SaTokenInsideUtil.isEmpty(path) == true) {
path = "/";
}
if(SaTokenInsideUtil.isEmpty(domain) == false) {
cookie.setDomain(domain);
}
cookie.setPath(path);
cookie.setMaxAge(timeout);
response.addCookie(cookie);
}
/**
* 删除Cookie
*
* @param request request对象
* @param response response对象
* @param name Cookie名称
*/
public static void delCookie(HttpServletRequest request, HttpServletResponse response, String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && (name).equals(cookie.getName())) {
addCookie(response, name, null, null, null, 0);
return;
}
}
}
}
/**
* 修改cookie的value值
*
* @param request request对象
* @param response response对象
* @param name Cookie名称
* @param value Cookie值
*/
public static void updateCookie(HttpServletRequest request, HttpServletResponse response, String name,
String value) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && (name).equals(cookie.getName())) {
addCookie(response, name, value, cookie.getPath(), cookie.getDomain(), cookie.getMaxAge());
return;
}
}
}
}
}

View File

@@ -1,7 +1,7 @@
package cn.dev33.satoken.router;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
/**
* 执行验证方法的辅助类
@@ -14,10 +14,10 @@ public interface SaRouteFunction {
/**
* 执行验证的方法
*
* @param request request对象
* @param response response对象
* @param request Request包装对象
* @param response Response包装对象
* @param handler 处理对象
*/
public void run(HttpServletRequest request, HttpServletResponse response, Object handler);
public void run(SaRequest request, SaResponse response, Object handler);
}

View File

@@ -23,7 +23,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatch(String pattern, String path) {
return SaTokenManager.getSaTokenServlet().matchPath(pattern, path);
return SaTokenManager.getSaTokenContext().matchPath(pattern, path);
}
/**
@@ -47,7 +47,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatchCurrURI(String pattern) {
return isMatch(pattern, SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
return isMatch(pattern, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
}
/**
@@ -56,7 +56,7 @@ public class SaRouterUtil {
* @return 是否匹配成功
*/
public static boolean isMatchCurrURI(List<String> patterns) {
return isMatch(patterns, SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
return isMatch(patterns, SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
}
@@ -119,7 +119,7 @@ public class SaRouterUtil {
* @return 匹配结果包装对象
*/
public static IsRunFunction match(String... patterns) {
boolean matchResult = isMatch(Arrays.asList(patterns), SaTokenManager.getSaTokenServlet().getRequest().getRequestURI());
boolean matchResult = isMatch(Arrays.asList(patterns), SaTokenManager.getSaTokenContext().getRequest().getRequestURI());
return new IsRunFunction(matchResult);
}

View File

@@ -1,36 +0,0 @@
package cn.dev33.satoken.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet相关操作接口
*
* @author kong
*
*/
public interface SaTokenServlet {
/**
* 获取当前请求的 Request 对象
*
* @return 当前请求的Request对象
*/
public HttpServletRequest getRequest();
/**
* 获取当前请求的 Response 对象
*
* @return 当前请求的response对象
*/
public HttpServletResponse getResponse();
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
* @param pattern 路由匹配符
* @param path 需要匹配的路径
* @return 是否匹配成功
*/
public boolean matchPath(String pattern, String path);
}

View File

@@ -1,41 +0,0 @@
package cn.dev33.satoken.servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.exception.SaTokenException;
/**
* sa-token 对SaTokenServlet接口默认实现类
*
* @author kong
*
*/
public class SaTokenServletDefaultImpl implements SaTokenServlet {
/**
* 获取当前请求的Request对象
*/
@Override
public HttpServletRequest getRequest() {
throw new SaTokenException("SaTokenServlet接口未实现");
}
/**
* 获取当前请求的Response对象
*/
@Override
public HttpServletResponse getResponse() {
throw new SaTokenException("SaTokenServlet接口未实现");
}
/**
* 校验指定路由匹配符是否可以匹配成功指定路径
*/
@Override
public boolean matchPath(String pattern, String path) {
throw new SaTokenException("SaTokenServlet接口未实现");
}
}

View File

@@ -6,16 +6,14 @@ import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.SaTokenManager;
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.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.exception.DisableLoginException;
import cn.dev33.satoken.exception.NotLoginException;
@@ -95,8 +93,8 @@ public class StpLogic {
*/
public void setTokenValue(String tokenValue, int cookieTimeout){
SaTokenConfig config = getConfig();
// 将token保存到本次request里
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
// 将token保存到本次Request里
SaRequest request = SaTokenManager.getSaTokenContext().getRequest();
// 判断是否配置了token前缀
String tokenPrefix = config.getTokenPrefix();
if(SaTokenInsideUtil.isEmpty(tokenPrefix)) {
@@ -108,9 +106,8 @@ public class StpLogic {
// 注入Cookie
if(config.getIsReadCookie() == true){
HttpServletResponse response = SaTokenManager.getSaTokenServlet().getResponse();
SaTokenManager.getSaTokenCookie().addCookie(response, getTokenName(), tokenValue,
"/", config.getCookieDomain(), cookieTimeout);
SaResponse response = SaTokenManager.getSaTokenContext().getResponse();
response.addCookie(getTokenName(), tokenValue, "/", config.getCookieDomain(), cookieTimeout);
}
}
@@ -120,7 +117,7 @@ public class StpLogic {
*/
public String getTokenValue(){
// 0. 获取相应对象
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
SaRequest request = SaTokenManager.getSaTokenContext().getRequest();
SaTokenConfig config = getConfig();
String keyTokenName = getTokenName();
String tokenValue = null;
@@ -139,10 +136,7 @@ public class StpLogic {
}
// 4. 尝试从cookie里读取
if(tokenValue == null && config.getIsReadCookie()){
Cookie cookie = SaTokenManager.getSaTokenCookie().getCookie(request, keyTokenName);
if(cookie != null){
tokenValue = cookie.getValue();
}
tokenValue = request.getCookieValue(keyTokenName);
}
// 5. 如果打开了前缀模式
@@ -290,7 +284,7 @@ public class StpLogic {
}
// 如果打开了cookie模式第一步先把cookie清除掉
if(getConfig().getIsReadCookie() == true){
SaTokenManager.getSaTokenCookie().delCookie(SaTokenManager.getSaTokenServlet().getRequest(), SaTokenManager.getSaTokenServlet().getResponse(), getTokenName());
SaTokenManager.getSaTokenContext().getResponse().deleteCookie(getTokenName());
}
logoutByTokenValue(tokenValue);
}
@@ -379,7 +373,7 @@ public class StpLogic {
public boolean isDisable(Object loginId) {
return SaTokenManager.getSaTokenDao().get(splicingKeyDisable(loginId)) != null;
}
/**
* 获取指定账号剩余封禁时间,单位:秒(-1=永久封禁,-2=未被封禁)
* @param loginId 账号id
@@ -692,7 +686,7 @@ public class StpLogic {
// 删除[最后操作时间]
SaTokenManager.getSaTokenDao().delete(splicingKeyLastActivityTime(tokenValue));
// 清除标记
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY);
SaTokenManager.getSaTokenContext().getRequest().removeAttribute((SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY));
}
/**
@@ -705,7 +699,7 @@ public class StpLogic {
return;
}
// 如果本次请求已经有了[检查标记], 则立即返回
HttpServletRequest request = SaTokenManager.getSaTokenServlet().getRequest();
SaRequest request = SaTokenManager.getSaTokenContext().getRequest();
if(request.getAttribute(SaTokenConsts.TOKEN_ACTIVITY_TIMEOUT_CHECKED_KEY) != null) {
return;
}
@@ -1255,14 +1249,14 @@ public class StpLogic {
* @param loginId 指定loginId
*/
public void switchTo(Object loginId) {
SaTokenManager.getSaTokenServlet().getRequest().setAttribute(splicingKeySwitch(), loginId);
SaTokenManager.getSaTokenContext().getRequest().setAttribute(splicingKeySwitch(), loginId);
}
/**
* 结束临时切换身份
*/
public void endSwitch() {
SaTokenManager.getSaTokenServlet().getRequest().removeAttribute(splicingKeySwitch());
SaTokenManager.getSaTokenContext().getRequest().removeAttribute(splicingKeySwitch());
}
/**
@@ -1270,7 +1264,7 @@ public class StpLogic {
* @return 是否正处于[身份临时切换]中
*/
public boolean isSwitch() {
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(splicingKeySwitch()) != null;
return SaTokenManager.getSaTokenContext().getRequest().getAttribute(splicingKeySwitch()) != null;
}
/**
@@ -1278,7 +1272,7 @@ public class StpLogic {
* @return 返回[身份临时切换]的loginId
*/
public Object getSwitchLoginId() {
return SaTokenManager.getSaTokenServlet().getRequest().getAttribute(splicingKeySwitch());
return SaTokenManager.getSaTokenContext().getRequest().getAttribute(splicingKeySwitch());
}
/**

View File

@@ -27,20 +27,24 @@ implementation 'cn.dev33:sa-token-spring-boot-starter:1.15.2'
- gitee地址[https://gitee.com/dromara/sa-token](https://gitee.com/dromara/sa-token)
- 开源不易,求鼓励,给个`star`吧
- 源码目录介绍:
```
── sa-token
├── sa-token-core // sa-token核心模块
├── sa-token-spring-boot-starter // sa-token整合springboot快速集成
├── 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示例
├── sa-token-demo-jwt // sa-token集成jwt示例
├── 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-servlet // sa-token 整合 Servlet容器实现类包
├── sa-token-spring-boot-starter // sa-token 整合 SpringBoot 快速集成
├── sa-token-webflux-spring-boot-starter // sa-token 整合 WebFlux 快速集成
├── 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开发文档
├──pom.xml
```

View File

@@ -6,20 +6,47 @@
---
## 具体API
#### StpUtil.logoutByLoginId(Object loginId)
让指定loginId的会话注销登录踢人下线例如
### 根据账号id踢人
让指定账号id的会话注销登录例如
``` java
// 使账号id为10001的会话注销登录待到10001再次访问系统时会抛出`NotLoginException`异常,场景值为-5
// 使账号id为10001的会话注销登录(踢人下线)待到10001再次访问系统时会抛出`NotLoginException`异常,场景值为-5
StpUtil.logoutByLoginId(10001);
```
#### StpUtil.logoutByTokenValue(String tokenValue);
你还可以让指定token的会话注销登录 (此方法直接删除了`token->uid`的映射关系,对方再次访问时提示:`token无效`,场景值为-2)
### 根据Token令牌踢人
你还可以让指定token的会话注销登录
``` java
// 使账号id为10001的会话注销登录
StpUtil.logoutByTokenValue("xxxx-xxxx-xxxx-xxxx-xxxx");
```
此方法直接删除了`token->uid`的映射关系,对方再次访问时提示:`token无效`,场景值为-2
### 账号封禁
对于违规账号,有时候我们仅仅将其踢下线还是远远不够的,我们还需要对其进行**账号封禁**防止其再次登录
``` java
// 封禁指定账号
// 参数一账号id
// 参数二:封禁时长,单位:秒 (86400秒=1天此值为-1时代表永久封禁)
StpUtil.disableLoginId(10001, 86400);
// 获取指定账号是否已被封禁 (true=已被封禁, false=未被封禁)
StpUtil.isDisable(10001);
// 获取指定账号剩余封禁时间,单位:秒
StpUtil.getDisableTime(10001);
```
#### 注意点
对于正在登录的账号,对其账号封禁时并不会使其立刻注销<br>
如果需要将其封禁后立即掉线,可采取先踢再封禁的策略,例如:
``` java
// 先踢下线
StpUtil.logoutByLoginId(10001);
// 再封禁账号
StpUtil.disableLoginId(10001, 86400);
```

View File

@@ -81,13 +81,17 @@
<p>拦截违规调用适配RBAC权限模型不同角色不同授权权限分配精细到按钮级</p>
</div>
<div class="feature">
<h2>Session会话</h2>
<h2>分布式Session会话</h2>
<p>专业的数据缓存中心内置三种会话模型User-Session、Token-Session、自定义Session</p>
</div>
<div class="feature">
<h2>踢人下线</h2>
<p>一行代码实现踢人下线功能,清退违规用户,对方再次访问系统提示“已被踢下线”</p>
</div>
<div class="feature">
<h2>账号封禁</h2>
<p>封禁指定账号,并设定解封时间,期间此账号无法登录系统</p>
</div>
<div class="feature">
<h2>Redis集成</h2>
<p>可扩展持久层集成Redis、Memcached等专业缓存中间件重启数据不丢失</p>
@@ -139,16 +143,16 @@
</div>
<div class="feature">
<h2>记住我模式</h2>
<p>一个参数即可轻松适配 [记住我] 模式,做到重启浏览器免验证</p>
<p>轻松适配 [记住我] 模式,重启浏览器免验证,还可指定免验证具体时长</p>
</div>
<div class="feature">
<h2>密码加密</h2>
<p>提供密码加密模块可快速MD5、SHA1、SHA256、AES、RSA加密</p>
</div>
<!-- <div class="feature">
<div class="feature">
<h2>组件自动注入</h2>
<p>零配置与Spring等框架集成</p>
</div> -->
</div>
</div>
<div class="re-text">有了sa-token你所有的权限认证问题都不再是问题</div>
</div>

12
sa-token-servlet/.gitignore vendored Normal file
View File

@@ -0,0 +1,12 @@
target/
node_modules/
bin/
.settings/
unpackage/
.classpath
.project
.factorypath
.idea/

35
sa-token-servlet/pom.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version='1.0' encoding='utf-8'?>
<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-parent</artifactId>
<version>1.15.2</version>
</parent>
<packaging>jar</packaging>
<name>sa-token-servlet</name>
<artifactId>sa-token-servlet</artifactId>
<description>sa-token authentication by Sservlet API</description>
<dependencies>
<!-- sa-token-spring-boot-starter -->
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<version>${sa-token-version}</version>
</dependency>
<!-- Servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,100 @@
package cn.dev33.satoken.context.model.servlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import cn.dev33.satoken.context.model.SaRequest;
/**
* Request for Servlet
* @author kong
*
*/
public class SaRequestForServlet implements SaRequest {
/**
* 底层Request对象
*/
HttpServletRequest request;
/**
* 实例化
* @param request request对象
*/
public SaRequestForServlet(HttpServletRequest request) {
this.request = request;
}
/**
* 获取底层源对象
*/
@Override
public Object getSource() {
return request;
}
/**
* 在 [Request作用域] 里写入一个值
*/
@Override
public void setAttribute(String name, Object value) {
request.setAttribute(name, value);
}
/**
* 在 [Request作用域] 里获取一个值
*/
@Override
public Object getAttribute(String name) {
return request.getAttribute(name);
}
/**
* 在 [Request作用域] 里删除一个值
*/
@Override
public void removeAttribute(String name) {
request.removeAttribute(name);
}
/**
* 在 [请求体] 里获取一个值
*/
@Override
public String getParameter(String name) {
return request.getParameter(name);
}
/**
* 在 [请求头] 里获取一个值
*/
@Override
public String getHeader(String name) {
return request.getHeader(name);
}
/**
* 在 [Cookie作用域] 里获取一个值
*/
@Override
public String getCookieValue(String name) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if (cookie != null && name.equals(cookie.getName())) {
return cookie.getValue();
}
}
}
return null;
}
/**
* 返回当前请求的URL
*/
@Override
public String getRequestURI() {
return request.getRequestURI();
}
}

View File

@@ -0,0 +1,62 @@
package cn.dev33.satoken.context.model.servlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.util.SaTokenInsideUtil;
/**
* Response for Servlet
* @author kong
*
*/
public class SaResponseForServlet implements SaResponse {
/**
* 底层Request对象
*/
HttpServletResponse response;
/**
* 实例化
* @param request request对象
*/
public SaResponseForServlet(HttpServletResponse response) {
this.response = response;
}
/**
* 获取底层源对象
*/
@Override
public Object getSource() {
return response;
}
/**
* 删除指定Cookie
*/
@Override
public void deleteCookie(String name) {
addCookie(name, null, null, null, 0);
}
/**
* 写入指定Cookie
*/
@Override
public void addCookie(String name, String value, String path, String domain, int timeout) {
Cookie cookie = new Cookie(name, value);
if(SaTokenInsideUtil.isEmpty(path) == true) {
path = "/";
}
if(SaTokenInsideUtil.isEmpty(domain) == false) {
cookie.setDomain(domain);
}
cookie.setPath(path);
cookie.setMaxAge(timeout);
response.addCookie(cookie);
}
}

View File

@@ -0,0 +1,4 @@
/**
* Sa-Token对接ServletAPI容器所需要的实现类接口包
*/
package cn.dev33.satoken.context.model.servlet;

View File

@@ -24,7 +24,7 @@ public class SaCheckAspect {
/**
* 切面执行顺序
*/
public static final int aspectOrder = -1;
public static final int aspectOrder = -100;
/**
* 构建

View File

@@ -18,7 +18,7 @@
<dependencies>
<dependency>
<groupId>cn.dev33</groupId>
<artifactId>sa-token-core</artifactId>
<artifactId>sa-token-servlet</artifactId>
<version>${sa-token-version}</version>
</dependency>
<dependency>

View File

@@ -11,6 +11,7 @@ import org.springframework.context.annotation.Import;
/**
* 将此注解加到springboot启动类上即可完成sa-token与springboot的集成
* <p>注: v1.7版本以上已不再需要此注解直接引入sa-token-spring-boot-starter依赖即可
* <p>请直接忽略此注解
* @author kong
*
*/

View File

@@ -9,10 +9,9 @@ import org.springframework.util.PathMatcher;
import cn.dev33.satoken.SaTokenManager;
import cn.dev33.satoken.action.SaTokenAction;
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.cookie.SaTokenCookie;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.dao.SaTokenDao;
import cn.dev33.satoken.servlet.SaTokenServlet;
import cn.dev33.satoken.spring.SaTokenServletSpringImpl;
import cn.dev33.satoken.spring.SaTokenContextForSpring;
import cn.dev33.satoken.stp.StpInterface;
/**
@@ -65,16 +64,6 @@ public class SaTokenSpringAutowired {
SaTokenManager.setStpInterface(stpInterface);
}
/**
* 注入Cookie操作Bean
*
* @param saTokenCookie SaTokenCookie对象
*/
@Autowired(required = false)
public void setSaTokenCookie(SaTokenCookie saTokenCookie) {
SaTokenManager.setSaTokenCookie(saTokenCookie);
}
/**
* 注入框架行为Bean
*
@@ -86,23 +75,23 @@ public class SaTokenSpringAutowired {
}
/**
* 获取Servlet操作Bean (Spring版)
* 获取容器交互Bean (Spring版)
*
* @return Servlet操作Bean (Spring版)
* @return 容器交互Bean (Spring版)
*/
@Bean
public SaTokenServlet getSaTokenServlet() {
return new SaTokenServletSpringImpl();
public SaTokenContext getSaTokenContext() {
return new SaTokenContextForSpring();
}
/**
* 注入Servlet操作Bean
* 注入容器交互Bean
*
* @param saTokenServlet SaTokenServlet对象
* @param saTokenContext SaTokenContext对象
*/
@Autowired
public void setSaTokenServlet(SaTokenServlet saTokenServlet) {
SaTokenManager.setSaTokenServlet(saTokenServlet);
public void setSaTokenContext(SaTokenContext saTokenContext) {
SaTokenManager.setSaTokenContext(saTokenContext);
}
/**
@@ -112,7 +101,7 @@ public class SaTokenSpringAutowired {
*/
@Autowired(required = false)
public void setPathMatcher(PathMatcher pathMatcher) {
SaTokenServletSpringImpl.setPathMatcher(pathMatcher);
SaTokenContextForSpring.setPathMatcher(pathMatcher);
}

View File

@@ -5,6 +5,8 @@ import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import cn.dev33.satoken.context.model.servlet.SaRequestForServlet;
import cn.dev33.satoken.context.model.servlet.SaResponseForServlet;
import cn.dev33.satoken.router.SaRouteFunction;
import cn.dev33.satoken.stp.StpUtil;
@@ -57,7 +59,7 @@ public class SaRouteInterceptor implements HandlerInterceptor {
StpUtil.checkLogin();
} else {
// 否则执行函数
function.run(request, response, handler);
function.run(new SaRequestForServlet(request), new SaResponseForServlet(response), handler);
}
// 通过验证

View File

@@ -1,12 +1,13 @@
package cn.dev33.satoken.spring;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import cn.dev33.satoken.servlet.SaTokenServlet;
import cn.dev33.satoken.context.SaTokenContext;
import cn.dev33.satoken.context.model.SaRequest;
import cn.dev33.satoken.context.model.SaResponse;
import cn.dev33.satoken.context.model.servlet.SaRequestForServlet;
import cn.dev33.satoken.context.model.servlet.SaResponseForServlet;
/**
* sa-token 对Cookie的相关操作 接口实现类
@@ -14,25 +15,24 @@ import cn.dev33.satoken.servlet.SaTokenServlet;
* @author kong
*
*/
public class SaTokenServletSpringImpl implements SaTokenServlet {
public class SaTokenContextForSpring implements SaTokenContext {
/**
* 获取当前请求的Request对象
*/
@Override
public HttpServletRequest getRequest() {
return SpringMVCUtil.getRequest();
public SaRequest getRequest() {
return new SaRequestForServlet(SpringMVCUtil.getRequest());
}
/**
* 获取当前请求的Response对象
*/
@Override
public HttpServletResponse getResponse() {
return SpringMVCUtil.getResponse();
public SaResponse getResponse() {
return new SaResponseForServlet(SpringMVCUtil.getResponse());
}
/**
* 路由匹配器
*/
@@ -54,7 +54,7 @@ public class SaTokenServletSpringImpl implements SaTokenServlet {
* @param pathMatcher 路由匹配器
*/
public static void setPathMatcher(PathMatcher pathMatcher) {
SaTokenServletSpringImpl.pathMatcher = pathMatcher;
SaTokenContextForSpring.pathMatcher = pathMatcher;
}
/**